I'm using vue to take a returned object from an axios call and fill in an html table with it. I have the table exactly as I want but I'm wondering if there's a way (don't want to convert this whole thing to datatables) to make each header a filter for the table so that multiple columns can be filtered for the whole table. Basically, say the rows have items like 'Truck', 'Trailer' and 'Container' for the 'Resources' column. I'm thinking of a dropdown filter on the header of that column that would show rows for all resources or I could select 'Truck' so that only rows with 'Truck' show on the table.
Does that make sense? Is there an inherent way to do this with Vue?
<table style="width:100%; text-align:center;">
<thead>
<tr>
<th>Title</th>
<th>Resource</th>
<th>Location</th>
<th>Status</th>
</tr>
</thead>
<tbody v-for="dateEvent in dateEvents">
<tr>
<td v-if="dateEvent.id === '2'">{{ dateEvent.title }}</td>
<td v-if="dateEvent.id === '2'">{{ dateEvent.resource }}</td>
<td v-if="dateEvent.id === '2'">{{ dateEvent.location }}</td>
<td v-if="dateEvent.id === '2'">{{ dateEvent.status }}</td>
</tr>
</tbody>
</table>
data () {
return {
dateEvents: []
},
created() {
this.fetchItems();
},
methods: {
fetchItems() {
axios.get('/home/resource_items')
.then(response => {
// handle success
console.log(response.data)
this.dateEvents = response.data
})
.catch(function(error) {
console.log(error)
})
.finally(function() {})
}
}
You can use computed functionality to automatically calculate:
a filtered array of dateEvents to display in the table
an array of titles to display in the filter
an array of resources to display in the filter
an array of locations to display in the filter
an array of statuses to display in the filter
Here is an example:
...
<select v-model="filters.title">
<option v-for="title in titles" :value="title">{{ title }}</option>
</select>
<select v-model="filters.resource">
<option v-for="resource in resources" :value="resource">{{ resource }}</option>
</select>
<select v-model="filters.location">
<option v-for="location in locations" :value="location">{{ location }}</option>
</select>
<select v-model="filters.status">
<option v-for="status in statuses" :value="status">{{ status }}</option>
</select>
<button #click="reset">Reset</button>
...
<tbody v-for="dateEvent in filtered">
<tr>
<td>{{ dateEvent.title }}</td>
<td>{{ dateEvent.resource }}</td>
<td>{{ dateEvent.location }}</td>
<td>{{ dateEvent.status }}</td>
</tr>
</tbody>
...
...
data() {
return {
dateEvents: [],
filters: {
title: null,
resource: null,
location: null,
status: null,
},
};
},
computed() {
filtered() {
return this.dataEvents
.filter(dataEvent => !this.filters.title || dataEvent.title === this.filters.title),
.filter(dataEvent => !this.filters.resource || dataEvent.resource === this.filters.resource),
.filter(dataEvent => !this.filters.location || dataEvent.location === this.filters.location),
.filter(dataEvent => !this.filters.status || dataEvent.status === this.filters.status);
},
titles() {
return this.dataEvents
.map(dataEvent => dataEvent.title)
.filter((title, index, self) => self.indexOf(title) === index);
},
resources() {
return this.dataEvents
.map(dataEvent => dataEvent.resource)
.filter((resource, index, self) => self.indexOf(resource) === index);
},
locations() {
return this.dataEvents
.map(dataEvent => dataEvent.location)
.filter((location, index, self) => self.indexOf(location) === index);
},
statuses() {
return this.dataEvents
.map(dataEvent => dataEvent.status)
.filter((status, index, self) => self.indexOf(status) === index);
},
},
methods: {
reset() {
this.filters.title = null;
this.filters.resource = null;
this.filters.location = null;
this.filters.status = null;
},
},
...
Related
I am developing a Vue app to fetch orders from Woocommerce REST API. So i am having a HTML Table to fill the JSON Data. So when each order receive to Woocommerce, I will get it in my dashboard using "setInterval" for 60 seconds through refreshing data. Also the flags are set to notify new order in the HTML table using colors.
Apart from this I need to play a sound in the Vue app whenever the Woocommerce receives an order. How can I archive this as a stable function?
My JS code
var app = new Vue({
el: '#app',
data: {
orders: []
},
mounted: function() {
// Call the API the first time
this.refreshData()
// Then call the API every minute
this.setIntervalId = setInterval(this.refreshData, 60000)
},
beforeDestroy: function() {
// Stop refreshing data after the component is destroyed!
clearInterval(this.setIntervalId)
},
methods: {
refreshData () {
axios.get('https://mysite/wp-json/wc/v3/orders?per_page=20&consumer_key=key1&consumer_secret=key2')
.then(response => {
const previouslyFlaggedIds = this.orders.filter(x => x.is_printed).map(x => x.id);
this.orders = response.data.map(x => ({...x, is_printed: previouslyFlaggedIds.find(y => y === x.id) != null}));
console.log(response);
})
.catch(error => {
console.log(eror);
});
},
printBill(order) {
//change flag
order.is_printed = true;
}
}
})
HTML
<div class ="container mt-5" id="app">
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Order id</th>
<th scope="col">Name</th>
<th scope="col">Order Date</th>
<th scope="col">Phone</th>
<th scope="col">Address</th>
<th scope="col">Items</th>
<th scope="col">Total</th>
<th scope="col">Print</th>
</tr>
</thead>
<tbody>
<tr
v-for="(order, index) in orders"
:key="order.id"
:class="{highlight: !order.is_printed}"
>
<td>{{ order.id }}</td>
<td>{{ order.billing.first_name + " " +order.billing.last_name }}</td>
<td>{{ order.date_created }}</td>
<td>{{ order.billing.phone}}</td>
<td>{{ order.billing.address_1 + ", " + order.billing.address_2 + ", " + order.billing.city + order.billing.postcode }}</td>
<td>{{ order.line_items[0].name}} </td>
<td>{{ order.total}}</td>
<td><button class="btn btn-primary" #click="printBill(order)">Print</button>
</tr>
</tbody>
</table>
You can use audio tag for this.
<audio
ref="audio"
src="/media/cc0-audio/t-rex-roar.mp3">
</audio>
Then after you receive the new orders just play the audio
this.$refs.audio.play()
JSFiddle example
I'm trying to call my api to get the name of a tp but in the view I only see a [object promise] and in the browser console it looks like it's doing an infinite loop
html:
<table [dtOptions]="dtOptions" class="row-border hover" datatable>
<thead>
<tr>
<th>Date</th>
<th>Intitulé</th>
<th>Résultat</th>
<th>Coefficiant</th>
</tr>
</thead>
<tbody *ngIf="grades?.length != 0">
<tr *ngFor="let grade of grades">
<td>{{ formatDate(grade.Date) | date : 'MM/dd/yyyy hh:mm'}}</td>
<td>{{ getTpName(grade.tp_id) }}</td>
<td><b>{{ grade.Grade | number:'2.1-2' }}/20</b></td>
<td>{{ grade.coeff | number:'1.1'}}</td>
</tr>
</tbody>
<tbody *ngIf="grades?.length == 0">
<tr>
<td class="no-data-available" colspan="4">Aucune note enregistées</td>
</tr>
<tbody>
</table>
TS:
async getTpName(tp_id: any) {
return await this.apiService.getTpName(tp_id);
}
apiservice>getTpName
getTpName(tp_id) {
let url = `${this._tpUrl}/readName/${tp_id}`;
return new Promise((resolve, reject) => {
this.http.get(url, {headers: this.headers}).subscribe(
res => resolve(res),
error => reject(error)
)
});
}
Do you know why it happen and how to correct this ?
EDIT:
It will be good to move the api call from html to component controller.
ngOnInit() {
grades.forEach(grade => {
this.getTpName(grade.tp_id)
.pipe(take(1))
.subscribe(tpName => {
grade.tpName = tpName;
});
});
}
< td > {{ grade.tpName | json }}</td >
When I add new data it won't add to table
Code
HTML
<thead>
<tr>
<th class="text-center">ID</th>
<th class="text-center">Number</th>
<th class="text-center">Body</th>
<th class="text-center">Heading</th>
<th class="text-center">Book</th>
<th class="text-center">Chapter</th>
<th class="text-center">Actions</th>
</tr>
</thead>
<tbody>
<template v-for="verse in getVerses">
<tr v-bind:key="verse.id">
<td width="30" class="text-center">{{ verse.id }}</td>
<td class="text-center">{{ verse.number }}</td>
<td>{{ verse.body }}</td>
<td>{{ verse.heading }}</td>
<td class="text-center">{{ verse.book.name }}</td>
<td class="text-center">{{ verse.chapter.name }}</td>
<td class="text-center">
<button class="btn btn-sm btn-danger" type="button" #click="deleteVerse(verse.id)">Delete</button>
</td>
</tr>
</template>
</tbody>
</table>
Script
export default {
name: "adminVerses",
data() {
return {
isLoading: true,
type: '',
books: [],
errors: [],
pageTitle: 'Manage Verses',
getChapters: [],
getVerses: [],
isLoadingChapters: true,
isLoadingVerses: true,
verse: {
number: 1,
heading: '',
body: '',
book_id: '',
chapter_id: '',
}
}
},
methods: {
submit: function(e) {
axios.post('/api/saveVerse', this.verse)
.then(res => {
this.isLoading = false;
$('#exampleModal').modal('toggle');
this.getVerses.push( res.data.verse );
this.verse = {
number: parseInt(this.verse.number) + 1,
heading: '',
body: '',
book_id: this.verse.book_id,
chapter_id: this.verse.chapter_id,
};
})
.catch(error => {
// handle authentication and validation errors here
this.errors = error.response.data.errors
this.isLoading = false
})
},
}
}
Any idea?
Update
by adding
if ($.fn.dataTable.isDataTable('#verses')) {
$('#verses').DataTable().clear().destroy(); //This will destroy datatable
};
this.getVerses.push( res.data.verse );
now i can get my newly added data into my table but i also will lose ability of paging and search, etc.
ideas?
You are using this to refer to an object, so you are limited to Axios scope. Instead you can use a variable to store a reference to main object, in your case adminVerses and then use $data to set or fetch the data attributes.
Example :
let vm = this;
axios({
...
}).then((res) => {
vm.$data.getVerses.push( res.data.verse );
});
open your vue devtools and check if getVerses gets the right data
The push on the array isn't responsive, so the vue doesn't know it needs to update the view. The array setter is responsive, so:
this.getVerses = this.getVerses.concat(res.data.verse)
will do the trick.
I am new to Angular, maybe is a fool question.
I have a result from my AngularJs and I return an Array of values:
This is the code:
$scope.searchTitle = function () {
$http.post('/svn/cms2/branches/create_function/cms/includes/find.php', {
name_title: $scope.title
})
.success(function (result) {
console.log(result);
$scope.resultName = result;
$scope.ok = "we post";
})
.error(function (data, status) {
console.log(data);
});
};
And now i have the resultName in the html and i can see the result if i do this:
<p>{{ resultName[0].article_titile }}</p>
Question:
I want to display all the array. How can I display all?
P.S.:
I use this and it is not work
<tr ng-repeat="i in [3] | toRange" >
<td>{{ resultName[i].article_titile }}</td>
</tr>
But is not working
You need to use an iterator variable (e.g. result) with your resultName array in your ng-repeat:
<tr ng-repeat="result in resultName | toRange" >
<td>{{ result.article_titile }}</td>
</tr>
I am attempting to display a JSON response from PHP. I was pointed in the direction of the VueJS resource plugin. Unfortunately, the examples it gives are vague at best.
Is anyone able to provide a simple example of how to display the return JSON object in a list?
HTML:
<table id="list-items">
<tr v-for="item in items">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
</table>
JS:
new Vue({
el: '#list-items',
data: {
items: []
},
ready: function() {
this.items = this.getItems();
},
methods: {
getItems: function() {
this.$http.get('items.php', function(data){
this.items = data;
});
}
}
});
items.php must return a JSON encoded array like this:
[{id: 1, name: 'foo'},{id: 2, name: 'bar'}]
In vue 1.0.1 you can use v-for instead of v-repeat like this:
<table id="list-items">
<tr v-for="item in items">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
</table>
I think you are looking for
{{ $data | json }}