How to show nested array data in vuejs component - laravel

I'm running the following query:
$users=User::with('roles.permissions')->get()->unique();
this query returns result set:
Array = [
{
created_at: "2019-01-11 09:27:02",
deleted_at: null,
email: "admin#example.com",
email_verified_at: null,
id: 1,
name: "ADMIN",
roles: [
{id: 1, name: "Admin", slug: "Admin", description: "This is Super-Admin Role", created_at: "2019-01-11 09:27:02",
permissions: [
{id:1, name:"Create,slug:"Create"},
{id:1, name:"Read",slug:"Read"},
{id:1, name:"Delete",slug:"Delete"},
],
},
],
},
]
returns user details with roles I want to show this result set in my Vue Component table.
this my vue component read method
read:function(){
axios.get('/userlist')
.then(response=>{
console.log(response.data);
})
}
This is my table
<table class="table table-bordered">
<thead>
<th>no.</th>
<th>Name</th>
<th>E-mail</th>
<th>Roles</th>
<th>Permissions</th>
<th>Action</th>
</thead>
<tbody>
<tr v-for="(user,key) in users">
<td>{{++key}}</td>
</tr>
</tbody>
</table>
How to show user,roles and permissions separately in html table.

You should store your API result in your component data. But you need to prepare your component data to receive your users.
data() {
return {
users: []
}
}
Now, you should make your function update this brand new data.
read:function(){
axios.get('/userlist')
.then(response=>{
this.users = response.data;
})
}
Now, I assume that you want to display user's roles as a concatenated string. Then, you need a function to do this.
methods: {
getRoles: function(roles) {
let rolesString = ''
roles.forEach((role, index) => {
if (index != 0)
rolesString += ', '
rolesString = rolesString + role.name
})
return rolesString
},
getPermissionsFromRoles: function(roles) {
let permissionsList = []
roles.permissions.forEach((permission) => {
if (permissionsList.indexOf(permission.name) != -1) {
permissionsList.push(permission.name)
}
})
let permissionsString = ''
if (permissionsList.length > 0) {
permissionsList.forEach((permission, index) => {
if (index != 0)
permissionsString += ', '
permissionsString += permission
})
}
return permissionsString
}
}
Then, you can use this function in your template to handle your user roles.
<table class="table table-bordered">
<thead>
<th>no.</th>
<th>Name</th>
<th>E-mail</th>
<th>Roles</th>
<th>Permissions</th>
</thead>
<tbody>
<tr v-for="(user,key) in users">
<td>{{key}}</td>
<td>{{user.name}}</td>
<td>{{user.email}}</td>
<td>{{getRoles(user.roles)}}</td>
<td>{{getPermissionsFromRoles(user.roles)}}</td>
</tr>
</tbody>
</table>

rendering in the template will look like:
<td v-for="role in roles">{{role}}</td>
you will also need to have roles in your data:
data() {
return {
roles: []
}
}
and finally make your function update the data
function(){
.then(response=>{
this.roles = response.data
})
}

Related

Filter records using daterangetime picker

I have a target where I need to filter the data using daterange with time picker. The thing is I need to show the result of my filtered data based on what I selected on the said daterange with time picker I have provided my codes below and my target. Thank you so much in advance.
Views:
<div class="card-body table-responsive py-3 px-3">
<input type="text" id="demo" name="daterange" value="06/05/2021 - 06/06/2021" style="width:350px;">
<button class="btn btn-success float-right" onclick="add_person()" data-dismiss="modal"><i class="glyphicon glyphicon-plus"></i> Add Person</button>
<table id="table_account" class="table table-bordered table-hover" cellspacing="0">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Email</th>
<th>Mobile</th>
<th>Role</th>
<th>Status </th>
<!-- <th>File </th> -->
<th>Added By</th>
<th>Date Created</th>
<th>Date Updated</th>
<th>Updated By</th>
<th style="width:100x;">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</script>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Email</th>
<th>Mobile</th>
<th>Role</th>
<th>Status </th>
<th>Added By</th>
<th>Date Created</th>
<th>Date Updated</th>
<th>Updated By</th>
<th style="width:100x;">Action</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
Ajax:
<script>
// first, put this at the top of your JS code.
let dateParams = {}
// update this with setting dataParams
$('#demo').daterangepicker({
"timePicker": true,
"timePicker24Hour": true,
"startDate": "06/05/2021",
"endDate": "06/06/2021",
locale: {
format: 'M/DD/YYYY hh:mm A'
}
}, function(start, end, label) {
// set the dateParam obj
dateParams = {
start: start.format('YYYY-MM-DD hh:mm'),
end: end.format('YYYY-MM-DD hh:mm')
}
console.log('New date range selected: ' + start.format('YYYY-MM-DD hh:mm') + ' to ' + end.format('YYYY-MM-DD hh:mm') + ' (predefined range: ' + start + + end +')');
});
$(document).ready(function() {
//datatables
table = $('#table_account').DataTable({
dom: 'lBfrtip',
buttons: [
'print', 'csv', 'copy', 'excel', 'pdfHtml5'
],
"processing": false, //Feature control the processing indicator.
"serverSide": true, //Feature control DataTables' server-side processing mode.
"order": [], //Initial no order.
// Load data for the table's content from an Ajax source
"ajax": {
"url": "<?php echo site_url('profile/ajax_list')?>",
"type": "POST",
"data": function (dateParams) {
return $.extend( { "start": dateParams.start,
"end": dateParams.end,}, dateParams, {
});
},
},
//Set column definition initialization properties.
"columnDefs": [
{
"targets": [ 0 ], //first column
"orderable": false, //set not orderable
},
{
"targets": [ -1 ], //last column
"orderable": false, //set not orderable
},
],
});
});
setInterval( function () {
table.ajax.reload(null,false);
}, 1000);
</script>
Controller:
public function ajax_list()
{
$list = $this->profiles->get_datatables();
$data = array();
$no = $_POST['start'];
foreach ($list as $person) {
$no++;
$row = array();
$row[] = $person->firstname;
$row[] = $person->lastname;
$row[] = $person->username;
$row[] = $person->email;
$row[] = $person->mobile;
$row[] = $person->role;
$row[] = $person->status;
$row[] = $person->addedBy;
$row[] = $person->dateCreated;
$row[] = $person->updatedBy;
$row[] = $person->dateUpdated;
//add html for action
$row[] = '<a class="btn btn-sm btn-primary" href="javascript:void(0)" title="Edit" onclick="edit_person('."'".$person->userID."'".')"><i class="glyphicon glyphicon-pencil"></i> Edit</a>';
$data[] = $row;
}
$output = array(
"draw" => $_POST['draw'],
"recordsTotal" => $this->profiles->count_all(),
"recordsFiltered" => $this->profiles->count_filtered(),
"data" => $data,
);
//output to json format
echo json_encode($output);
}
Model:
var $table = 'users';
var $column_order = array(null,'userID','firstname','lastname','username','email','mobile','addedBy','dateCreated');
var $order = array('userID' => 'desc');
var $column_search = array('email','firstname','lastname','username','email','mobile','dateCreated');
//set column field database for datatable orderable //set column field database for datatable searchable just firstname , lastname , address are searchable var $order = array('id' => 'desc'); // default order
private function _get_datatables_query()
{
if($this->input->post('daterange')){
$this->db->where('dateCreated >=', $this->input->post('start'));
$this->db->where('dateCreated <=', $this->input->post('end'));
}
// $this->input->post('start'); // YYYY-mm-dd
// $this->input->post('end'); // YYYY-mm-dd
$this->db->from($this->table);
$i = 0;
foreach ($this->column_search as $item) // loop column
{
if($_POST['search']['value']) // if datatable send POST for search
{
if($i===0) // first loop
{
$this->db->group_start(); // open bracket. query Where with OR clause better with bracket. because maybe can combine with other WHERE with AND.
$this->db->like($item, $_POST['search']['value']);
}
else
{
$this->db->or_like($item, $_POST['search']['value']);
}
if(count($this->column_search) - 1 == $i) //last loop
$this->db->group_end(); //close bracket
}
$i++;
}
if(isset($_POST['order'])) // here order processing
{
$this->db->order_by($this->column_order[$_POST['order']['0']['column']], $_POST['order']['0']['dir']);
}
else if(isset($this->order))
{
$order = $this->order;
$this->db->order_by(key($order), $order[key($order)]);
}
}
function get_datatables()
{
$this->_get_datatables_query();
if($_POST['length'] != -1)
$this->db->limit($_POST['length'], $_POST['start']);
$query = $this->db->get();
return $query->result();
}
To connect the calendar with the data output table, edit your daterangepicker initialization:
// first, put this at the top of your JS code.
let dateParams = {}
// update this with setting dataParams
$('#demo').daterangepicker({
"timePicker": true,
"timePicker24Hour": true,
"startDate": "06/05/2021",
"endDate": "06/06/2021",
locale: {
format: 'M/DD hh:mm A'
}
}, function(start, end, label) {
// set the dateParam obj
dataParams = {
start: start.format('YYYY-MM-DD'),
end: end.format('YYYY-MM-DD')
}
// reload the table
table.ajax.reload();
//console.log('New date range selected: ' + start.format('YYYY-MM-DD') + ' to ' + end.format('YYYY-MM-DD') + ' (predefined range: ' + label + ')');
});
Over in your DataTable() setup change your ajax to pass the start and end dates
"ajax": {
"url": "<?php echo site_url('profile/ajax_list')?>",
"type": "POST",
"data": function ( d ) {
// add this
return $.extend( {}, d, {
"start": dataParams.start,
"end": dataParams.end
});
// could also be written: return $.extend( {}, d, dataParams);
}
}
Finally, you'll need to pick this up in your CI app so you can search you DB.
$this->input->post('start'); // YYYY-mm-dd
$this->input->post('end'); // YYYY-mm-dd
Then this is just a nit. Please move <table id="table_account" class="table table-bordered table-hover" cellspacing="0"> to right above the first <thead>. Right now there is the datepicker element in between them. Might not matter, but it should be fixed.
https://datatables.net/reference/option/ajax

Datatable display problem using vue-axios and laravel

Im using jQuery datatables for displaying my data in my users component in Vue.js, but when I run my code it displays the data but it has some text that says "No data found". Can someone help me with this? I really don't have any idea because I'm new in this Frontend tools.
Users.vue:
<template>
<table id="table" class="table table-striped table-bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<th>Type</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<tr v-for="user in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.type }}</td>
<td>{{ user.created_at }}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
data() {
return {
users: [],
form: new Form({
id: "",
name: "",
email: "",
password: "",
type: ""
})
};
},
methods: {
loadUsers() {
axios.get("api/user").then(({ data }) => (this.users = data));
}
},
created() {
console.log("Component mounted.");
this.loadUsers();
}
};
$(document).ready(function() {
$("#table").DataTable({});
});
</script>
Probably, you should init your widget DataTable after receiving data from api, more precisely in then method.
axios.get("api/user").then(({ data }) => {
this.users = data;
this.$nextTick(() => {
$("#table").DataTable({});
});
});
Explanation about Vue.$nextTick:
Defer the callback to be executed after the next DOM update cycle. Use
it immediately after you’ve changed some data to wait for the DOM
update. This is the same as the global Vue.nextTick, except that the
callback’s this context is automatically bound to the instance calling
this method.
axios.get("api/user").then(({ data }) => {
this.users = data;
$(function() {
$("#table").DataTable({});
});
});

