How to populate the v-data-table after an AJAX request to fetch the data using Vuetify in Laravel? - ajax

Using VueJS with Vuetify and in Laravel framework. Many different methods of AJAX and defining components were tried but nothing worked. It seems that when the ajax call is made, the variable is updated, which I checked in the console.log, but it is not reflected in the DOM.
My current code is as follows
Method 1
In the home.blade.php
<div id="items-display-table">
#{{itemslist}}
<v-data-table
:items="itemslist"
class="elevation-1"
hide-actions
hide-headers
>
<template slot="items" slot-scope="props">
<td>#{{ props.item.name }}</td>
<td class="text-xs-right">#{{ props.item.calories }}</td>
<td class="text-xs-right">#{{ props.item.fat }}</td>
<td class="text-xs-right">#{{ props.item.carbs }}</td>
<td class="text-xs-right">#{{ props.item.protein }}</td>
<td class="text-xs-right">#{{ props.item.iron }}</td>
</template>
</v-data-table>
</div>
And in the app.js
var itemsDisplayTable = new Vue({
el: '#items-display-table',
data: {
itemslist: []
},
created: function () {
this.fetchData();
},
methods: {
fetchData: function () {
var self = this;
var apiURL = '/api/cards';
axios.get( apiURL )
.then ( function( response ) {
data = response['data'];
// console.log(data);
self.itemslist = data;
console.log(self._data);
});
}
}
});
Method 2
Alternatively, I have also tried building a component with the data passed as a prop to solve the reactive issue but still it doesn't work.
The code for that is as follows in home.blade.php
<div id="cards-display-table">
<grid
:itemslist="itemslist">
</grid>
</div>
In app.js
Vue.component('grid', require('./components/DataTable.vue'));
And the instance creation is same as above.
The code in the DataTable.vue file is as follows
<template>
<div>{{itemslist}}</div>
<v-data-table
:items="itemslist"
class="elevation-1"
hide-actions
hide-headers
>
<template slot="items" slot-scope="props">
<td>#{{ props.item.name }}</td>
<td class="text-xs-right">#{{ props.item.calories }}</td>\
<td class="text-xs-right">#{{ props.item.fat }}</td>\
<td class="text-xs-right">#{{ props.item.carbs }}</td>\
<td class="text-xs-right">#{{ props.item.protein }}</td>\
<td class="text-xs-right">#{{ props.item.iron }}</td>\
</template>
</v-data-table>
</template>
<script>
export default {
props: {
itemslist: Array
}
}
</script>
How should i proceed?

I found a solution to my question. It was a pretty silly mistake. So just in case, anyone faces it again, I have decided to answer it.
The problem was that I was registering a new root component to display the items in the app.js file. And it is clearly mentioned that for the Vuetify components to work, they must be wrapped in the <v-app>. So I put the components in a single file and now it is working perfectly.

Related

Im confuse with axios in seperate service file

