If I have code like the code below in my vue.js, upon clicking a button, how can I only display the array item I clicked ( for e.g, Donnie) and hide all of the rest? (Joanne, Peter e.t.c), then when you click the only displayed element again, make all of the other array elements display again?
const app = new Vue({
el: '#app',
data: {
keyword: '',
friends: [
{
name: "Donnie",
age: "20"
},
{
name: "Joanne",
age:"19",
},
{
name: "David",
age: "26"
},
{
name: "Peter",
age: "23"
},
{
name: "John",
age: "29"
},
{
name: "Jason",
age: "19"
},
],
},
computed: {
filteredList() {
return this.friends.filter((friend) => {
return friend.name.toLowerCase().includes(this.keyword) + friend.age.includes(this.keyword) + friend.name.includes(this.keyword);
});
}
},
methods:{
exclude(friend) {
console.log(!friend.name);
},
}
})
HTML
<div v-for="friend in filteredList" class="card" #click="exclude(friend)">
{{friend.name}} - {{friend.age}}
</div>
You should be able to add an identity check to your filter expression if an item has been clicked.
Start by adding a property to store the clicked friend. I'll call mine selected
data {
selected: null,
keyword: '',
//etc
}
Then in your exclude method
exclude (friend) {
this.selected = this.selected ? null : friend
}
now your computed property can filter the list based on the selected friend first, then fall back to the keyword match
filteredList () {
return this.selected ? [this.selected] : this.friends.filter(friend => {
let search = this.keyword.trim().toLowerCase()
return friend.name.toLowerCase().includes(search) || friend.age.includes(search)
})
}
I think that's what you're looking for:
const app = new Vue({
el: '#app',
data: {
keyword: '',
friends: [
{
name: "Donnie",
age: "20"
},
{
name: "Joanne",
age:"19",
},
{
name: "David",
age: "26"
},
{
name: "Peter",
age: "23"
},
{
name: "John",
age: "29"
},
{
name: "Jason",
age: "19"
},
],
selected: null
},
computed: {
filteredList() {
if (!this.selected) {
return this.friends.filter((friend) => {
return friend.name.toLowerCase().includes(this.keyword) + friend.age.includes(this.keyword) + friend.name.includes(this.keyword);
});
} else {
return [this.selected];
}
},
},
methods:{
exclude(friend) {
if(!this.selected) {
this.selected = friend;
} else {
this.selected = null;
}
},
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<div v-for="friend in filteredList" class="card" #click="exclude(friend)">
{{friend.name}} - {{friend.age}}
</div>
</div>
The trick here is that the selected data property store the friend and also doubles as a checker if there's a friend, so if not, show all, if is, show only that one.
Related
I have one Amount column in my table and I want to calculate total debit, total credit, total remaining amount by chnage in status of dropdown debit and credit.
if dropdown selection is debit then "Remaining=Amount-current Amount" and
if dropdown selection is credit then add amount in remaining balance, This Is My Code. Please help I'm new in Vuejs
<script>
import Breadcrumb from "primevue/breadcrumb";
import Button from "primevue/button";
import InputText from "primevue/inputtext";
import Calendar from "primevue/calendar";
import Dropdown from "primevue/dropdown";
import InputNumber from "primevue/inputnumber";
import { ref, reactive } from "vue";
import { computed } from "#vue/reactivity";
export default {
name: "CashPayementVoucher",
components: {
Button,
InputText,
Calendar,
Dropdown,
InputNumber,
Breadcrumb,
},
setup() {
const home = ref({ icon: "pi pi-home", to: "/" });
const items = ref([
{ label: "Vouchers" },
{ label: "Cash Payement Voucher" },
]);
const accountsData = ref([
{ name: "0987-12345678-1", value: "0987-12345678-1" },
{ name: "0987-12345678-2", value: "0987-12345678-2" },
{ name: "0987-12345678-3", value: "0987-12345678-3" },
{ name: "0987-12345678-4", value: "0987-12345678-4" },
{ name: "0987-12345678-5", value: "0987-12345678-5" },
]);
const projectsData = ref([
{ name: "Blue World City", value: "Blue World City" },
{ name: "Estate 92", value: "Estate 92" },
{ name: "Atlantics City", value: "Atlantics City" },
{ name: "Park View City", value: "Park View City" },
{ name: "Bahria Town", value: "Bahria Town" },
]);
const usersData = ref([
{ name: "Ali Suleman", value: "Ali Suleman" },
{ name: "Muhammad Khan", value: "Muhammad Khan" },
{ name: "Sheraz Ahemad", value: "Sheraz Ahemad" },
{ name: "Mehbob Sultan", value: "Mehboob Sultan" },
{ name: "Usama Javeed", value: "Usama javeed" },
{ name: "Shoaib Khan", value: "Shoaib Khang" },
]);
const payementType = ref([
{ name: "Debit", value: 1 },
{ name: "Credit", value: 0 },
]);
const invoice = reactive({
account: "",
date: "",
projects: "",
payeeName: "",
amount: 0,
details: [
{
account: "",
name: "",
description: "",
debit_credit: 1,
amount: 0,
},
],
totalCredit: 0,
totalDebit: 0,
difference: 0,
});
const addnewRow = () => {
invoice.details.push({
account: "",
name: "",
description: "",
debit_credit: "",
amount: 0,
});
};
const removeRow = (index) => {
invoice.details.splice(index, 1);
};
const postData = () => {
console.log("Hello I'm Here 'Cash Payement Voucher'", invoice);
};
const remaining =computed(() => {
return (
invoice.amount +
invoice.details.reduce(function (prevTotal, detail) {
let temp = detail.debit_credit > 0 ? detail.amount * -1 : detail.amount * 1;
return +prevTotal + temp;
}, 0)
);
});
return {
home,
items,
accountsData,
projectsData,
usersData,
payementType,
invoice,
addnewRow,
removeRow,
postData,
remaining
};
},
};
</script>
Image Link
https://i.stack.imgur.com/zkdOZ.png
Please on the next question insert only important code for your problem it's easier to analyze code. To solve your problem create computed property which will return data depending on dropdown choose.
computed() {
calculateValue() {
if (this.details[0].debit_credit === 'Debit') {
return //enter your equation for debit option i can't find currentAmount data
else if (this.details[0].debit_credit === 'Credit') {
return //enter your equation for credit option
}
return null
}
}
}
Then you can display calculateValue anywhere in HTML code:
<template>
<div> Balance: {{calculateValue}} </div>
</template>
So I have an array of objects that looks like this :
let medicines = [
{
id:3340,
name:nutraplus,
description:"some medicine",
ingredients: [{
ingredient:"glycerol"
},
{
ingredient:"Morphine"
}
]
},
{
id:3320,
name:Panadol,
description:"tablet",
ingredients: [{
ingredient:"Paracetamol"
},
{
ingredient:"Some stuff"
}
]
}
]
I want to to be able to filter by name and by ingredient name I have acheived the former by doing this :
computed: {
medicines() {
return this.$store.state.medicines.filter(med => {
//this.search is the what comes after typing in search bar
return med.name.toLowerCase().includes(this.search.toLowerCase())
})
},
}
Its vue.js so the computed() stuff anyways this works perfectly when searching by name however i also want to be able to search by ingredients from the same search bar. I tried something like this :
edicines() {
return this.$store.state.medicines.filter(med => {
return med.name.toLowerCase().includes(this.search.toLowerCase()) || med.ingredients.map(ing=>{
ing.ingredient.name.toLowerCase().includes(this.search.toLower)
})
})
}
But it didn't work. Any ideas on how to get this working? Thank you for your time.
Haven't used vue in the example, you just need to extract the logic behind the filtering that I have done (Simple JS filtering)
As example -
Try searching for 'Para' - It must return the entries with name/ingredient containing Para
Try searching for 'stuff' - It should return two entries (since both medicine in that array consist of 'some stuff' as ingredient)
let medicines = [{
id: 3340,
name: 'nutraplus',
description: "some medicine",
ingredients: [{
ingredient: "glycerol"
},
{
ingredient: "Morphine"
},
{
ingredient: "Some stuff"
}
]
},
{
id: 3320,
name: 'Panadol',
description: "tablet",
ingredients: [{
ingredient: "Paracetamol"
},
{
ingredient: "Some stuff"
}
]
},
{
id: 3311,
name: 'Amazin',
description: "tablet"
}
];
const form = document.querySelector('form')
form.addEventListener('submit', (e) => {
e.preventDefault();
const searchValue = form.searchText.value.toLowerCase();
const matchValue = medicines.filter(medicine => {
return medicine.name.toLowerCase().includes(searchValue) || (medicine.ingredients ? medicine.ingredients.filter(ingredientObj => {
return ingredientObj.ingredient.toLowerCase().includes(searchValue);
}).length > 0 : false);
});
document.querySelector('.result').textContent = JSON.stringify(matchValue, null, 4);
});
pre {
background: #c5c5c5;
}
<form>
<label for="searchText"></label>
<input type="text" id="searchText" name="searchText">
<button>Search</button>
</form>
<pre class='result'></pre>
This should work.
let medicines = [
{
id:3340,
name:"nutraplus",
description:"some medicine",
ingredients: [{
ingredient:"glycerol"
},
{
ingredient:"Morphine"
}
]
},
{
id:3320,
name:"Panadol",
description:"tablet",
ingredients: [{
ingredient:"Paracetamol"
},
{
ingredient:"Some stuff"
}
]
}
];
const searchPhrase = "Paracetamol";
const filteredByName = medicines.filter((medicine) => {
return medicine.name.toLowerCase() === searchPhrase.toLowerCase();
});
const filteredByIngredient = medicines.filter((medicine) => {
return medicine.ingredients.some((item) => item.ingredient.toLowerCase() === searchPhrase.toLowerCase());
})
const result = [...filteredByName, ...filteredByIngredient];
console.log(result)
I can't understand why do filter returns an empty array when I try to loop through the object's array property.
Though, When I try to do console.log(this.users) inside the getFilteredUsers method, I can see the filter method inside its proto...
var userService = {
currentFilter: "active",
users: [
{ name: "Alex", status: "active" },
{ name: "Nick", status: "deleted" }
],
getFilteredUsers: function() {
// console.log(this.users);
return this.users.filter(function(user) {
return user.status === this.currentFilter;
});
}
};
console.log(userService.getFilteredUsers()); // []
It is because of value of
this
in filter callback. Use arrow function to get correct value for this
var userService = {
currentFilter: "active",
users: [
{ name: "Alex", status: "active" },
{ name: "Nick", status: "deleted" }
],
getFilteredUsers: function() {
// console.log(this.users);
return this.users.filter((user)=> {
return user.status === this.currentFilter;
});
}
};
console.log(userService.getFilteredUsers()); // []
The problem is with the scope of this object. It changes inside the callback function of filter(). There are two ways you can try:
Create a new filter variable in your function before filter callback function, something like:
var userService = {
currentFilter: "active",
users: [{
name: "Alex",
status: "active"
},
{
name: "Nick",
status: "deleted"
}
],
getFilteredUsers: function() {
const currentStatus = this.currentFilter;
return this.users.filter(function(user) {
return user.status === currentStatus;
});
}
};
console.log(userService.getFilteredUsers()); //[ { name: 'Alex', status: 'active' } ]
Use es6 arrow function:
var userService = {
currentFilter: "active",
users: [{
name: "Alex",
status: "active"
},
{
name: "Nick",
status: "deleted"
}
],
getFilteredUsers: function() {
return this.users.filter(({
status
}) => status === this.currentFilter);
}
};
console.log(userService.getFilteredUsers()); // [ { name: 'Alex', status: 'active' } ]
Hope this helps :)
i have next example https://codepen.io/mihail-kuznecow/pen/mjoYzz
It's animejs library, https://github.com/juliangarnier/anime.
Codesnippet example:
const members = [{
name: "Вася Пупки"
}, {
name: "Дмитрий Васильев"
}, {
name: "Анатолий Вассерман"
}, {
name: "Петросян Вазгенович"
}, {
name: "Гоша Вазгенович"
}, {
name: "Миша Вазгенович"
}, {
name: "Саша Вазгенович"
}, {
name: "Анатолий Вазгенович"
}, {
name: "Энакентий Вазгенович"
}, {
name: "Динис Вазгенович"
}, {
name: "Иван Вазгенович"
}, {
name: "Руслан Вазгенович"
}, {
name: "Богдан Вазгенович"
}, {
name: "Костян Вазгенович"
}];
window.onload = function() {
const button = document.getElementById('start');
if(button){
button.addEventListener('click', () => rollNames(document.querySelector('.name'), members));
}
function rollNames(domNode, names) {
const animatedName = {value: 0};
let name;
if (domNode) {
anime({
targets: [animatedName, domNode],
value: names.length - 1,
round: 1,
easing: 'easeInOutCirc',
duration: 5000,
update: function(a) {
if(name != names[animatedName.value].name) {
a.animatables[1].target.style.opacity = 0;
}else{
a.animatables[1].target.style.opacity = 1;
}
domNode.innerText = names[animatedName.value].name;
name = names[animatedName.value].name;
}
});
//return anime.finished;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="test">
<div class="name">
Hello!
</div>
</div>
<button id="start">Start roll</button>
You can see, name change with flash, i would like to this flash was changed smoothly for each name.
Maybe I should take callbacks or timeline, but all my attempts are not successful.
How i can do it?
This took me a while, but I think I finally have something that you were looking for. You will have to mess around with it a little bit more to get it perfect but I think it's pretty close to what you were asking. The few things I changed was the easing to linear and the duration to 14000 (14 names, 1 name per second). I then used jquery's animate to have a sort of fade in/fade out for each name. You will have to tweak the timing a little but I think basically it is a good example of what you were asking (I hope). Also, here is the modified codepen: https://codepen.io/anon/pen/ZjZYWM
const members = [{
name: "Вася Пупки"
}, {
name: "Дмитрий Васильев"
}, {
name: "Анатолий Вассерман"
}, {
name: "Петросян Вазгенович"
}, {
name: "Гоша Вазгенович"
}, {
name: "Миша Вазгенович"
}, {
name: "Саша Вазгенович"
}, {
name: "Анатолий Вазгенович"
}, {
name: "Энакентий Вазгенович"
}, {
name: "Динис Вазгенович"
}, {
name: "Иван Вазгенович"
}, {
name: "Руслан Вазгенович"
}, {
name: "Богдан Вазгенович"
}, {
name: "Костян Вазгенович"
}];
window.onload = function() {
const button = document.getElementById('start');
if(button){
button.addEventListener('click', () => rollNames(document.querySelector('.name'), members));
}
function rollNames(domNode, names) {
const animatedName = {value: 0};
let name;
if (domNode) {
anime({
targets: [animatedName, domNode],
value: names.length - 1,
round: 1,
easing: 'linear',
duration: 14000,
update: function(a) {
if(name != names[animatedName.value].name) {
$(a.animatables[1].target).animate({opacity:'+=1'}, 500)
if(a.animatables[1].target.style.opacity > 0 ){
$(a.animatables[1].target).animate({opacity:'-=1'}, 500) //fades out
}
else{
$(a.animatables[1].target).animate({opacity:'+=1'}, 500)//fades in
$(a.animatables[1].target).animate({opacity:'-=1'}, 500)//fades out
}
}
else{
}
domNode.innerText = names[animatedName.value].name;
name = names[animatedName.value].name;
}
});
//return anime.finished;
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test">
<div class="name">
</div>
</div>
<button id="start">Start roll</button>
I have a Vue file that looks like so :
import store from '#/store'
export default{
name: 'myList',
data: () => ({
show: true,
listContent: [{
name: '1',
icon: 'person',
value: function () {
return store.state.myStore.settings.one
}
}, {
name: '2',
icon: 'person',
value: function () {
return store.state.myStore.settings.two
}
}, {
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
]
})
}
The part that's not working is getting the 'value' from the 'listContent'.
{
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
In my code, I have imported the view as if I were to put :
this.$store.state.myStore.settings.one
Inside the value function, 'this' would refer to the object
{
name: '3',
icon: 'person',
value: function () {
return store.state.myStore.settings.three
}
}
And I wouldnt be able to get the store. However, my code still doesn't work. I need to get access to the store inside the listContent.
The list is rendered like so :
<v-data-table :items="listContent" hide-actions hide-headers>
<template slot="items" slot-scope="props">
<td>{{ props.item.name }}</td>
<td class="text-xs-right" v-text="props.item.value()"> </td>
</template>
</v-data-table>
Either I have referenced the store incorrectly, or the template is incorrect. Any ideas ?
Why do you want the value to be a function that returns the state value. You can just assign it to state value using this.$store.state.myStore.settings.one
For this to work make the data option a normal function instead of an arrow function so that this still represents the vue instance
export default {
name: "myList",
data() {
return {
show: true,
listContent: [
{
name: "1",
icon: "person",
value: this.$store.state.myStore.settings.one
},
{
name: "2",
icon: "person",
value: this.$store.state.myStore.settings.two
},
{
name: "3",
icon: "person",
value: this.$store.state.myStore.settings.three
}
]
};
}
};
May be this will help. Long one, but it works.
const myModule = {
state: {
test: "modulle",
settings: {
one: "This is one",
two: "This is two",
three: "This is three"
}
}
};
const store = new Vuex.Store({
modules: { myModule }
});
new Vue({
el: "#app",
store,
data() {
return {
listContent: [
{
name: "1",
icon: "person",
value: null
},
{
name: "2",
icon: "person",
value: null
},
{
name: "3",
icon: "person",
value: null
}
]
};
},
watch:{
'$store.state.myModule.settings.one':{
immediate:true,
handler:function(value){
this.listContent[0].value = value;
}
},
'$store.state.myModule.settings.two':{
immediate:true,
handler:function(value){
this.listContent[1].value = value;
}
},
'$store.state.myModule.settings.three':{
immediate:true,
handler:function(value){
this.listContent[2].value = value;
}
},
}
});