Retrieve data using axios vue.js

I retrieve data using axios in methods created () like this:
data() {
return {
filterBox: false,
color: [],
sortBy: null,
productType: [],
products: null,
productcolors: null,
categories: null,
active_el: 0,
isActive: false,
categories: null,
inputSearch: '',
}
},
created() {
axios.get('/admin/product_index_vue').then(response => {
this.products = response.data.products.data;
this.productcolors = response.data.productcolors;
this.categories = response.data.categories;
console.log(this.products.length);
}).catch((error) => {
alert("ERROR !!");
});
},
when checking using console.log the data is there :
Vue DevTools :
but when trying to check the mounted () function I get empty data
what is the cause of this problem?
what I really want is to create a filter, but when using this function the data will not appear :
computed: {
filteredProduct: function () {
if (this.products.length > 0) {
return this.products.filter((item) => {
return (this.inputSearch.length === 0 || item.name.includes(this.inputSearch));
});
}
}
},
HTML CODE :
<tr v-for="product in filteredProduct">
<td style="width:20px;">{{product.id}}</td>
<td class="table-img-product">
<img class="img-fluid" alt="IMG">
</td>
<td> {{ product.name }}</td>
<td style="display:none">{{product.product_code}}</td>
<td>{{ product.base_color }}</td>
<td>{{ product.category }}</td>
<td>{{ product.price }}</td>
<td>{{ product.stock }}</td>
<td>{{ product.status }}</td>
<td>
<button type="button" name="button" v-on:click="deleteProduct(product.id,product.product_color_id)">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
RESULT
app.js:36719 [Vue warn]: Error in render: "TypeError: Cannot read
property 'length' of null"
found in
---> at resources\assets\js\components\products\Product_index.vue
what causes this function to not work and no detected product data?
This is because the computed property will potentially be calculated before the response has been returned.
If your data properties are going to be an array then I would suggest defining them as an array from the beginning. In the data object change the properties to something like e.g.
products: [],
productcolors: [],
Alternatively, you can add an additional check to your computed property method:
filteredProduct: function () {
if (!this.products) {
return [];
}
return this.products.filter((item) => {
return (this.inputSearch.length === 0 || item.name.includes(this.inputSearch));
});
}
this is axios response ont wording
mounted: {
let self = this
axios.get('/admin/product_index_vue').then(response=>{
self.products=response.data.products.data;
self.productcolors =response.data.productcolors;
self.categories=response.data.categories;
console.log(self.products.length);
}).catch((error)=>{
alert("ERROR !!");
});
},

