Order table column in asc/desc order with datatables - laravel

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.

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

Laravel Blade foreach loop in Laravel-DOMPDF output file

I'm having issues using DOMPDF and Laravel Blade. I'm using DOMPDF to render a blade view into PDF following their documentation, but when I have records that span more than a page, it cuts them off. It's like overflow:hidden is added to the page so the records won't show. You can see by the image below. You can clearly see there is another record at the bottom, but the next page is qualifications, not the next record in the list.
I have tried using page breaks and all sorts to try and get this working, but for the life of me this just does not want to play ball.
I can't find anything in their documentation that suggests this is an issue and I'm not sure what's causing it.
Package used: barryvdh/laravel-dompdf
The rendered PDF:
The section of the view that's being loaded:
Please excuse the tables, but as PDFs don't load CSS3, I have to go back to basics to get the proper styling results needed for the PDF.
<tr>
<td class="border-b-4 border-grey-200 pb-5 mb-5">
<table width="100%" class="mb-5" style="width:100%" border="0" cellpadding="0">
<tr>
<td>
<h1 class="text-6 text-grey-700 mb-3">Employment History</h1>
</td>
</tr>
</table>
#foreach ($employers as $employer)
<table width="100%" class="mb-5" style="width:100%" border="0" cellpadding="0">
<tr>
<td class="border border-grey-200 p-5 rounded">
<h2 class="capitalize text-grey-700 text-lg">{{ $employer->job_title }}</h2>
<span class="text-grey-600">{{ $employer->employer_name }}</span>
<p class="my-3 text-blue-500 text-sm">
<span>{{ date('jS F Y', strtotime($employer->from_date)) }}</span>
<span> — </span>
#if ($employer->current != 1)
<span>{{ date('jS F Y', strtotime($employer->to_date)) }}</span>
#else
<span>Present</span>
#endif
</p>
<div class="markdown text-grey-700">{!! $employer->description !!}</div>
</td>
</tr>
</table>
#endforeach
</td>
</tr>
The PDF controller:
PDF::setOptions([
'dpi' => 150,
'defaultFont' => 'sans-serif',
'fontHeightRatio' => 1,
'isPhpEnabled' => true,
]);
$pdf = PDF::loadView('pdf_cv', [
'cv' => $cv,
'awards' => $awards,
'employers' => $employers,
'hobbies' => $hobbies,
'images' => $images,
'languages' => $languages,
'projects' => $projects,
'qualifications' => $qualifications,
'skills' => $skills
]);
return $pdf->stream();
I've done the Googling, read their documentation countless times and I'm bemused by this issue, so hopefully, someone else has experienced this too and can lend a helping hand.
If you need more information, I can provide it.
The issue with this was the table setup. I don't know exactly what was happening because you can't inspect PDFs but the table seemed to keep overlapping causing it run off the page.

ajax call in beforeCreate does not update data

I'm trying to get Vue to update value through an api call. I log the searches two times: ones outside the beforeCreate and once inside. Outside it gives the initial value of 'searches', inside the correct, new value.
The main problem is that I don't see the updated values.
<div id="app">
<!-- shows when there are no searches -->
<p class="text-center" v-if="searches === null">Er werden nog geen zoekopdrachten uitgevoerd.</p>
<!-- this div gets repeated for every search -->
<div class="search border border-info rounded p-3 m-3 row" v-for="search in searches">
<table class="col-6">
<tr>
<td class="text-info">Zoekwoorden</td>
<td v-for="keyword in search.keywords">#{{ keyword }}</td>
</tr>
<tr class="even">
<td class="text-info">Platforms</td>
<td v-for="platform in search.platforms">#{{ platform }}</td>
</tr>
<tr>
<td class="text-info">Gerelateerde zoekwoorden</td>
<td v-for="keyword in search.all_keywords">
#{{ keyword }}
</td>
</tr>
<tr class="even">
<td class="text-info">Locatie</td>
<td>Voskenslaan, Gent</td>
</tr>
<tr>
<td class="text-info">Datum</td>
<td>#{{ search.created_at }}</td>
</tr>
</table>
<div class="col-6 text-right">
<button type="button" class="close" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h3 class="search-id text-secondary">##{{ search.id }}</h3>
<a :href="'/searches/' + search.id " role="button" class="btn btn-info details-button">Details...</a>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var $root = new Vue({
el: '#app',
data:
{
searches: [
{ id: 123, keywords: ['sample', 'sample'], platforms: ['sample', 'sample'] },
{ id: 123, keywords: ['sample', 'sample'], platforms: ['sample', 'sample'] }
]
},
beforeCreate: function ()
{
var vm = this;
$.get("api/searches", function(data, status){
vm.$set(vm,'searches', data); //zet de waarde van searches gelijk aan de opgehaalde
console.log(vm.searches); //geeft juiste opgehaalde searches
});
}
});
console.log($root.searches); //geeft de initiële twee sample searches
</script>
I think you may want to try beforeMount instead of beforeCreate.
beforeCreate fires before anything in the component is initialied, according to the docs:
Called synchronously immediately after the instance has been initialized, before data observation and event/watcher setup.
I haven't tested it, but I would be willing to bet this is your issue. Since there are no watchers or data structures initialized, your call to vm.$set(vm,'searches', data) is being overwritten by the component data structure
Whereas beforeMount is called after data and events/watchers have been initialized:
Called right before the mounting begins: the render function is about to be called for the first time.
I would probably also just push to the existing array instead of replacing it as such as this (especially if you have populated the search array as in your example):
beforeMount: function () {
var vm = this;
$.get("api/searches", function(data, status){
vm.searches.push(...data); // assuming data is an array
console.log(vm.searches);
});
},
mounted: function(){
var vm = this;
console.log(vm.searches);
},

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

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>

Resources