I have the following computed function so filter my houses based on a search input field. This works.
computed: {
filtered: function() {
var self = this;
let searchTerm = (this.search || "").toLowerCase()
if(this.houses) {
return this.houses.filter(function(item) {
let city = (item.city || "").toLowerCase()
let street = (item.street || "").toLowerCase()
return city.indexOf(searchTerm) > -1 || street.indexOf(searchTerm) > -1;
})
}
}
}
But how to implement ordering on City and Street also? Both asc and desc.
This is the table:
<input type="search" v-model="search" placeholder="Search for City OR Street" />
<table>
<thead>
<tr>
<th #click="sortByStreet()">Street</th>
<th #click="sortByCity()">City</th>
</tr>
</thead>
<tbody>
<tr v-for="house in filtered">
<td>{{ house.street }}</td>
<td>{{ house.city }}</td>
</tr>
</tbody>
</table>
How to fix it with the functions sortByStreet() and sortByCity()? Combined with the filter.
Your clicks should set a variable, call it sortBy, that the computed uses to determine how it sorts its results. When the variable changes, the computed will recompute.
new Vue({
el: '#app',
data: {
search: 'Z-town',
reverse: false,
houses: [{
street: 'First',
city: 'Z-town'
},
{
street: 'Second',
city: 'A-town'
},
{
street: 'First',
city: 'A-town'
},
{
street: 'Second',
city: 'Z-town'
}
],
sortBy: 'street'
},
computed: {
filtered: function() {
const result = this.houses
.filter(entry => [entry.street, entry.city].find(x => x === this.search))
.sort((a, b) =>
a[this.sortBy] < b[this.sortBy] ? -1 : a[this.sortBy] !== b[this.sortBy]
);
return this.reverse ? result.reverse() : result;
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<input type="search" v-model="search" placeholder="Search for City OR Street" />
<input type="checkbox" v-model="reverse"> Descending
<table>
<thead>
<tr>
<th #click="() => sortBy = 'street'">Street</th>
<th #click="() => sortBy = 'city'">City</th>
</tr>
</thead>
<tbody>
<tr v-for="house in filtered">
<td>{{ house.street }}</td>
<td>{{ house.city }}</td>
</tr>
</tbody>
</table>
</div>
Related
Guys I'm starting with Vue and I'm having a little difficulty. In the image below I have a table with some items and when I will increase the amount of the item Orange for example is increased all other items, how to fix it?
enter image description here
My code
new Vue({
el: '#app',
data() {
return {
quantity: 1,
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00" },
{ Code: 2, Name: 'Abacate', Price: "50.00" },
{ Code: 3, Name: 'Morango', Price: "60.00" },
{ Code: 4, Name: 'Maçã', Price: "17.00" },
{ Code: 5, Name: 'Laranja', Price: "30.00" }
]
}
},
methods: {
add() {
this.quantity++
},
remove() {
if(this.quantity === 0) {
this.quantity = 0
} else {
this.quantity--
}
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove">-</button>
<input type="text" :value="quantity">
<button #click="add">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
You should just need to have a quantity on each item in your list. You'd then pass the relevant item to add or remove.
new Vue({
el: '#app',
data() {
return {
fruits: [
{ Code: 1, Name: 'Abacaxi', Price: "50.00", quantity: 1 },
{ Code: 2, Name: 'Abacate', Price: "50.00", quantity: 1 },
{ Code: 3, Name: 'Morango', Price: "60.00", quantity: 1 },
{ Code: 4, Name: 'Maçã', Price: "17.00", quantity: 1 },
{ Code: 5, Name: 'Laranja', Price: "30.00", quantity: 1 }
]
}
},
methods: {
add(fruit) {
fruit.quantity++
},
remove(fruit) {
if(fruit.quantity !== 0) {
fruit.quantity--
}
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<template>
<div class="user-list">
<table>
<thead>
<tr>
<th>#Code</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr v-for="fruit in fruits" :key="fruit.Code">
<td>
<button #click="remove(fruit)">-</button>
<input type="text" v-model.number="fruit.quantity">
<button #click="add(fruit)">+</button>
</td>
<td>{{ fruit.Name }}</td>
<td>{{ fruit.Price }}</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
I've also switched :value to v-model.number, which seems more likely to be what you'd want though it's not directly related to the problem mentioned in the question.
I have the following construction:
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Наименование</th>
<th scope="col">API ключ</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="adv in advertisers">
<th scope="row">{{ adv.id }}</th>
<td>{{ adv.name }}</td>
<td>{{ adv.api_key }}</td>
<td>
<advertiser-delete-component :advertiser-id="adv.id"></advertiser-delete-component>
<advertiser-edit-component :advertiser-id="adv.id" :advertiser-name="adv.name"></advertiser-edit-component>
</td>
</tr>
</tbody>
</table>
Array "advertisers" keeps data from the server. Data is correct. But I see that all 'advertiser-delete-component' and 'advertiser-edit-component' have the first item of advertisers array in component props.
Here is the code of advertiser-edit-component:
<script>
import { EventBus } from '../../app.js';
export default {
mounted() {
},
props: ['advertiserId', 'advertiserName'],
data: function() {
return {
formFields: {
advertiserName: '',
advertiserId: this.advertiserId,
},
errors: []
}
},
methods: {
submit: function (e) {
window.axios.post('/advertiser/edit', this.formFields).then(response => {
this.formFields.advertiserName = '';
EventBus.$emit('reloadAdvertisersTable');
$('#addAdvertiser').modal('hide');
}).catch(error => {
if (error.response.status === 422) {
this.errors = error.response.data.errors || [];
}
});
}
}
}
The props props: ['advertiserId', 'advertiserName'] are the same for each component call with my code. I want them to be dynamic where they take corresponding elements from the array as the loop goes through it one by one.
What did I do wrong?
UPDATE:
Here is full code of table component:
<template>
<div>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Наименование</th>
<th scope="col">API ключ</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="adv in advertisers">
<th scope="row">{{ adv.id }}</th>
<td>{{ adv.name }}</td>
<td>{{ adv.api_key }}</td>
<td>
<advertiser-delete-component :advertiser-id="adv.id"></advertiser-delete-component>
<advertiser-edit-component :advertiser-id="adv.id"
:advertiser-name="adv.name"></advertiser-edit-component>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import {EventBus} from '../../app.js';
export default {
mounted() {
this.getAdvertisersTable();
EventBus.$on('reloadAdvertisersTable', this.getAdvertisersTable)
},
props: ['totalCountOfAdvertisers'],
data: function () {
return {
advertisers: [],
}
},
methods: {
getAdvertisersTable: function () {
window.axios.get('/advertisers/all')
.then(r => {
this.advertisers = r.data.data;
})
.catch(e => {
console.log(e.response.data.errors);
})
}
}
}
</script>
I think formFields should be array of objects like:
formFields: [{
advertiserName: '',
advertiserId: this.advertiserId,
}],
I've some problems with list rendering and filtering the data with computed properties
Instead of hardcoded row.age value, I'd like to use filterKey to filter row.age.
How to archieve this? I just don't get it.
Here's my example:
template:
<button type="button" class="btn btn-t1-secondary" v-on: click="filterKey = '15'">11</button>
<button type="button" class="btn btn-t1-secondary" v-on: click="filterKey = '30'">8</button>
<table>
<thead>
<tr>
<th>Category</th>
<th>Age</th>
<th>Food</th>
</tr>
</thead>
<tbody>
<tr v-for="row in filteredCategory">
<td>{{ row.category }}</td>
<td>{{ row.age }}</td>
<td>{{ row.food }}</td>
</tr>
</tbody>
</table>
JavaScript:
<script>
var app = new Vue({
el: '#app',
data: {
filterKey: '',
filterCategory: '',
dataToFilter: [
{
category: 'dog',
age: '11',
food: 'bone'
},
{
category: 'cat',
age: '8',
food: 'fish'
}
//etc.
]
},
computed: {
filteredCategory() {
return this.dataToFilter.filter(function (row) {
return row.category === 'dog'
})
.filter(function (row) {
console.log(this.filterKey)
return row.age === '15'
})
},
}
})
</script>
Solution
As #Sadraque_Santos suggested, I used arrow functions.
Code
filteredCategory() {
return this.dataToFilter.filter( r => r.category === 'dog' && r.age === this.filterKey);
}
Also, I have to support IE11 so I just use Babel to compile the code for me.
To have access to this inside a filter, map or another useful method you must learn about arrow functions, they allow you to create a function without the this bound to that object, so instead of using:
filteredCategory () {
return this.dataToFilter.filter(function (row) {
return row.category === 'dog'
})
.filter(function (row) {
console.log(this.filterKey)
return row.age === '15'
})
}
Your code should be like this:
filteredCategory () {
return this.dataToFilter
.filter((row) => row.category === this.filterCategory)
.filter((row) => row.age === this.filterKey)
}
im pretty new in vue js, im using it to show some data in a table, it is working fine, but... its showing the properties name on the result, can you please help me to verify this?
Admin.html
window.onload = function () {
Vue.component('todo-item', {
props: ['todo']
});
var app1 = new Vue({
el: '#app-1',
data: {
//default row to avoid errors
theUserList: [
{ id: 0, email: 'EMAIL', username: 'USER NAME', status: 'STATUS', gender: 'GENDER', registrationdate: 'REGISTRATION DATE', theurl: 'MODIFY' }
],
currentPage:0
},
methods: {
addData: function () {
if (rawData && rawData != undefined && rawData != null) {
for (y = 0; y < rawData.length; y++) {
this.theUserList.push({ id: rawData[y][0], email: rawData[y][1], username: rawData[y][2], status: rawData[y][3], gender: rawData[y][4], registrationdate: rawData[y][5], theurl: rawData[y][6] });
}
this.theUserList.splice(0, 1);
}
}
}
});
app1.addData();
}
<div id="app-1">
<table class="responsive-card-table unstriped">
<tr><th>Email</th><th>User Name</th><th>Status</th><th>Gender</th><th>Registration Date</th><th>Modify</th></tr>
<tr v-for="item in theUserList"
v-bind:class="{'':true, 'page-item-active':(item.id === currentPage)}"
v-bind:tr="item"
v-bind:key="item.id">
<td>{{ item.email.email}}</td><td>{{item.username}} </td><td>{{ item.status }}</td><td>{{ item.gender}} </td><td> {{item.registrationdate }} </td><td>{{ item.theurl }}</td></tr>
</table>
</div>
the output:
//TH
**Email User Name Status Gender Registration Date Modify Url**
//ROWS
*email:* admin#admin.com *username:* admin *status:* True *gender:* True *registrationdate:* 7-5-2018 *theurl:* theurl
If you want to use your data from rawData, wherever it comes from (props, data or computed property), you need to bind this to use it inside your Vue instance.
To display your data with the addData method when the Vue instance is created, you can return the method inside a created or mounted hook (depends on when your data is loaded).
Example:
new Vue({
el: "#app",
data: {
rawData: [
[1, "john#test.com", "John", "false", "male", "28/02/2018", "http://example.com"],
[2, "jane#test.com", "Jane", "true", "female", "19/02/2018", "http://example.com"]
],
theUserList: [
{ id: 0, email: 'EMAIL', username: 'USER NAME', status: 'STATUS', gender: 'GENDER', registrationdate: 'REGISTRATION DATE', theurl: 'MODIFY' }
],
currentPage:0
},
methods: {
addData: function () {
for (let y in this.rawData) {
this.theUserList.push({ id: this.rawData[y][0], email: this.rawData[y][1], username: this.rawData[y][2], status: this.rawData[y][3], gender: this.rawData[y][4], registrationdate: this.rawData[y][5], theurl: this.rawData[y][6] });
}
this.theUserList.splice(0, 1);
}
},
mounted() {
return this.addData()
}
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<table class="table">
<thead>
<tr><th>Email</th><th>User Name</th><th>Status</th><th>Gender</th><th>Registration Date</th><th>Modify</th></tr>
</thead>
<tbody>
<tr v-for="item in theUserList" :key="item.id">
<td>{{ item.email}}</td>
<td>{{item.username}} </td>
<td>{{ item.status }}</td>
<td>{{ item.gender}} </td>
<td> {{item.registrationdate }} </td>
<td>{{ item.theurl }}</td>
</tr>
</tbody>
</table>
</div>
someone posted the url
https://jsfiddle.net/1L00jj8z/
based in that, i modified the code to this:
JS
var vueApp = new Vue({
el: "#app",
data() {
return {
theUserList: [],
}
},
created() {
this.addUser();
},
methods: {
addUser() {
return this.theUserList.push({
id: + new Date,
email: '',
username: '',
status: '',
gender: '',
registrationdate: '',
theurl: ''
});
},
addRawUsers() {
if (rawData && rawData != undefined && rawData != null) {
for (y = 0; y < rawData.length; y++) {
this.theUserList.push({
id: '' + rawData[y][0],
email: '' + rawData[y][1],
username: '' + rawData[y][2],
status: '' + rawData[y][3],
gender: '' + rawData[y][4],
registrationdate: '' + rawData[y][5],
theurl: '' + rawData[y][6]
});
}
this.theUserList.splice(0, 1);
}
},
deleteUser(item) {
this.theUserList = this.theUserList.filter(user => user.id !== item.id)
}
}
});
vueApp.addRawUsers();
}
HTML
<div id="app">
<table class="responsive-card-table unstriped">
<tr>
<th>Email</th>
<th>User Name</th>
<th>Status</th>
<th>Gender</th>
<th>Registration Date</th>
<th>URL</th>
<th></th>
</tr>
<tr v-for="item in theUserList" :key="item.id">
<td><input type="text" class="input" v-model="item.email" /></td>
<td><input type="text" class="input" v-model="item.username" /> </td>
<td><input type="text" class="input" v-model="item.status" /></td>
<td><input type="text" class="input" v-model="item.gender" /> </td>
<td><input type="text" class="input" v-model="item.registrationdate" /> </td>
<td><input type="text" class="input" v-model="item.theurl" /></td>
<td><div v-on:click="deleteUser(item)">x</div></td>
</tr>
</table>
thank you all!
How can I filter by searching in multiple search keys?
I'm trying something like this, but (of course) it won't work:
<tr v-repeat="questions | filterBy search in 'reference','user.name','shop.shopName'">
The filterBy custom filter is not documented AFAIK, but you can use a method to make your own filter:
var demo = new Vue({
el: '#demo',
data: {
search: 're',
people: [
{name: 'Koos', age: 30, eyes:'red'},
{name: 'Gert', age: 20, eyes:'blue'},
{name: 'Pieter', age: 12, eyes:'green'},
{name: 'Dawid', age: 67, eyes:'dark green'},
{name: 'Johan', age: 15, eyes:'purple'},
{name: 'Hans', age: 12, eyes:'pink'}
]
},
methods: {
customFilter: function(person) {
return person.name.indexOf(this.search) != -1
|| person.eyes.indexOf(this.search) != -1
;
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="demo">
<input type="text" class="form-control" v-model="search"/>
<br/>
<table class="table">
<thead>
<tr>
<th>name</th>
<th>eyes</th>
<th>age</th>
</tr>
</thead>
<tr v-for="person in people | filterBy customFilter">
<td>{{ person.name }}</td>
<td>{{ person.eyes }}</td>
<td>{{ person.age }}</td>
</tr>
</table>
</div>
This problem resolve with "Computed Properties":
var app = new Vue({
el: '#demo',
data: {
search: '',
people: [
{name: 'Koos', age: 30, eyes:'red'},
{name: 'Gert', age: 20, eyes:'blue'},
{name: 'Pieter', age: 12, eyes:'green'},
{name: 'Dawid', age: 67, eyes:'dark green'},
{name: 'Johan', age: 15, eyes:'purple'},
{name: 'Hans', age: 12, eyes:'pink'}
]
},
computed: {
filteredPerson: function () {
var self = this;
return this.people.filter(function (person) {
return person.name.toLowerCase().indexOf(self.search.toLowerCase()) >= 0
|| person.eyes.toLowerCase().indexOf(self.search.toLowerCase()) >= 0;
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="demo">
<input type="text" class="form-control" v-model="search"/>
<br/>
<table class="table">
<thead>
<tr>
<th>name</th>
<th>eyes</th>
<th>age</th>
</tr>
</thead>
<tr v-for="person in filteredPerson">
<td>{{ person.name }}</td>
<td>{{ person.eyes }}</td>
<td>{{ person.age }}</td>
</tr>
</table>
</div>
Since Vue.js version 0.12.11 this is possible with:
<li v-repeat="user in users | filterBy searchText in 'name' 'phone'"></li>
Make sure to checkout the official guide on this: http://vuejs.org/api/#orderBy
computed: {
filteredItems() {
var result = this.accountList;
if (this.flt.userName != undefined) {
result = result.filter(
item =>
item.userName.toLowerCase().includes(
this.flt.userName.toLowerCase()
)
);
}
if (this.flt.tenantId != undefined) {
result = result.filter(
item =>
item.tenantId.includes(
this.flt.tenantId
)
);
}
if (this.flt.providerId != undefined) {
result = result.filter(
item =>
item.providerId.includes(
this.flt.providerId
)
);
}
return result;
}
},