I'm new to Vuejs. I have written a vuejs component for delete confirmation modal. I call this inside a list of records, here is my code :
<template id="bs-modal">
<div class="modal fade" id="confirmDeleteModal" tabindex="-1"
role="dialog" aria-labelledby="confirmDeleteModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close"
data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title"
id="confirmDeleteModalLabel">
Delete {{ item | capitalize }}
</h4>
</div>
<div class="modal-body">
Are you sure about deleting the {{ name }} {{ item }} ?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default"
data-dismiss="modal">No</button>
<button type="button" class="btn btn-primary"
v-on:click="deleteItem(id)">Yes</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
}
},
props: ['item', 'name', 'id'],
methods: {
deleteItem : function(id) {
var url = window.location.href;
var baseUrl = url.substring(0,
url.indexOf('/', url.indexOf('://') + 3) + 1);
var adminPosition = url.indexOf('admin/') + 6;
var entity = url.substring(adminPosition,
url.indexOf('/', adminPosition));
this.$http.delete(baseUrl + "admin/" + entity + "/" + id).then((response) => {
if (response.body.status_code == '200') {
// Calling just modal('hide') does not hide the backdrop
// There should be a better solution for this
$("#confirmDeleteModal").modal("hide");
$("#confirmDeleteModal").hide();
$('.modal-backdrop').hide();
$("body").removeClass("modal-open");
$("tr[data-id=" + id + "]").remove();
// Display success message
}
});
}
},
filters: {
capitalize: function (value) {
if (!value) {
return '';
}
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
}
</script>
And here is my blade template where I call this component (I'm using laravel 5.3) :
#foreach ($categories as $category)
<tr data-id="{{ $category->id }}">
<td>{{ $category->id }}</td>
<td>{{ $category->name }}</td>
<td id="actions">
Show
Edit
Delete
<confirm-delete-modal item="category" id="{{ $category->id }}" name="{{ $category->name }}"></confirm-delete-modal>
</td>
</tr>
#endforeach
The parameters I pass to the component are variable and according to Vue devtools, the component gets the correct value for each record but when I run the code, it always gets the parameters of first record in list.
Am I missing something ?
I think the main issue came from same Id for all components and when you click on a link first element with ID (confirmDeleteModal) will be opened.
You can set an unique id for each components like this:
<div class="modal fade" :id="'confirmDeleteModal_'+id" tabindex="-1"
role="dialog" aria-labelledby="confirmDeleteModalLabel">
I think calling the confirm-delete-modal for each record is a wrong method. I moved the modal outside the loop and made some changes to the code to solve the problem :
Here is the code of confirmDelete.vue :
<template id="modal-template">
<transition name="confirm-delete-modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
Are you sure about deleting the {{ this.$parent.item_name }} {{ item }} ?
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
<button class="modal-default-button" #click="deleteItem();">
Yes
</button>
<button class="modal-default-button" #click="$emit('close')">
No
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
data () {
return {
}
},
props: ['item'],
methods: {
deleteItem : function() {
var url = window.location.href;
var baseUrl = url.substring(0, url.indexOf('/', url.indexOf('://') + 3) + 1);
var adminPosition = url.indexOf('admin/') + 6;
var entity = url.substring(adminPosition, url.indexOf('/', adminPosition));
this.$http.delete(baseUrl + "admin/" + entity + "/" + this.$parent.item_id).then((response) => {
if (response.body.status_code == '200') {
$("tr[data-id=" + this.$parent.item_id + "]").remove();
this.$emit('close');
// Display success message
}
});
}
},
filters: {
capitalize: function (value) {
if (!value) {
return '';
}
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
}
</script>
And here is the blade template :
#foreach ($categories as $category)
<tr data-id="{{ $category->id }}">
<td>{{ $category->id }}</td>
<td>{{ $category->name }}</td>
<td id="actions">
Show
Edit
Delete
</td>
</tr>
#endforeach
<confirm-delete-modal item="category"
v-if="showDeleteModal"
#close="closeDeleteModal">
<h3 slot="header">Delete Category</h3>
</confirm-delete-modal>
And finally here is the code of parent vue instance :
new Vue({
el: '#crud',
data: {
showDeleteModal: false,
item_id: '',
item_name: ''
},
methods: {
setDeleteModal: function(e) {
this.showDeleteModal = true;
params = e.target.id.split("_");
this.item_id = params[1];
this.item_name = params[0];
},
closeDeleteModal: function() {
this.showDeleteModal = false;
}
}
});
I hope this helps someone else.
I'll be glad to know the idea of experts in vuejs.
You need to use v-bind when passing variables as props, like following"
<confirm-delete-modal item="category" v-bind:id="{{ $category->id }}" v-bind:name="{{ $category->name }}"></confirm-delete-modal>
or in short you can replace v-bind with : as:
<confirm-delete-modal item="category" :id="{{ $category->id }}" :name="{{ $category->name }}"></confirm-delete-modal>
Related
in my laravel project in livewire component i need to hide/set display none or something a checked checkbox and later i need to show again if its needed . Any solutions? I could simply delete it but i wanna store it in DB
I tried do this:
https://larainfo.com/blogs/laravel-livewire-show-and-hide-div-example
but its hidding my all input checkboxes
here is my Livewire component code:
<?php
namespace App\Http\Livewire\Tasks\Types;
use App\Http\Livewire\Forms\BaseForm;
use App\Models\Task\Task;
use App\Models\Task\TaskStatus;
use App\Models\Task\TaskType;
use App\Models\Task\TaskTypeStatus;
use Livewire\Component;
use App\Traits\HasPosition;
use Mpdf\Tag\Input;
class TaskTypeStatusModal extends BaseForm
{
public $task_type_id = 0;
public $availableStatuses = [];
public $selectedStatuses = [];
public $selectedStatusesList = [];
public function mount($params = [])
{
$this->task_type_id = $params['task_type_id'];
$this->title = 'Edytuj statusy';
$this->availableStatuses = TaskStatus::orderBy('position')->get();
$this->selectedStatuses = TaskTypeStatus::where('task_type_id', $this->task_type_id)->pluck('task_status_id');
$this->selectedStatusesList = TaskTypeStatus::where('task_type_id', $this->task_type_id)->orderBy('position')->get();
}
public function submit()
{
foreach ($this->selectedStatuses as $status) {
TaskTypeStatus::create([
'task_type_id' => $this->task_type_id,
'task_status_id' => $status,
]);
}
$this->closeFromModal();
$this->emit( 'Zapisano');
$this->emit('list:refresh');
}
public function render()
{
return view('livewire.tasks.types.task-type-status-modal',[
$this->selectedStatusesList = TaskTypeStatus::where('task_type_id', $this->task_type_id)->orderBy('position')->get()
]);
}
public function reorder($list)
{
foreach ($list as $item) {
TaskTypeStatus::find($item['value'])->update(['position' => $item['order']]);
}
}
public function deleteStatus($id)
{
TaskTypeStatus::find($id)->delete();
}
and here is my blade code:
<div>
<form wire:submit.prevent="submit">
<div class="modal-header">
<h5 class="modal-title">{{ $title }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" wire:click.prevent="closeFromModal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h6>Wybierz statusy</h6>
#forelse($availableStatuses as $availableStatus)
<div class="form-check checkbox">
<input class="form-check-input" name="status-{{ $availableStatus->id }}" id="status-{{ $availableStatus->id }}" wire:key="status-{{ $availableStatus->id }}"
wire:model.defer="selectedStatuses" type="checkbox" value="{{ $availableStatus->id }}"
wire:click="$toggle">
<label class="form-check-label" for="status-{{ $availableStatus->id }}">{{ $availableStatus->name }}</label>
</div>
#empty
<tr>
<td colspan="3">{{ __('Brak dostępnych statusów') }}</td>
</tr>
#endforelse
<hr>
<h6>Dodane statusy</h6>
<tr><span style="color:#3c4b64;font-size: 9pt"><b>{{ __('Przeciągnij za nazwę, aby zmienić kolejność.') }}</b></span></tr>
<ul class="list-group" wire:sortable="reorder">
#forelse ($selectedStatusesList as $selectedStatus)
<li class="list-group-item" value="{{ $selectedStatus->id }}" wire:sortable.item="{{ $selectedStatus->id }}" wire:key="selectedStatus-{{ $selectedStatus->id }}">
<td wire:sortable.handle>{{ __($selectedStatus->taskStatus->name) }}
<div class="float-right">
<button wire:click.prevent="deleteStatus({{ $selectedStatus->id }})" class="btn btn-sm btn-danger">{{ __('Usuń') }}</button>
</div>
</td>
</li>
#empty
<tr>
<td colspan="3">{{ __('Brak dodanych statusów') }}</td>
</tr>
#endforelse
</ul>
</div>
<div class="modal-footer">
<button wire:click.prevent="closeFromModal" class="btn btn-secondary" data-dismiss="modal">Anuluj</button>
<button type="submit" class="btn btn-primary">Zapisz</button>
</div>
</form>
</div>
i am trying to pass the ajax response to my view and use it as a variable to foreach,I need it to update the quantity of bikes available on the dates selected by the user
the procedure I use is:
I take the selected data in the calendar, I pass them via ajax to my controller
from the controller I execute the queries on the database and return to ajax a json with the data.
the ajax data must be cycled to assign the corresponding quantities to the categories but I don't know how to pass this data to the view
my view
#foreach ($category as $cat)
<div class="col pb-5 m-1">
<?php
$categoryId=DB::table('categories')->select('id')->orderBy('id', 'asc')->get();
foreach ($categoryId as $key) {
$quantity[$key->id]=DB::table('bikes')->where('category_id','=',$key->id)->count('*');
}
?>
<div class="card cat m-auto position-relative " id="cat{{$cat->id}}" >
#foreach ($qty as $item=>$val)
#if ($item==$cat->id)
<p class="m-3" id="numberqty" style="font-weight: bold;color:#ce2e30;text-shadow: 2px 5px 3px rgba(150, 150, 150, 0.92);">{{-- x{{$val}} --}}</p>
#endif
#endforeach
<p class="check position-absolute" style="display: none"><i class="fa fa-check" aria-hidden="true"></i></p>
<input class="cat-id" type="number" value="{{$cat->id}}" hidden>
<input class="id-cat" type="checkbox" name="category[]" id="category" value="{{$cat->id}}" hidden>
<img class="card-img-top p-3" src="{{asset('storage/'.$cat->cover_image)}}" alt="">
<div class="card-body my-n3">
<h3 class="card-title text-center" style="text-shadow: 2px 5px 3px rgba(150, 150, 150, 0.92);">{{$cat->tipo}}</h3>
{{-- <h3 class="card-title">Disponibilità: {{$val}}</h3> --}}
<button class="btn btn-primary pl-5 pr-5 ml-5 drop" type="button">{{__('payment.page.price')}}</button>
<button class="btn btn-primary pl-5 pr-5" type="button">Dettagli</button>
<div class="show-drop" style="display: none">
<h3 class="text-center my-1">{{__('payment.page.price')}}</h3>
<p class="text-center"> {{__('payment.page.1day')}} {{$cat->base}} </p> <hr>
<p class="text-center"> {{__('payment.page.2day')}} {{$cat->twoDay}}</p> <hr>
<p class="text-center"> {{__('payment.page.3day')}} {{$cat->threeDay}}</p> <hr>
<p class="text-center"> {{__('payment.page.4day')}} {{$cat->fourDay}}</p> <hr>
<p class="text-center"> {{__('payment.page.5day')}} {{$cat->fiveDay}}</p> <hr>
<p class="text-center"> {{__('payment.page.6day')}} {{$cat->sixDay}}</p> <hr>
<p class="text-center"> {{__('payment.page.7day')}} {{$cat->sevenDay}}</p>
<p class="text-center"> {{$cat->overprice}} {{__('payment.page.overprice')}}</p>
{{-- <p>{{$cat->overprice}}</p> --}}
</div>
</div>
</div>
<div class="number-drop" style="display: none">
<label for="quantity{{$cat->id}}">Nome</label>
<input name="{{$cat->id}}" type="number" id="quantity{{$cat->id}}" class="form-control" value="0" >
</div>
</div>
#endforeach
my ajax
$('#range_date').on('change', function(){
var data = $(this).val();
var split = data.split(' - ');
var startDate = split[0];
var dayStart = startDate.substr(0,2);
var monthStart = startDate.substr(3,2);
var yearStart = startDate.substr(6,4);
var startCorrect = monthStart+"/"+dayStart+"/"+yearStart;
console.log(startCorrect);
var endDate = split[1];
var dayEnd = endDate.substr(0,2);
var monthEnd = endDate.substr(3,2);
var yearEnd = endDate.substr(6,4);
var endCorrect = monthEnd+"/"+dayEnd+"/"+yearEnd;
console.log(endCorrect);
var date1 = new Date(startCorrect);
var date2 = new Date(endCorrect);
var diffTime = Math.abs(date2 - date1);
var diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
$.ajax({
"url": "bookingCheck",
"data": {
"start": startCorrect,
"end":endCorrect
},
"method": "GET",
success: function (response) {
let res = response;
let qty = res['qty'];
console.log(qty);
document.getElementById('numberqty').innerHTML=qty;
$('#numberqty').html(qty.html);
}
});
});
my controller
public function checkBike(Request $request){
$date1=Carbon::parse($request->start)->format('Y-m-d');
$date2=Carbon::parse($request->end)->format('Y-m-d');
$contract=DB::table('contracts')->get();
$contractdate=DB::table('contracts')->whereRaw('? between data_inizio and data_fine', [$date1,$date2])->get();
if (count($contractdate) > 0) {
foreach ($contractdate as $key) {
$id=$key->id;
}
$bikeContract=DB::table('bike_contract')->where('contract_id','=',$id)->get();
foreach ($bikeContract as $key) {
$bikeselect[$key->id]=DB::table('bikes')->where('id','=',$key->bike_id)->get();
}
foreach ($bikeselect[$key->id] as $key) {
$idcat=$key->category_id;
$quantity=DB::table('bikes')->select('category_id')->whereNotIn('category_id',[$idcat])->get();
}
foreach ($quantity as $key) {
$qty[$key->category_id]=DB::table('bikes')->where('category_id','=',$key->category_id)->count('*');
}
return response()->json(["qty"=>$qty]);
} else {
$categoryId=DB::table('categories')->select('id')->orderBy('id', 'asc')->get();
foreach ($categoryId as $key) {
$quantity[$key->id]=DB::table('bikes')->where('category_id','=',$key->id)->count('*');
}
return response()->json(["qty"=>$quantity]);
}
}
}
Try this:
success: function (response) {
response = JSON.parse(response);
let qty = response.qty;
}
I have a Bootstrap accordion with the expand collapse panels,which works fine.
But when expanded it should display minus icon which is not working well for me.
When I click to expand all the panel's icons are changed to minus instead of just changing the one which was expanded.
I have my code in the Vue JS template as below
Am calling the toggle function onclick to toggle the icons, but its doing it for all the other panels too.
How can I fix this? Thanks in advance.
Vue.component('accordion', {
data: function () {
return {
alerts: [],
sound: '',
collapsed:true
}
},
template: `
<div>
<div v-for="(alert, index ) in alerts" class="panel panel-default">
<div class="panel-heading" v-bind:style="'background-color:'+alert.color" role="tab" v-bind:id="'heading'+index" >
<a role="button" data-toggle="collapse" data-parent="#accordion"
v-bind:href="'#collapse'+index" aria-expanded="true" v-on:click="toggle">
<i id="collapseExpand" v-show="collapsed" class="more-less fa fa-plus"></i>
<i id="collapseExpand" v-show="!collapsed" class="more-less fa fa-minus"></i>
<h4 class="panel-title">#{{ alert.description }}</h4></a>
</div>
<div v-bind:id="'collapse'+index" class="panel-collapse collapse" role="tabpanel">
<div class="panel-body">
<div>#{{ alert.comment }}</div>
<div class="row">
<form v-bind:id="'form_'+index" v-bind:name="'form_'+index" v-bind:action="route" method="POST" style="display: inline;">
<input type="hidden" name="_token" :value="csrf">
<input type ="hidden" v-bind:id="'trigger_id_'+alert.triggerid" name = "trigger_id" v-bind:value="alert.triggerid">
<div class="col-lg-12">
<div class="input-group">
<input type="text" v-bind:id="'ack_msg_'+alert.triggerid" name="ack_msg" class="form-control"
placeholder="Acknowledge Message...">
<span class="input-group-btn">
<button class="btn btn-primary" type="submit">Save</button>
</span>
</div>
</div>
</form>
</div>
</div>
<div class="panel-footer">#{{ alert.timestamp }}</div>
</div>
</div>
<input type="hidden" id="audioFile" name="audioFile" v-bind:value="sound">
</div>`,
mounted: function () {
this.loadData();
setInterval(function () {
this.loadData();
}.bind(this), 1000);
},
methods: {
loadData: function () {
$.get('{{ route('getAlertsPersistent') }}', function (response) {
this.alerts = response;
this.sound = this.alerts[0].sound
}.bind(this));
},
toggle(){
this.collapsed = !this.collapsed ;
}
},
});
new Vue({el: '#accordion'});
You want to separate your accordion item that you want to loop. In that way you can have isolated states in each component.
<div>
<accordion-item
v-for="(alert, index) in alerts"
:alert="alert"
:key="index">
</accordion-item>
</div>
inside your <accordion-item/> you should have collapsed inside your data
The other way around is storing the toggled items in array.
export default {
data: () => ({
toggled: []
}),
methods: {
isActive (item) {
return this.toggled.indexOf(item) >= 0
},
toggleItem (item) {
const index = this.toggled.indexOf(item)
if (index >= 0) {
this.toggled.splice(index, 1)
return
}
this.toggled.push(item)
}
}
}
So you can use it now as follows
<a
role="button"
data-toggle="collapse"
data-parent="#accordion"
v-bind:href="'#collapse'+index"
aria-expanded="true"
v-on:click="toggleItem(index)">
<i
:class="[isActive(index) ? 'fa-minus' : 'fa-plus']"
class="more-less fa"></i>
<h4 class="panel-title">#{{ alert.description }}</h4>
</a>
btw you're looping an id=collapseExpand which will cause you problem. instead try :id="'collapseExpand' + index"
I use Bootstrap Modal for editing user roles. But without using form. just some Checkbox and a buttom for submitting operation.
I use ajax to send data to coontroller.
But in controller side when I want to use Eloquent methods, I get errros like 404 and 500. I really confused. I worked on it for more then 5 hours.
View :
<div class="modal" id="rolesEditModal" role="dialog" > <!--tabindex="-1"-->
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Roles</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="alert" id="imgMessage" style="display:none"></div>
<div class="modal-body bg-gray">
<div class="editRolesElement">
<label for="modalTitle" id="userRolesLabel"><span> </span> User Roles </label>
<!-- checkbox -->
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="sysAdminCheckbox" id="checkbox1">
<label class="form-check-label" for="checkbox1" style="font-weight: bold;color: black">System Admin</label>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="homePageAdminCheckbox" id="checkbox2">
<label class="form-check-label" for="checkbox2">HomaPage Admin</label>
</div>
<div class="form-group form-check">
<input type="checkbox" class="form-check-input" name="aboutUsAdminCheckbox" id="checkbox3">
<label class="form-check-label" for="checkbox3">Aboutus Admin</label>
</div>
<div id="editmessage" style="display:none"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button id="submitModal" type="button" class="btn btn-success" data-dismiss="modal">save</button>
<!--<input type="submit" id="submitModal" class="btn btn-primary" value="Save">--><!--Save changes</button>-->
</div>
script :
<pre><code><script type="text/javascript">
$(document).ready( function () {
$("#submitModal").click(function(){
$('#editmessage').hide();
var systemAdmin = 0;
var homeAdmin = 0;
var aboutUsAdmin = 0;
var portfolioAdmin = 0;
var featuresAdmin = 0;
var contactusAdmin = 0;
var commentAdmin = 0 ;
if($('#checkbox1:checked').val())
{ systemAdmin = 1; } else { systemAdmin = 0; }
if($('#checkbox2:checked').val())
{ homeAdmin = 1; } else { homeAdmin = 0; }
if($('#checkbox3:checked').val())
{ aboutUsAdmin = 1; } else { aboutUsAdmin = 0; }
if($('#checkbox4:checked').val())
{ portfolioAdmin = 1; } else { portfolioAdmin = 0; }
if($('#checkbox5checked').val())
{ featuresAdmin = 1; } else { featuresAdmin = 0; }
if($('#checkbox6:checked').val())
{ contactusAdmin = 1; } else { contactusAdmin = 0; }
if($('#checkbox7:checked').val())
{ commentAdmin = 1; } else { commentAdmin = 0; }
var A_url='';
A_url = "{{ route('userManagement.editRoles') }}";
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url : A_url,
data :
{
userId : $(this).data('userid'),
systemAdmin : systemAdmin,
homeAdmin : homeAdmin,
aboutUsAdmin : aboutUsAdmin,
portfolioAdmin : portfolioAdmin,
featuresAdmin : featuresAdmin,
contactusAdmin : contactusAdmin,
commentAdmin : commentAdmin
},
type : 'post',
fail: function(data){
var incerttxt = '<div class="alert alert-danger" role="alert">Server error</div>';
$('#editmessage').html(incerttxt);
$('#editmessage').fadeIn();
},
success : function( data ) {
//updateUserList_afterEditRoles(data,selectedButton);
console.log(data);
}
});
$('#rolesEditModal').modal('hide');
});
the route :
Route::post('editRoles', 'UserManagementController#editRoles')->name('userManagement.editRoles');
controller :
<pre><code>public function editRoles(Request $request)
{
$userId=$request["userId"];
//$findedUser = User::find($userId)->roles()->orderBy('id')->get();
$findedUser = User::findorfail($request['userId']);
//$findedUser->roles()->detach();
//$findedUser->roles()->attach($roleId);
$assignedRoles = array();
if ($request["systemAdmin"]==="1")
{ array_push($assignedRoles, 1); }
if ($request["homeAdmin"]==="1")
{ array_push($assignedRoles, 2); }
if ($request["aboutUsAdmin"]==="1")
{ array_push($assignedRoles, 3); }
if ($request["portfolioAdmin"]==="1")
{ array_push($assignedRoles, 4); }
if ($request["featuresAdmin"]==="1")
{ array_push($assignedRoles, 5); }
if ($request["contactusAdmin"]==="1")
{ array_push($assignedRoles, 6); }
if ($request["commentAdmin"]==="1")
{ array_push($assignedRoles, 7); }
$findedUser->roles()->sync([2,3,4]/*$assignedRoles*/);
return ($findedUser);
}
</code></pre>
I write the whole implementation without checking. Hope this will work well for you.
Did just small changes and improvements. So you can customize if you want..
BLADE WITH SCRIPT
<div class="modal" id="rolesEditModal" role="dialog" >
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Roles</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="alert" id="imgMessage" style="display:none"></div>
<div class="modal-body bg-gray">
<div class="editRolesElement">
<label for="modalTitle" id="userRolesLabel"><span> </span> User Roles </label>
#foreach($roles as $role)
<div class="form-group form-check">
<input data-id="{{ $role->id }}" type="checkbox" class="form-check-input" id="checkbox_{{ $role->id }}">
<label class="form-check-label" for="checkbox_{{ $role->id }}">{{ $role->name }}</label>
</div>
#endforeach
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button id="submitModal" type="button" class="btn btn-success" data-dismiss="modal">Save</button>
</div>
</div>
</div>
</div>
<script>
function getRoles() {
let roles = {};
$('#rolesEditModal .form-check-input').each(function(i) {
roles [$(this).data('id')] = $(this).prop('checked');
});
return roles;
}
function submitRoles(roles) {
$.ajax({
data: {
_token: "{{ csrf_token() }}",
user_id: "{{ $user->id }}",
roles: roles
},
url: "{{ route('userManagement.editRoles') }}",
type: "POST"
}).done(function (data) {
console.log(data.message);
}).fail(function (jqXHR, ajaxOptions, thrownError) {
console.log("Server error!");
});
}
function destructCheckboxes() {
$('#rolesEditModal .form-check-input').prop('checked', false);
}
$("#submitModal").on('click', function() {
let roles = getRoles();
submitRoles(roles);
destructCheckboxes();
$('#rolesEditModal').modal('hide');
});
</script>
ROUTE
// here you just need to write one more route, which from action will return $roles collection and $user (or $users for your case with foreach in blade) object to the view
Route::post('editRoles', 'UserManagementController#editRoles')->name('userManagement.editRoles');
CONTROLLER
public function editRoles(Request $request)
{
$user = User::findOrfail($request->get('user_id'));
$roles = Role::whereIn('id', $request->get('roles'))->get();
$user->roles()->delete();
$user->roles()->saveMany($roles);
return response()->json([
'success' => true,
'message' => "Roles successfully assigned to the user.",
], 200);
}
NEW UPDATES
In your controller you also have some method for getting your page, right?
I think in your blade you have one $user (for single user's page) or $users (for showing multiple users). So I don't know what exactly in your blade, but you can use one of these methods for your specific case, or both them if you need:
public function singleUserPage($user_id)
{
$user = User::findOrFail($user_id);
$roles = Role::all();
return view('user-management', [ // view for single user
'user' => $user,
'roles' => $roles,
]);
}
// for this you need to loop over on each user in the view, and it will have a same functionality
public function multipleUsersPage()
{
$users = User::all();
$roles = Role::all();
return view('users-management', [ // view for multiple users
'users' => $users,
'roles' => $roles,
]);
}
You will have (or already have) appropriate routes for this methods like this:
Route::get('user/{user_id}', 'UserManagementController#singleUserPage')->name('user_page');
Route::get('users', 'UserManagementController#multipleUsersPage')->name('users_page');
So if you getting the $user as "undefined", you need to send that from controller to the page at first (as I in two methods on the top).
I use Laravel and Vue. I have two components: parent and child.
Parent:
<template>
<div>
<sport-sites-add :applications-all-list="applicationsAll"></sport-sites-add>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Application id</th>
<th scope="col">Name</th>
<th scope="col">Description</th>
<th scope="col">Picture</th>
<th scope="col">URL</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="sportSite in sportSites">
<th scope="row">{{ sportSite.id }}</th>
<td>
<template v-for="application in sportSite.applications">
id {{ application.id }} => {{ application.name }} <br>
</template>
</td>
<td>{{ sportSite.name }}</td>
<td>{{ sportSite.description }}</td>
<td>
<img style="width: 100px; height: 100px;" :src="sportSite.image" >
</td>
<td>
<a :href="sportSite.url" target="_blank">{{ sportSite.url }}</a>
</td>
<td>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import { EventBus } from '../../app';
export default {
name: "SportSitesTable",
mounted(){
this.loadTable();
this.getApplications();
},
methods:{
loadTable: function () {
window.axios.get('/sport_sites_all')
.then(resp => {
this.sportSites = resp.data.data;
}).catch(err => {
console.error(err);
});
},
getApplications: function () {
window.axios.get('/applications/all')
.then(resp => {
this.applicationsAll = resp.data.applications.data;
}).catch(err => {
console.error(err);
});
}
},
data(){
return {
sportSites: [],
applicationsAll: [],
}
},
}
</script>
Child:
<template>
<div>
<button type="button" class="btn btn-primary my-2" data-toggle="modal" data-target="#sportSiteAdd">
Add
</button>
<div class="modal fade" id="sportSiteAdd" tabindex="-1" role="dialog" aria-labelledby="sportSiteAddLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="sportSiteAddLabel">Add sport site</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ul class="alert-danger">
<li v-for="error in errors">
{{ error[0] }}
</li>
</ul>
<form>
<div class="form-group">
<label for="name">Title</label>
<input type="text" class="form-control" id="name" name="name" v-model="formFields.name">
</div>
<div class="form-group">
<label for="image">Picture</label>
<input type="text" class="form-control" id="image" name="image" v-model="formFields.image">
</div>
<div class="form-group">
<label for="url">URL</label>
<input type="text" class="form-control" id="url" name="url" v-model="formFields.url">
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea class="form-control" id="description" name="description" v-model="formFields.description"></textarea>
</div>
<div>
<label class="typo__label">Applications </label>
<multiselect v-model="formFields.applications"
tag-placeholder="Applications"
placeholder="Search"
label="name"
track-by="id"
:options="applications"
:multiple="true"
:taggable="true">
</multiselect>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" v-on:click="submit">Save</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { EventBus } from '../../app';
import Multiselect from 'vue-multiselect'
export default {
name: "SportSitesAdd",
props: ['applicationsAllList'],
methods:{
submit: function (e) {
window.axios.post('/sport_site/add/', this.formFields)
.then(res => {
console.log('Saved!');
$('#sportSiteAdd').modal('hide');
this.formFields.name = '';
this.formFields.image = '';
this.formFields.url = '';
this.formFields.description = '';
EventBus.$emit('reloadApplicationsTable');
}).catch(err => {
if(err.response.status === 422){
this.errors = err.response.data.errors || [];
}
console.error('Error of saving!');
});
},
},
data(){
return {
formFields: {
name: '',
image: '',
url: '',
description: '',
applications: this.applicationsAllList,
},
errors: [],
}
},
components: {
Multiselect
},
}
</script>
The parent component is a table. Child component is a form for the table. I pass a data from the parent to the child via props:
<sport-sites-add :applications-all-list="applicationsAll"></sport-sites-add>
In the child component I have a plugin for creating a multiple select. The plugin requires 'options' and 'values' collections. It's very simple, documentation with my case is here https://vue-multiselect.js.org/#sub-tagging. At the result I want to see the following: all items on the select are selected. But I have just the empty collection during mounting of the child component. I have available items on the 'select' but I dont know how I can make it selected by default. Obviously, I need to copy the applicationsAllList into local data() of child component and use it. But it not available during mounted and beforeMounted.
console.log tells me that the child is faster.
you're missing #tag function & v-model, in this case, must be array, You need to use applicationsAllList props directly on options
<multiselect v-model="formFields.value"
tag-placeholder="Applications"
placeholder="Search"
label="name"
track-by="id"
:options="applicationsAllList"
:multiple="true"
#tag="addTag"
:taggable="true">
</multiselect>
in methods add addTag function and add value as array
data() {
return {
formFields: {
name: '',
value: [],
image: '',
url: '',
description: '',
},
errors: [],
}
},
methods: {
addTag (newTag) {
const tag = {
name: newTag,
code: newTag.substring(0, 2) + Math.floor((Math.random() * 10000000))
}
this.options.push(tag)
this.value.push(tag)
}
}