Write VueJS data binding expression in href of <a> tag - laravel

I'm using VueJS 2.0 with Laravel 5.3. I have Vue array data (e.g, items). Now I want to render those data in table using v-for. In table, there is a button to redirect page to item details page. For that, I'm writing my static URL till / in href of tag. Then I'm appending {{item.id}}. But I'm getting this error.
Interpolation inside attributes has been removed. Use v-bind or the
colon shorthand instead. For example, instead of ,
use <div :id="val">
So I can't get that how to write data binding expression of VueJS in <a href="">. If anyone knows the solution, it will be appreciated.
Here is my code.
my-items.blade.php
<div id="app">
....
<tr v-for="item in items">
<td>
view
</td>
</tr>
....
</div>
my-items.js
new Vue({
el: '#app',
data: {
items: [
{id: 1},
{id: 2},
{id: 3}
]
},
})
EDIT
Here is what I was doing in AngularJS with Laravel 5.2. And I want similar like this.
view

It should be like following:
<tr v-for="item in items">
<td>
<a :href="'{{url('/item')}}/' + item.id" />
</td>
</tr>

If you wan't to maintain fixed URL rather than relative URL, you may consider this one:
<div id="app">
<tr v-for="item in items">
<td>
<a :href="'{{ url('/item') }}' + '/' + #{{ item.id }}" />
</td>
</tr>
</div>

Related

