alpine js, x-model binds to wrong value when switching tabs - laravel

running into an issue with alpine js.
First of all I have a master component that allows the user to switch between two tabs
#props(['pages', 'blogs'])
<div x-data="init()" class="overview row mb30">
<div class="pageContent__content__languages disFlex mb20 bBottom">
<span
#click.prevent='tab = "pages"'
:class='{ "active": tab === "pages" }'
class="pageContent__content__languages__item disFlex aiCenter pt10 pb10 pr10 pl10 mr10 pointer">
Pagina's
</span>
<span
#click.prevent='tab = "blogs"'
:class='{ "active": tab === "blogs" }'
class="pageContent__content__languages__item disFlex aiCenter pt10 pb10 pr10 pl10 bRadius mr10 pointer">
Blogs
</span>
</div>
<div x-show="tab === 'pages'">
<x-form.edit.navigation.pages :pages="$pages" />
</div>
<div x-show="tab === 'blogs'">
<x-form.edit.navigation.blogs :blogs="$blogs" />
</div>
<button type="button" wire:click="navigationAddToMenu" class="btn blue w100 mt10">
Toevoegen aan menu
</button>
</div>
#push('scripts')
#once
<script type='text/javascript'>
function init() {
return {
selected: #entangle('selected'),
tab: 'pages',
};
}
</script>
#endonce
#endpush
These tabs either display pages or blogs depending on which tab is clicked.
Inside of these blade components is just a foreach loop to display the items,
#props(['pages'])
<div style="grid-area: unset" class="pageContent__settings bRadius--lrg disFlex fdCol">
<table class="overview__wrapper">
<tbody class="bRadius--lrg">
#foreach($pages as $page)
<tr class="overview__row bBottom">
<td class="overview__row__checkbox">
<input x-model='selected' value='{{ $page->id }}' type="checkbox"
id="col-row-{{$loop->index}}">
<label for="col-row-{{$loop->index}}"></label>
</td>
<td class="overview__row__name lh1">
{{ $page->page_name }}
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
The blog blade component is nearly identical.
Now the user is able to check a checkbox to add items to their menu, this is binded using the #entangle directive and the x-model on the checkbox.
So far when the user is on the default tab pages and they select a page the correct ID is retrieved from the checkbox, BUT when the user switches tab to the blogs display, and clicks a checkbox the value is retrieved from the pages tab.
e.g.
1 page and 1 blog, page has id of 1 blog has id of 2. User is on the pages tab and clicks on the checkbox the correct value of 1 is now added to the selected array, user switches tabs to blogs and clicks the checkbox the expected behavior would be to have the id of 2 added to the selected array, but it still adds 1.
Inspecting the HTML and the loops do add unique ids to each of their items.

Fixed it, need to make my ids on the input more unique, instead of doing
<input x-model='selected' value='{{ $blog->id }}' type="checkbox"
id="col-row-{{$loop->index}}">
<label for="col-row-{{$loop->index}}"></label>
I added a extra identifier
<input x-model='selected' value='{{ $blog->id }}' type="checkbox"
id="col-row-blogs-{{$loop->index}}">
<label for="col-row-blogs-{{$loop->index}}"></label>
and pages for the pages.
This fixed the issue

Related

knockout - Bring checked checkboxes on top of the list using foreach

<div data-bind="foreach: lists">
<div class="checkbox list-item">
<label>
<input type="checkbox" data-bind="checked: isSelected, click: $parent.list, disable: $parent.disableInput()"/> <span data-bind="text: note">
</label>
</div>
</div>
I tried to do the checked checkboxes to move on top. When I click the unchecked checkbox, it needs to move on top. When I click the checked checkbox, it needs to move back down.
You're going to need an intermediate object to hold the sorted list. Something like:
const sorted_lists = ko.pureComputed(() => {
return lists.sort(a => a.isSelected ? -1 : 0);
});
Then you point your foreach to this computed value:
<div data-bind="foreach: sorted_lists">...

