How to use select2 multiselect with livewire - laravel

What I am trying to achieve is, there are two models A and B with a relationship of One to many, where A has many B. So if the records for A and B have already been created, A can be assigned to many B. So I started this current project with livewire, and now I am at a loss. Normal select with multiple works just fine and populates the array in the backend of livewire. But when I use select2 nothing is stored in the array, and when I dd it, it shows an empty array.
Even though livewire provides wonderful set of tools, I am starting to realize that there is a lot of gray areas where things are missing or lacks external support, like select2 here.
Here is what I have done so far:
<div>
<div class="tab-pane fade show active" id="card1" role="tabpanel" aria-labelledby="card1-tab">
<div class="pt-3"></div>
<div class="row" >
<div class="form-group col">
<label for="cards">Enter Cards</label>
<select class="form-control select2" id="cards" multiple="multiple" onchange="this.dispatchEvent(new InputEvent('input'))>
<option disabled="">Select Cards</option>
#foreach($cardsUnassigned as $card)
<option value="{{ $card->id }}">{{ $card->imei_number }}</option>
#endforeach
</select>
</div>
<div class="form-group col">
<label for="technicians" class="">Technicians</label>
<select class="form-control select2" id="technicians" wire:model='techies.'>
<option disabled="">Select Technicians</option>
#foreach($technicians as $tech)
<option value="{{ $tech->id }}">{{ $tech->first_name }}</option>
#endforeach
</select>
</div>
</div>
#foreach($cardSelect as $key => $value)
{{$value}}
#endforeach
<button wire:click="assignCardToTech()" class="btn btn-primary">Submit</button>
</div>
</div>
#push('scripts')
<script>
$('#cards').select2({
placeholder: 'Select Cards to assign'
});
//send data to livewire
$('#technicians').select2({
placeholder: 'Select Technicians'
});
</script>
#endpush
And the backend:
<?php
namespace App\Http\Livewire\Stock\Assigns;
use App\Models\Card;
use App\Models\Sim;
use App\Models\Technician;
use Livewire\Component;
use Livewire\WithPagination;
use Illuminate\Support\Facades\Auth;
class Assigns extends Component
{
public $sortBy_card = 'imei_number';
public $sortBy_sim = 'ip';
public $sortDirection = 'asc';
public $search = '';
public $perPage = 10;
public $cardSelect = [];
public $techies;
public function render()
{
$simsUnassigned = Sim::query()
->whereNull('technician_id')
->searchUnassigned($this->search)
->get();
$cardsUnassigned = Card::query()
->whereNull('technician_id')
->searchUnassignedCard($this->search)
->get();
// dd($cardsUnassigned);
$simsAssigned = Sim::query()
->searchAssigned($this->search)
->orderBy($this->sortBy_sim, $this->sortDirection)
->paginate($this->perPage);
$cardsAssigned = Card::query()
->searchAssignedCard($this->search)
->orderBy($this->sortBy_card, $this->sortDirection)
->paginate($this->perPage);
$technicians = Technician::query()->get();
return view('livewire.stock.assigns.assigns',compact('simsUnassigned','cardsUnassigned','simsAssigned','cardsAssigned','technicians'))
->extends('layouts.base')
->section('content');
}
public function assignCardToTech(){
dd($this->cardSelect);
if($this->cards){
foreach($this->cards as $card){
}
}
}
}
Hopefully this helps.