(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"

calculate shopping cart sale total in laravel and vuejs

i'm developing a shopping cart with laravel and vuejs i'm new to programming. I want to get the total amount of the products in the shopping cart but I don't understand how to do it.
any help is appreciated
I am using vuejs components, in my data element I have a cart that is the one who has the cart with the products.
<script >
import Axios from 'axios'
export default {
data(){
return{
csrf: document.head.querySelector('meta[name="csrf-token"]').content,
carrito: [],
}
},
mounted(){
Axios.get('carrito')
.then(Response => {this.carrito = Response.data})
},
}
</script>
Inside my template I have a table where it traverses the products with the v-for directive, I would like to have the total in a but I don't understand how I can do this operation
<table class="table">
<thead>
<tr>
<th scope="col">Producto</th>
<th scope="col">Cantidad</th>
<th scope="col">precio</th>
<th scope="col">total</th>
<th scope="col">accion</th>
</tr>
</thead>
<tbody >
<tr v-for="(ProductCart, index) in carrito" :key="index.id">
<td>{{ProductCart.name}}</td>
<td>{{ProductCart.cantidad}}</td>
<td>{{ProductCart.precio}}</td>
<td>{{ProductCart.cantidad * ProductCart.precio}}</td>
<td>
<form action="" method="post">
<input :value="csrf" type="hidden" name="_token" >
<input type="hidden" name="id" id="id" value="<?php echo $producto['id'] ?>" >
<button name="btnAccion" value="Eliminar" class="btn btn-danger" type="submit"> Remove</button>
</form>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2"></th>
<td>
<h2>Total</h2>
</td>
<td align="right">
<h3> </h3>
</td>
</tr>
</tfoot>
</table>
so I receive the data
{1: {id: "1", name: "Motor 1", cantidad: "1", precio: "20.00"}}
1: {id: "1", name: "Motor 1", cantidad: "1", precio: "20.00"}
cantidad: "1"
id: "1"
name: "Motor 1"
precio: "20.00"
It seems like computed properties would work best in your case. I'm not sure how the data in carrito is structured, but assuming it looks something like this:
carrito: {
1: {
"id":"1",
"name":"Motor 1",
"cantidad":"1",
"precio":"20.00"
}
...
}
...you would have to loop through carrito, take the precio times the cantidad of each object, and add it to a running total. Here's an example:
total: function () {
let total = 0;
Object.values(this.carrito).forEach(
(item) => (total += item.precio * item.cantidad)
);
return total;
}
Object.values returns an array of just the values of carrito, which is then iterated through by .forEach, and its precios/cantidads are multiplied together, and then then added to the running total, and returned.
total would go in computed: {}, within your Vue instance. Computed properties are re-evaluated when dependant data changes, so total will be reevaluated whenever carrito changes. You can then place it wherever you want in the page, like a normal data property:
...
<tfoot>
<tr>
<th colspan="2"></th>
<td>
<h2>Total</h2>
</td>
<td align="right">
<h3>{{ total }}</h3>
</td>
</tr>
</tfoot>
...
Check out the demo here, (network fetching is simulated, so it takes two seconds to load carrito) and its code here.
More info on computed properties:
Computed Properties and Watchers: Vue Docs
Computed Properties: Vue Mastery
You could create a computed property or a method for your component. There you could loop all the items and add each price to a total variable. Then you return the total.
Have a look here: Vue computed properties

Order table column in asc/desc order with datatables

I am using datatable v1.10.13. I am having problem displaying data according to created_at of laravel. While fetching data, I am getting posts according to created_at desc but while displaying data it shows data in alphabetical order. How can I get latest post first with datatables? I am not populating data with ajax.
I have this query to get posts in PostController:
$allPost = $this->post->orderBy('created_at', 'desc')->get();
I have following code in html:
<div class="dt-responsive table-responsive">
<table id="posts-data" class="table table-striped table-bordered nowrap dataTable no-footer" role="grid" aria-describedby="basic-col-reorder_info">
<thead>
<tr>
<th>Title</th>
<th>Category</th>
<th>Status</th>
<th>Image</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#if(!empty($allPost)) #foreach($allPost as $postsLists)
<tr>
<td>{{ $postsLists->title }}</td>
<td>
#if(!empty($postsLists->categories)) #foreach($postsLists->categories as $cat_lists)
<i class="icofont icofont-arrow-right"></i> {{$cat_lists->name}}
<br> #endforeach #endif
</td>
<td>{{ $postsLists->status }}</td>
<td><img src="{{ $postsLists->image }}" alt="" width="100"></td>
<td>View image</td>
<td>
<a href="{{ route('posts.edit', $postsLists->id) }}" class="btn btn-primary btn-sm pull-left" style="margin-right: 5px">
<span class="icofont icofont-ui-edit"></span>
</a>
<a class="pull-left" onclick="return confirm('Are you sure you want to delete this post?')">
<form method="POST" action="{{ route('posts.destroy', $postsLists->id) }}" accept-charset="UTF-8">
<input name="_method" type="hidden" value="DELETE">
<input name="_token" type="hidden" value="{{ csrf_token() }}">
<button class="btn btn-danger btn-sm" type="submit"><span class="icofont icofont-ui-delete"></span></button>
</form>
</a>
</td>
</tr>
#endforeach #endif
</tbody>
</table>
I have following code to call initialize datatable:
$('#posts-data').DataTable({
colReorder: true,
pageLength: 0,
lengthMenu: [20, 40, 60, 80, 90, 100],
});
Adding order: [] should solve your problem:
$('#posts-data').DataTable({
colReorder: true,
order: [],
pageLength: 0,
lengthMenu: [20, 40, 60, 80, 90, 100],
});
By default datatable will sort the table by first column, so the title in your case, but since you are providing the inital ordering from your data, you can set the default ordering to an empty array.
Some suggestions:
1) The DataTables "no default sort" option
The solution proposed by #Remul - order: [] - should have worked. This suggests there is a problem elsewhere, potentially interfering with DataTables. Some suggestions:
(a) The foreach iterator is doing something surprising. Unlikely, but you may want to check that.
(b) Can you get DataTables to initially sort by any other field using order []? For example, sort by the first column in descending order:
order: [[ 0 , "desc" ]],
(c) Is your DataTables initializer placed inside a document ready function?
$(document).ready(function() {
$('#posts-data').DataTable({
colReorder: true,
order: [],
pageLength: 0,
lengthMenu: [20, 40, 60, 80, 90, 100],
});
});
I'm sure it is - but just in case...
2) Add your created_at data to the table
I assume this is a date, or datetime field. DataTables has somewhat limited support for sorting dates and times (without using plugins) so I recommend formatting your data as a sortable string field (e.g. YYYY-MM-DD HH24:MI:SS or whatever variant works for you).
(a) You can add it as a hidden field.
(b) Just a suggestion: Consider adding it as a visible field. Otherwise, users may sort the data by some other column, and they will not be able to return to the originally displayed sort order (created_at descending). Something like this:
"columnDefs": [
{
"targets": 5, // assuming the datetime is the 6th column
"visible": false
}
]
3) Build up from a Basic Solution
Strip out everything which is not needed to demonstrate the sort order you want. So, for example, remove the colReorder; remove all columns except the first one, and so on. Assuming it starts working at some point, you can add items back one-by-one.

How to append div in a vue template

I have a template which I run a for
<tr v-for="entry in filteredData">
<td>
#{{ entry.position}}
</td>
<td :class="addNewElement(entry.value)">
</td>
<td>
#{{ Math.round(entry.chanceOfApproval*100) }}
</td>
</tr>
I need that the method addNewElement append a div into this column, but I don't know how can I do that in my template
The answer depends on the version of Vue.js you are using. For a given Vue instance
{
...
methods: {
renderEl() {
return '<div>...</div>'
}
}
}
In Vue 1.x you can do (docs)
{{{ renderEl () }}}
In Vue 2.x you can do (docs)
<div v-html="renderEl()"></div>

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();
}

Resources