(Vue + Laravel) v-if / v-else inside <td> throws no matching end tag error

I apologize in advance if my question is silly-- Vue newbie here but very eager to learn!
In order to create an interface to manage user privileges in a web app, I've made a component in which I want to create a table with nested v-fors.
For each row, I want 5 cells (): the first one includes text depending on the current iteration of object permisos and the other 4 should be created from the object tipos_permisos (which is an object with 'fixed' values).
The problem:
When I try to compile, I get multiple errors claiming that some tags have no matching end tag. I assume it is due to the v-for nested inside another v-for and/or the v-if inside the innermost v-for... or something like this. The claim is that has no matching tag or that the element uses v-else without corresponding v-if :/
I've tried writing out the last 4 cells manually (without using the tipos_permisos object) but even then, I get errors. In this case, claiming that , and have no matching end tag.
The desired result:
Please note that for some of the resources listed, some of the privileges might not apply (i.e., the log viewer is read-only always so it doesn't have the C (create), U (update) or D (delete) privileges, hence the conditional to show either a checkbox or an icon)
My component:
<template>
<form :action="usr.url.savepermisos" method="post" class="">
<div class="card">
<div class="card-header bg-gd-primary">
<h3 class="card-title">Privilegios de {{ usr.nombre }}</h3>
</div>
<div class="card-content">
<p class="mb-3">
El usuario
<span class="font-w700">{{ usr.nombre }}</span>
tiene los siguientes privilegios:
</p>
<table class="table">
<thead>
<tr>
<th>Recurso</th>
<th>Alta / Creación</th>
<th>Visualización</th>
<th>Edición</th>
<th>Eliminación</th>
</tr>
</thead>
<tbody>
<tr v-for="(recurso, idxrecurso) in permisos">
<td :data-order="recurso.id">{{ recurso.etiqueta }}</td>
<td class="align-middle" v-for="(color,tp) in tipos_permisos">
<label :class="'checkbox checkbox-' + color + ' mycheckbox'" v-if="(typeof recurso[tp] !== "undefined")">
<input type="checkbox" class="checkbox-input check_permiso" />
<span class="checkbox-indicator"></span>
</label>
<i class="fas fa-minus-square fa-lg text-muted" data-toggle="tooltip" title="N/A" v-else></i>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</form>
</template>
<script>
export default {
data() {
return {
tipos_permisos: {
'C': 'success',
'R': 'info',
'U': 'warning',
'D': 'danger'
}
}
},
props: [
'usr',
'permisos',
'perm_log'
]
}
</script>
If something is unclear please let me know so that I can provide further info.
There is a missing "=" after v-for:
<td class="align-middle" v-for"(color,tp) in tipos_permisos">
I didn't understand this part:
v-if="(typeof recurso[tp] !== "undefined")"
If undefined in your code is a string, your condition should be
v-if="recurso[tp] !== 'undefined'"
If it's a real undefined, it should be like this:
v-if="recurso[tp] !== undefiened"

Angular 2 doesn't update my view after I add or edit item

I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}

What is the proper way to edit items in a listview when using Kendo UI Mobile & MVVM?