######## INSIDE LIVEWIRE COMPONENT
public array $locationUsers = [];
protected $listeners = ['locationUsersSelected'];
public function locationUsersSelected($locationUsersValues)
{
$this->locationUsers = $locationUsersValues;
}
######## INSIDE LIVEWIRE BLADE
<div class="col-md-12 mb-3" wire:ignore>
<label for="locationUsers">Select Users</label>
<select id="locationUsers" class="form-control select2" multiple="multiple">
<option value="">--select--</option>
#foreach($this->users as $id => $name)
<option value="{{ $id }}">{{ $name }}</option>
#endforeach
</select>
</div>
######## INSIDE LIVEWIRE SCRIPTS
document.addEventListener('livewire:load', function () {
$('#locationUsers').on('select2:close', (e) => {
#this.emit('locationUsersSelected', $('#locationUsers').select2('val'));
});
$('#locationUsers').val(#this.get('locationUsers')).trigger('change');
});

Your could try adding this to your html
<div class="form-group col-md-6" wire:ignore>
<label for="manager" class="mb-0 h5">Assign Managers:</label>
<select wire:model="reporting_managers" id="manager" class="select-2 multiple='multiple' data-placeholder="Assign Managers">
#foreach ($managers as $manager)
<option value="{{ $manager->id }}" data-name="{{ $manager->name }}">{{ $manager->name }}</option>
#endforeach
</select>
</div>
and then in your javaScript section
$('#manager').on('select2:select', function (e) {
#this.set('reporting_managers', $('#manager').select2('val'));
});
$('#manager').on('select2:unselect', function (e) {
#this.set('reporting_managers', $('#manager').select2('val'));
});
This will directly store your selection in variable in livewire and won't get deselected on render.

Related

select2 not showing options within livewire component

I am working with laravel livewire.There is a component to update brands and categories of a product. category and brand select option is a select2 option. dropdown showing as a select2, but does not show the options.
This is my component
<?php
namespace App\Http\Livewire\Components\MemberArea\Product;
use App\Models\ProductBrand;
use App\Models\ProductCategory;
use App\Models\Product;
use Illuminate\Support\Facades\Session;
use Livewire\Component;
class UpdateProductBrand extends Component
{
public $product_id;
public $product_category_id;
public $product_brand_id, $categories, $brands, $product;
public function render()
{
return view('pages.products.components.update-product-brand');
}
public function mount()
{
$this->product = Product::get($this->product_id);
$this->categories = ProductCategory::all();
$this->brands = ProductBrand::all();
$this->product_category_id = $this->product->product_category_id;
}
public function submit()
{
$data = $this->validate();
$product = Product::get($this->product_id);
Product::update($product, $data);
session()->flash('message', 'Brand Details Updated Successfully.');
}
}
This is My Blade
<div class="card-body">
<form wire:submit.prevent="submit">
<div class="row">
<div class="form-group col-lg-6">
<label class="h5">Product Category <sup class="text-danger">*</sup>|<button type="button"
id="new-category" class="btn btn-light ">+</button></label>
<select required class="form-control" wire:model="product_category_id" id="categories_edit">
<option value=""></option>
#foreach ($categories as $category)
<option {{ $product->product_category_id === $category->id ? 'selected' :'' }}
value="{{ $category->id }}">{{
$category->title }}</option>
#endforeach
</select>
</div>
#error('product_brand_id')
<span class="text-danger error">{{ $message }}</span>
#enderror
<div class="form-group col-lg-6">
<label class="h5">Product Brand <sup class="text-danger">*</sup>| <button type="button" id="new-brand"
class="btn btn-light">+</button></label>
<select class="form-control" wire:model="product_brand_id" id="brands_edit">
#foreach ($brands as $brand)
<option {{ $product->product_brand_id === $brand->id ? 'selected' :'' }} value="{{ $brand->id }}">
{{ $brand->title }}
</option>
#endforeach
</select>
</div>
#error('product_category_id')
<span class="text-danger error">{{ $message }}</span>
#enderror
<div class="form-group col-lg-12 text-center">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</div>
</form>
</div>
#push('js')
<script>
document.addEventListener("livewire:load", function (event) {
window.livewire.hook('afterDomUpdate', () => {
$('#categories_edit, #brands_edit').select2({
placeholder: 'Select an option',
});
});
});
$(document).ready(function () {
$('#categories_edit').select2();
$('#brands_edit').select2();
});
//set category on select
$('#categories_edit').on('change', function (e) {
var category_select = $('#categories_edit').select2("val");
console.log("category when select= " + category_select);
#this.product_category_id = category_select;
});
//set brand on select
$('#brands_edit').on('change', function (e) {
var brand_select = $('#brands_edit').select2("val");
console.log("brand when select= " + brand_select);
#this.product_brand_id = brand_select;
});
</script>
#endpush
this is how show it
when use wire:ignore it also not working. show only dropdown as select2 , but it does not show the options

How to Display a selected grade with its subject?

I want to when a user select a dropdown from the list, a group of subjects available for that grade must be displayed with checkboxes next to them
My controller
public function create()
{
$grades = Grade::with('subjects')->orderBy('slug', 'asc')->get();
return view('admin.users.create', compact( 'grades'));
}
Blade file
<div class="form-group">
<select id="grade" name="grade" class="form-control #error('grade') is-invalid #enderror" v-model="selectedSubjects">
<option value="">Choose a Grade...</option>
#foreach($grades as $grade)
<option value="{{ $grade->id }}" {{ old('grade', $grade) == $grade->name ? 'selected' : "" }}>{{ $grade->name }}</option>
#endforeach
</select>
</div>
<div class="custom-control custom-checkbox mt-2">
#foreach($grade->subjects as $subject)
<input type="checkbox" class="custom-control-input" id="{{$subject->slug}}" name="subjects[]" :value="selectedSubjects" />
<label class="custom-control-label" for="{{$subject->slug}}">{{$subject->name}}</label>
#endforeach
</div>
vue
<script>
window.addEventListener('load',function(){
var app = new Vue({
el: '#app',
data:{
selectedSubjects: {!! $grade->subjects->pluck('name') !!},
}
});
});
</script>
THIS IS IMPOSSIBLE... I GIVE UP
As per I have understood, you want to select grades from dropdown & show its corresponding checkbox as per subjects for the grades.
I would suggest to create a vue component for that lets say grades-component,
in your blade you can add,
<form action="" class="form-control">
#csrf
<grade-component :grades='#json($grades)'></grade-component>
</form>
here in blade, $grades is the object(or array) you are passing via compact. Basically it is to pass your data to the component, we will use that with help of props.
Now you can add your GradeComponent.vue in resources->js->components->GradeComponent.vue
GradeComponent.vue
<template>
<div class="container">
<select v-model="selected_grade" #change="onChange($event)">
<option v-for="grade in grading" :value="grade.slug">{{grade.name}}</option>
</select>
<div class="custom-control custom-checkbox mt-2" v-if="subjects !== null" v-for="subject in subjects">
<input type="checkbox" :id="subject.slug" :value="subject.slug"/>
<label :for="subject.slug">{{subject.name}}</label>
</div>
</div>
</template>
<script>
export default{
props: ['grades'],
data: function() {
return {
grading: this.grades,
selected_grade: null,
subjects : null
}
},
methods: {
onChange(event) {
this.grading.forEach((obj, index) => {
if (obj.slug === event.target.value){
this.subjects = obj.subjects;
}
})
}
}
}
</script>
Now finally you can add it in app.js
Vue.component('grade-component', require('./components/GradeComponent.vue').default);
Then compile your vuejs code, I would use npm run watch
A similar one but with fake data, you can see https://jsfiddle.net/bhucho/2yu4nmws/3/,

select2 on Laravel Livewire does not work

I implemente select2 in a select as the official documentation indicates and I can't get it to work in full.
<div>
<div wire:ignore>
<select class="js-example-basic-single" name="state">
<option value="AL">Alabama</option>
<option value="WY">Wyoming</option>
</select>
<!-- Select2 will insert it's DOM here. -->
</div>
#push('scripts')
<script>
$(document).ready(function() {
$('.js-example-basic-single').select2();
$('.js-example-basic-single').on('change', function (e) {
#this.set('foo', e.target.value);
});
});
</script>
#endpush
if I remove the following script in the view the select2 component renders fine
$('.js-example-basic-single').on('change', function (e) {
#this.set('foo', e.target.value);
});
but of course I lose the desired functionality.
The selct2 add links I use are as follows
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="{{asset('SitioWeb/assets/select2/js/select2.min.js')}}"></script>
what am i missing?
Due to the way select2 works, livewire's wire:model and wire:change may not work with select2. Livewire's wire:model and wire:change work perfectly with the traditional HTML select control. To use select to with livewire's wire:model and wire:change, write a js code to get the selected value from select2, then use Livewire.emit() to send the selected value to your component and handle it from there. Example js code is as follows:
$(document).ready(function() {
$('#id').select2();
$('#id').on('change', function(e) {
Livewire.emit('listenerReferenceHere',
$('#id').select2("val"));
});
});
Your Livewire component :
...
protected $listeners = ['listenerReferenceHere'];
public function listenerReferenceHere($selectedValue)
{
//Do something with the selected2's selected value here
}
I hope this helps... 😊
you can use Bootstrap-select
npm install bootstrap-select
It worked well for me. this my code.
<div class="form-group">
<label for="permissions">{{ __('role.permissions') }}</label>
<div class="col-sm-10">
<div wire:key="UNIQUE_KEY">
<div wire:ignore>
<select id="permissions" wire:model="permissions"
data-live-search="true"
data-actions-box="true"
title="{{__('generic.select')}} {{ __('role.permissions') }}"
name="permissions[]" data-width="100%"
class="selectpicker permissions" multiple>
#foreach($list_permission as $permission)
<option value="{{ $permission->id }}"
data-subtext="{{ $permission->key }} {{ ' -'. $permission->table_name }}">
{{ __('permission.'.$permission->key) }}
</option>
#endforeach
</select>
</div>
</div>
#error('permissions') <span class="text-danger">{{ $message }}</span> #enderror
</div>
</div>
in script :
....
#push('scripts')
<script>
Livewire.restart();
$(function () {
$('.permissions').selectpicker();
});
</script>
#endpush
</div>
in Component
public $permissions = [];
public $old_permissions = [];
public function updatedPermissions()
{
$filter_arrays = array_filter($this->permissions);
$unique = array_unique($filter_arrays);
$this->permissions = $unique;
}
in update :
if (! empty($this->old_permissions)){
$updateRole = $this->role->find($this->modelId)->permissions()->detach();
$updateRole = $this->role->find($this->modelId)->permissions()->sync($validatedData['permissions']);
}elseif ($this->old_permissions != $this->permissions ){
$updateRole = $this->role->find($this->modelId)->permissions()->attach($validatedData['permissions']);
}
I tried hard to combine livewire with select2 and finally found the solution that way.
UsersComponent.php
class Users extends Component
{
public $users = [];
public function mount()
{
$this->users= User::all();
}
public function render()
{
return view('livewire.users');
}
}
then
users.blade.php
<div class="col-sm-12 col-xl-3 m-b-30" wire:ignore >
<div >
<h4 class="sub-title" >USERS</h4>
<select class="js-example-basic-single form-control-warning" name="states" >
#foreach ($users as $user)
<option value="{{ $user->id }}">{{ $user->name}}</option>
#endforeach
</select>
</div>
</div>
index.blade.php
<p>
#livewire(livewire.users)
</p>

Dropdown filter doesn't work in Laravel 5.8

I tried to do the input dropdown filter using this code:
<div class="col-md-2">
<div class="text-justify" >
<select class="itemName form-control form-filter" style="width:90px;" name="itemName" id="itemName">
#foreach($data as $category){
<option value="{{$category->Umur}}">{{$category->Umur}}</option>
#endforeach
</select>
</div>
</div>
However, my code does not run as I expected (in picture below) - the code only call the first row in database. What should I edit with the code?
<div class="col-md-2">
<div class="text-justify" >
<select class="itemName form-control form-filter" style="width:90px;" name="itemName" id="itemName">
#foreach($data as $category){
<option value="{{$category->Umur}}">{{$category->Umur}}</option>
#endforeach
</select>
</div>
</div>
remove the { after #foreach & change the value like
<div class="col-md-2">
<div class="text-justify" >
<select class="itemName form-control form-filter" style="width:90px;" name="itemName" id="itemName">
#foreach($data as $category)
<option value="{{$category->id}}">{{$category->Umur}}</option>
#endforeach
</select>
</div>
</div>
I too had this issue myself, this is what i used:
<div class="form-group">
<div class="btn-group">
<input list="brow" class="form-control"name="instagram_account_id" id="instagram_account_id" placeholder="Search..">
<datalist id="brow">
#if($users->count() > 0)
#foreach($users as $user)
<option value="{{$user->id}}">{{ $user->username }}</option>
#endforeach
#else
No User(s) Found
#endif
</datalist>
</div>
</div>
As for my controller:
public function index()
{
$comments = Comment::paginate(10);
$users = InstagramAccount::all();
return view('instagramComments', [
'comments' => $comments,
'users' => $users,
]);
}
And (if you're going to use it an a form) my insert in my controller:
public function insert(Request $req)
{
$instagram_comment = $req->input('instagram_comment');
$instagram_account_id = $req->input('instagram_account_id');
$data = array('comment'=>$instagram_comment, 'account_id'=>$instagram_account_id);
DB::table('comments')->insert($data);
return redirect('/comments');
}
(if using the insert above, use this in your web route):
Route::post('/locationsInsert', 'InstagramLocationsController#insert')->middleware('auth');
Hope any of this helps!

Laravel 5.2 How to populate edit form with multiple select?

I want to create a zone which contain few cities. So I decided to use jQuery Select2
Here is my create form multiple selection
<div class="form-group {{ $errors->has('cities') ? 'has-error' : '' }}">
<label>Tentukan Kota</label>
<select name="cities[]" class="city form-control" data-placeholder="Pilih Kota" style="width: 100%;" multiple="multiple">
#foreach($cities as $city)
<option value="{{ $city->id }}">{{ $city->name }}</option>
#endforeach
</select>
</div>
I can multiple select just like in documentation.
Here is my controller which handle display create form
public function zone_create()
{
$cities = City::where('zone_id', null)->get();
return view('backend.admin.pricings.zone_create', compact('cities'));
}
The relationship is One Zone Has Many City.
class Zone extends Model
{
protected $fillable = [
'name',
];
public function cities(){
return $this->hasMany(City::class);
}
}
The city belongs to zone
class City extends Model
{
protected $fillable = [
'zone_id',
'name',
];
public function zone(){
return $this->belongsTo(Zone::class);
}
}
Here is my edit method
public function edit($id)
{
$zone = Zone::find($id);
$cities = City::all();
return view('backend.admin.pricings.zone_edit', compact('zone', 'cities'));
}
Here is my edit form so far
<div class="form-group {{ $errors->has('cities') ? 'has-error' : '' }}">
<label>Tentukan Kota</label>
<select name="cities[]" class="city form-control" data-placeholder="Pilih Kota" style="width: 100%;" multiple="multiple">
//load option from cities table
//set selected the city belongs to zone
//the other city which don't belong to zone still here for option
</select>
</div>
But how I can populate my edit form (multiple selection) with City belongs to zone?
Just like this in my view
<select name="cities[]" class="city form-control" data-placeholder="Pilih Kota" style="width: 100%;" multiple="multiple">
#foreach($cities as $city)
#if(in_array($city->id, $zoneCityIds))
<option value="{{ $city->id }}" selected="true">{{ $city->name }}</option>
#else
<option value="{{ $city->id }}">{{ $city->name }}</option>
#endif
#endforeach
</select>
and like this in my controller
public function zone_edit($id)
{
$zoneCityIds = [];
$zone = Zone::find($id);
$cities = City::all();
foreach($zone->cities as $zoneCity)
{
$zoneCityIds[] = $zoneCity->id;
}
return view('backend.admin.pricings.zone_edit', compact('zone', 'cities', 'zoneCityIds'));
}
actually it's jus about option tag selected="true"
for multiple values simply use
<div class="form-group">
{!! Form::label('Categories') !!}<br />
{!! Form::select('categories[]', $cost_centers,
$post->categories->pluck('id')->toArray(),
['class' => 'form-control',
'multiple' => 'multiple']) !!}
</div>
In your edit function you can get all the cities of that particular zone
$zone_cities = implode(',',$zone->cities->lists('name')->toArray());
and pass $zone_cities in your view.
return view('backend.admin.pricings.zone_edit', compact('zone', 'cities','zone_cities'));
You will have to use Form Model binding in your view
Read about laravel collective form model binding [here].1
You will open your form like this
Your Edit form will be like this
{!! Form::label('cities','Cities: ') !!}
{!! Form::text('cities',$zone_cities,['class'=>'input','id'=>'cities','aria-required'=>'true','data-seperator'=>',']) !!}

Resources