Can't get data in laravel vue

I try to show detail of my posts by slugs but data won't render. i just get my navbar and white page,
Code
controller
public function single($slug)
{
$post = Post::where('slug', $slug)->first();
return response()->json([
"post" => $post
], 200);
}
single.vue where i show my single post data
<template>
<div class="post-view" v-if="post">
<div class="user-img">
<img src="...." alt="">
</div>
<div class="post-info">
<table class="table">
<tr>
<th>ID</th>
<td>{{ post.id }}</td>
</tr>
<tr>
<th>Title</th>
<td>{{ post.title }}</td>
</tr>
<tr>
<th>Body</th>
<td>{{ post.body }}</td>
</tr>
</table>
<router-link to="/blog">Back to all post</router-link>
</div>
</div>
</template>
<script>
export default {
created() {
if (this.posts.length) {
this.project = this.posts.find((post) => post.slug == this.$route.params.slug);
} else {
axios.get(`/api/posts/${this.$route.params.slug}`)
.then((response) => {
this.post = response.data.post
});
}
},
data() {
return {
post: null
};
},
computed: {
currentUser() {
return this.$store.getters.currentUser;
},
posts() {
return this.$store.getters.posts;
}
}
}
</script>
vuex store.js
state: {
posts: []
},
getters: {
posts(state) {
return state.posts;
}
},
mutations: {
updatePosts(state, payload) {
state.posts = payload;
}
},
actions: {
getPosts(context) {
axios.get('/api/posts')
.then((response) => {
context.commit('updatePosts', response.data.posts);
})
}
}
Question
Why I can't get my post data? is there any mistake in my code?
................................................................................................................................................................................
You're calling /api/posts/${this.$route.params.slug}, which (by REST convention) returns ONE post object.
When setting your post (this.post = response.data.post) you should use response.data (without .post)