What is the proper way to edit items in a listview when using Kendo UI Mobile & MVVM?
I don't get the expected results when using the following:
HTML
<div id="itemsView"
data-role="view"
data-model="vm">
<ul data-role="listview" data-bind="source: items"
data-template="itemsTemplate">
</ul>
<script id="itemsTemplate" type="text/x-kendo-template">
<li>
#=Name#
</li>
</script>
<input type="text" data-bind="value: newValue" />
<button data-role="button" data-bind="click: update">update</button>
</div>​
JavaScript
var vm = kendo.observable({
items: [{
Name: "Item1"}],
newValue: '',
update: function(e) {
var item = this.get("items")[0];
item.set("Name", this.get("newValue"));
//adding the follwoing line makes it work as expected
kendo.bind($('#itemsView'), vm);
}
});
kendoApp = new kendo.mobile.Application(document.body, {
transition: "slide"});​
I expect the listview to reflect the change to the Name property of that item. Instead, a new item is added to the listview. Examining the array reveals that there is no additional item, and that the change was made. (re)Binding the view to the view-model updates the list to reflect the change. Re-Binding after a change like this doesn't seem to make any sense.
Here is the jsfiddle:
http://jsfiddle.net/5aCYp/2/
Not sure if I understand your question properly: but this is how I did something similar with Kendo Web UI, I expect mobile is not so different from Web UI from API perspective.
$element.kendoListView({
dataSource: list,
template: idt,
editTemplate: iet,
autoBind: true
});
The way I bind the listview is different, but I guess you can get similar results with your method as well.
I pass two templates to the list view, one for displaying and one for editing.
Display template contains a button (or any element) with css class k-edit to which kendo will automatically bind the listview edit action.
display template:
<div class="item">
# if (city) { #
#: city #<br />
# } #
# if (postCode) { #
#: postCode #<br />
# } #
<div class="btn">
<span class="k-icon k-edit"></span>Edit
<span class="k-icon k-delete"></span>Delete
</div>
</div>
Edit template
<div class="item editable">
<div>City</div>
<div>
<input type="text" data-bind="value: city" name="city" required="required" validationmessage="*" />
<span data-for="city" class="k-invalid-msg"></span>
</div>
<div>Post Code</div>
<div>
<input type="text" data-bind="value: postCode" name="postCode" required="required" validationmessage="*" />
<span data-for="postCode" class="k-invalid-msg"></span>
</div>
<div class="btn">
<span class="k-icon k-update"></span>Save
<span class="k-icon k-cancel"></span>Cancel
</div>
</div>
Clicking that element will put the current element on edit mode using the editTemplate.
Then on the editTemplate there is another button with k-update class, again to which kendo will automatically bind and call the save method on the data source.
Hopefully this will give you more ideas on how to solve your issue.
The problem was caused by the <li> in the template. The widget already supplies the <li> so the additional <li> messes up the rendering. This question was answered by Petyo in the kendo ui forums

Binding text box to telerik upload control MVC3

I want my textbox to display the name of file selected by telerik upload control. Please find the code snippet below.
<td>
#Html.TextBox(txtBox, null, new { style = string.Format("width:200px") })
</td>
<td style="padding-top: 1%; padding-left: 8%">
#(Html.Telerik().Upload().Name(BrowseButton)
//.HtmlAttributes(new { #class = "myCustomClass" }).Multiple(false))
Currently the textbox is displaying null.
The Telerik control should allow you to show the file name. Your extra textbox seems redundant.
Read the telerik documentation and specifically the html and css section. It says the following:
During and after uploading, a file list is displayed, which shows the progress and status of each uploaded file. Its HTML output is the following:
<ul class="t-upload-files t-reset">
<li class="t-file">
<span class="t-icon t-success">uploaded</span>
<span class="t-filename">some-uploaded-file.jpg</span>
<button class="t-button t-button-icontext t-upload-action" type="button">
<span class="t-icon t-delete"></span>Remove</button>
</li>
<li class="t-file">
<span class="t-icon t-fail">failed</span>
<span class="t-filename">some-failed-file.jpg
<span class="t-progress">
<span style="width: 75%;" class="t-progress-status">
</span></span>
</span>
<button class="t-button t-button-icontext t-upload-action" type="button">
<span class="t-icon t-retry"></span>Retry</button>
</li>
</ul>
If you want to update a textbox of your own, simply use their client api by adding this when creating telerik control
#(Html.Telerik().Upload().Name(BrowseButton)
.ClientEvents(events => events.OnSelect("onSelect"))
and in your javascript
function onSelect(e) {
// Array with information about the uploaded files
$('#yourTextboxId').val(e.files[0].name);
}
Again all the details are in the documentation.

Resources