Im now is learn vue.js, and i want to consume API from my backend (using spring).
This is my service.js
import axios from "axios";
class LowonganKerjaService {
retrieveAllLoker() {
return axios.get('http://localhost:8081/api/listLoker');
}
deleteLoker(idLowongan){
return axios.delete('http://localhost:8081/api/${idLowongan}');
}
}
export default new LowonganKerjaService();
this is my component
<template>
<div class="container">
<h3>All Courses</h3>
<div v-if="message" class="alert alert-success">
{{message}}
</div>
<div class="container">
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr v-for="loker in loker" v-bind:key="loker.idLowongan">
<td>{{loker.idLowongan}}</td>
<td>{{loker.deskripsi}}</td>
<td>
<button class="btn btn-warning" v-on:click="deleteLokerClicked(loker.idLowongan)">
Hapus
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import LowonganKerjaService from '../../service/LowonganKerjaService';
export default {
name : "LokerList",
data() {
return{
loker : []
};
},
methods:{
refreshLoker(){
LowonganKerjaService.retrieveAllLoker()
.then(response => {
this.loker = response.data;
});
},
deleteLokerClicked(idLowongan){
LowonganKerjaService.deleteLoker(idLowongan).then(()=> {
this.message = 'Loker dengan ${idLowongan} berhasil dihapus';
this.refreshLoker();
});
}
},
created(){
this.refreshLoker();
}
};
</script>
<style>
</style>
and i got this error
Failed to compile.
./src/service/LowonganKerjaService.js Module Error (from
./node_modules/eslint-loader/index.js):
D:\Kuliah\TERM
6\Propensi\Implementasi\frontend-sixacti\src\service\LowonganKerjaService.js
10:17 error 'idLowongan' is defined but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
Oh and i've got error too when i use ${} in those service.
Why that error state that my 'idLowongan' is never used? is it because i wrong my syntaks or what?
Please somebody help me to give the reason
Thanks
**sorry for my bad language
From the looks of your code it looks like you're using a single quote (') and not a backtick (`) when you're attempting to use JS template literal. You can see an example of that in the MSDN documentation. Since it is a string in your example and not a template literal the variable in the function's argument is never used.
Try changing the code in your service's delete method to be this:
return axios.delete(`http://localhost:8081/api/${idLowongan}`)

vuetify show-select in data-table not selecting items

So, I upgraded from vuetify 1.5 to latest (2.1xx) and get stuck on a few places.
I have a data-table where I want a "select all" checkbox in the header.
I added it with the "show-select" property and what I can see is that as the checkbox, when checked, actually puts all the items in the "selected" v-model.
My problem is that I want to have a template for item-props to customize the appearance of the rows and the checkbox that I bind to "props.selected" does not seem to work. If I check any checkbox on any row the item is not added to my "selected" v-model.
It is only if I use no template at all that I get it to work with the auto-generated checkboxes but this does not suffice for my current demands. In vuetify 1.5 I got it to work but I don't understand how to make it work in the new version.
<template>
<div>
<v-data-table
hide-default-footer
v-model="selected"
:sort-desc.sync="sortDescending"
:sort-by.sync="sortBy"
:headers="headers"
:items="cases"
item-key="id"
show-select
:items-per-page="itemsPerPage"
class="elevation-0">
<template v-slot:item="props">
<tr>
<td>
<v-checkbox v-model="props.selected" color="nordnetBlue" hide-details ></v-checkbox>
</td>
<td class="navigation-link" #click="goToCase(props.item)">{{ concatText( props.item.subject, 20) }}</td>
<td>{{ props.item.createdOn }}</td>
<td>{{ props.item.source }}</td>
<td>{{ !props.item.isSameQueue ? props.item.queueName : '' }}</td>
</tr>
</template>
</v-data-table>
<pre class="green--text">{{selected}}</pre>
</div>
</template>
I could not solve this so I followed a vuetify documentation example of how to customize the slot for each particular column.
So in my case, as you can see. three of the columns I just display the text as is and for two of them I do some modifying. So, I used a template for the two ones I wanted to edit.
Example:
template v-slot:item.Name="{ item }">
{{ item.Name }}
<v-tooltip bottom>
<template v-slot:activator="{on}">
<v-icon #click="openCustomer(item.Id)" class="clickable" small color="nordnetBlue" v-on="on">launch</v-icon>
</template>
Open in new window
</v-tooltip>
</template>

Angular 8 Pagination with Data from Database --

I am having a little trouble with this one.
Using the approach discussed in this -- https://jasonwatmore.com/post/2019/06/18/angular-8-simple-pagination-example
Use-case difference is, my data all comes from database. So I have had to use a model class and all. But, due to some problem, I am getting the same data [1st row from db] in all the rows. Let me post the code I used --
ANGULAR
method inside my component to get data from service class
newsTopics: NewsTopic[];
pageOfItems: Array<NewsTopic>;
getAllNewsTopics() {
this.userService.getAllTopics()
.subscribe((data: NewsTopic[]) => {
this.newsTopics = (data as NewsTopic[]).map((x, i) => ({ Id: (i + 1), TopicId: data[0].TopicId, TopicName: data[0].TopicName, TopicInfo: data[0].TopicInfo, IssueStartDate: data[0].IssueStartDate, IssueCloseDate: data[0].IssueCloseDate, NewsCategory_Id: 0 }));
})
}
my model class
export class NewsTopic
{
Id: number;
TopicId: string;
TopicName: string;
TopicInfo: string;
IssueStartDate: Date;
IssueCloseDate: Date;
NewsCategory_Id: number;
}
the method in service class itself
getAllTopics(){
var reqHeader = new HttpHeaders({ 'No-Auth': 'True' });
return this.http.get<NewsTopic[]>(this.rootUrl + '/api/NewsTopic/GetAllNewsTopics', { headers: reqHeader });
}
my html for showing the data and the pagination control
<div class="card-body">
<table class="table table-striped" id="newstopics_tbl">
<thead>
<tr style="background:linear-gradient(50deg, #d9fcfc, #dafbde)">
<th>Topic ID</th>
<th>Topic Name</th>
<th>Topic Info</th>
<th>Start Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let nt of pageOfItems">
<td><b>{{nt.TopicId}}</b></td>
<td>{{nt.TopicName}}</td>
<td>{{nt.TopicInfo}}</td>
<td>{{nt.IssueStartDate}}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer pb-0 pt-3" style="background:linear-gradient(50deg, #d9fcfc, #dafbde); margin-top:15px">
<jw-pagination [items]="newsTopics" (changePage)="onChangePage($event)"></jw-pagination>
</div>
My guess is, the problem lies in the getAllNewsTopics() method, where I am trying to fill and map the array of objects and assign to the variable. Something wrong there. If you see the original example from the link, they used a .fill(0) also. In my case I tried doing .fill(data[0]) however result is the same, ie. only first record, repeated multiple times.
What is the trick I am missing? Can someone just point me out.
Much needed, Thanks,
EDITS --
These are the changes->
getAllNewsTopics() {
var reqHeader = new HttpHeaders({ 'No-Auth': 'True' });
return this.http.get<NewsTopic[]>(this.rootUrl + '/api/NewsTopic/GetAllNewsTopics', { headers: reqHeader })
.subscribe((data: NewsTopic[]) => {
this.newsTopics = data;
});
}
and
<div class="card-body">
<table class="table table-striped" id="newstopics_tbl">
<thead>
<tr style="background:linear-gradient(50deg, #d9fcfc, #dafbde)">
<th>Topic ID</th>
<th>Topic Name</th>
<th>Topic Info</th>
<th>Start Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let nt of pageOfItems" style="cursor:pointer" (click)="NewsArticleAdd(nt)">
<td (click)=""><b>{{nt.TopicId}}</b></td>
<td style="color:mediumvioletred;" (click)="">{{nt.TopicName}}</td>
<td (click)="">{{nt.TopicInfo}}</td>
<td (click)="">{{nt.IssueStartDate}}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-footer pb-0 pt-3" style="background:linear-gradient(50deg, #d9fcfc, #dafbde); margin-top:15px">
<jw-pagination [items]="newsTopics" (changePage)="onChangePage($event)"></jw-pagination>
</div>
That does the trick. Works as expected,

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

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>

Resources