How to use server side option in Angular DataTables with the Angular way example?

I'm trying to use Angular DataTables with the server side processing option, but when I try to enable it in their "Angular way example", only the first request gets rendered, the subsequent requests (paging, ordering, searching) are sent but they never update the table.
After a little digging, I found an unrelated user contributed note that suggests that you override the ajax option with your own function to handle the server side call.
The trick here is to return an empty array to the DataTables callback, so it won't use its renderer to render the table. That will be done by Angular. It's also a good idea to specify the columns names to the server.
ngOnInit(): void {
var that = this;
this.dtOptions = {
pagingType: 'full_numbers',
serverSide: true,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
that.http
.post<DataTablesResponse>('/api/Persons', dataTablesParameters, {})
.subscribe(resp => {
that.persons = resp.data;
callback({
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsFiltered,
data: [],
});
});
},
columns: [
{ data: "id" },
{ data: "firstName" },
{ data: "lastName" },
],
};
}
Since DataTables will think there are no rows to display, it will show the "No data available" message. The simplest way to handle it is to hide it with CSS. You can add it to your global styles.css:
.dataTables_empty {
display: none;
}
then show it yourself in the template:
<tr *ngIf="persons?.length == 0">
<td colspan="3" class="no-data-available">No data!</td>
</tr>
So here's the complete code. Tested with Angular 5.0.0, datatables.net 1.10.16 and angular-datatables 5.0.0:
angular-way-server-side.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient, HttpResponse } from '#angular/common/http';
import { DataTablesResponse } from '../datatables/datatables-response';
import { Person } from './person';
#Component({
selector: 'app-angular-way-server-side',
templateUrl: 'angular-way-server-side.component.html',
styleUrls: ['angular-way-server-side.component.css'],
})
export class AngularWayServerSideComponent implements OnInit {
dtOptions: DataTables.Settings = {};
persons: Person[];
constructor(private http: HttpClient) { }
ngOnInit(): void {
var that = this;
this.dtOptions = {
pagingType: 'full_numbers',
serverSide: true,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
that.http
.post<DataTablesResponse>('/api/Persons', dataTablesParameters, {})
.subscribe(resp => {
that.persons = resp.data;
callback({
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsFiltered,
data: [],
});
});
},
columns: [
{ data: "id" },
{ data: "firstName" },
{ data: "lastName" },
],
};
}
}
angular-way-server-side.component.html
<table datatable [dtOptions]="dtOptions" class="row-border hover">
<thead>
<tr>
<th>ID</th>
<th>First name</th>
<th>Last name</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let person of persons">
<td>{{ person.id }}</td>
<td>{{ person.firstName }}</td>
<td>{{ person.lastName }}</td>
</tr>
<tr *ngIf="persons?.length == 0">
<td colspan="3" class="no-data-available">No data!</td>
</tr>
</tbody>
</table>
angular-way-server-side.component.css
.no-data-available {
text-align: center;
}
person.ts
export class Person {
id: number;
firstName: string;
lastName: string;
}
datatables-response.ts
export class DataTablesResponse {
data: any[];
draw: number;
recordsFiltered: number;
recordsTotal: number;
}
src/styles.css
.dataTables_empty {
display: none;
}
The server side is implemented pretty much the same way as if you were using DataTables with JavaScript/jQuery. You can see a very simple sample implementation in PHP.

Resources