I want to show an icon depending if variable is true or false, so I just made a ternary operator to do this :
getClass(enabled) {
return enabled ? "fa fa-check" : "fa fa-times";
}
I call it like this :
<div slot-scope="{ row }" class="f-flex">
<i :class="getClass(row.enabled)" />{{ row.enabled }}
</div>
It works first (when I load the page)
but when I change the row.enabled variable, it doesn't work whereas the content is changed
I also tried to put the entire data into an array like this :
this.dashboards.forEach((d) => {
this.enabledDashboards[d._id] = d.enabled;
this.default_range[d._id] = this.ranges.find((r) => r.value == d.default_range).label;
});
and now I get the class like this :
<i :class="getClass(row._id)" />{{ enabledDashboards[row._id] }}
</div>
getClass(id) {
return this.enabledDashboards[id] ? "fa fa-check" : "fa fa-times";
},
But it won't work
Related
I have a component that displays rows of data which I want to toggle to show or hide details. This is how this should look:
This is done by making the mapping the data to a new array and adding a opened property. Full working code:
<script setup>
import { defineProps, reactive } from 'vue';
const props = defineProps({
data: {
type: Array,
required: true,
},
dataKey: {
type: String,
required: true,
},
});
const rows = reactive(props.data.map(value => {
return {
value,
opened: false,
};
}));
function toggleDetails(row) {
row.opened = !row.opened;
}
</script>
<template>
<div>
<template v-for="row in rows" :key="row.value[dataKey]">
<div>
<!-- Toggle Details -->
<a #click.prevent="() => toggleDetails(row)">
{{ row.value.key }}: {{ row.opened ? 'Hide' : 'Show' }} details
</a>
<!-- Details -->
<div v-if="row.opened" style="border: 1px solid #ccc">
<div>opened: <pre>{{ row.opened }}</pre></div>
<div>value: </div>
<pre>{{ row.value }}</pre>
</div>
</div>
</template>
</div>
</template>
However, I do not want to make the Array deeply reactive, so i tried working with ref to only make opened reactive:
const rows = props.data.map(value => {
return {
value,
opened: ref(false),
};
});
function toggleDetails(row) {
row.opened.value = !row.opened.value;
}
The property opened is now fully reactive, but the toggle doesn't work anymore:
How can I make this toggle work without making the entire value reactive?
The problem seems to come from Vue replacing the ref with its value.
When row.opened is a ref initialized as ref(false), a template expression like this:
{{ row.opened ? 'Hide' : 'Show' }}
seems to be interpreted as (literally)
{{ false ? 'Hide' : 'Show' }}
and not as expected as (figuratively):
{{ row.opened.value ? 'Hide' : 'Show' }}
But if I write it as above (with the .value), it works.
Same with the if, it works if I do:
<div v-if="row.opened.value">
It is interesting that the behavior occurs in v-if and ternaries, but not on direct access, i.e. {{ rows[0].opened }} is reactive but {{ rows[0].opened ? "true" : "false" }} is not. This seems to be an issue with Vue's expression parser. There is a similar problem here.
Hi currently I am making a add & minus function and the problem I am facing is once I clicked add or minus, the value still remain the same... I use the watch property also and it still not working
The get_list is calling from a API
<b-row v-for="(data,i) in get_list" :key="i" class="mt-3 mx-0">>
<b-button pill
class="quantity-btn btn-secondary"
#click="addQuantity(data.id_product,data.id_style)"
>
<span style="transform: translateY(-5%);">+</span>
</b-button>
<div class="px-2">
<b-form-input type="number" min="1" :max="data.quantity_available" :value="quantity" v-model="data.cart_quantity" class="quantity-input"></b-form-input>
</div>
<b-button pill
class="quantity-btn btn-secondary"
#click="minusQuantity(data.id_product,data.id_style)"
>
<span style="transform: translateY(-5%);">-</span>
</b-button>
</b-row>
script
data: () => ({
get_list: [],
quantity:0,
}),
method :{
addQuantity(id,style) {
this.quantity++
this.updateQuantity(id,style)
},
minusQuantity(id,style) {
this.quantity--
this.updateQuantity(id,style)
},
},
watch: {
quantity(newVal, oldVal) {
console.log('new'+newVal)
}
}
Take a look of this code in code proved above.
<div class="px-2">
<b-form-input type="number" min="1" :max="data.quantity_available" :value="quantity" v-model="data.cart_quantity" class="quantity-input"></b-form-input>
</div>
Here it seems cart_quantity is getting used in template instead of quantity due to this it's not getting updated.
to fix this issue, you can update the cart_quantity property of the data object instead of the quantity data property in the addQuantity and minusQuantity
methods: {
addQuantity(id, style) {
this.get_list.forEach(item => {
if (item.id_product === id && item.id_style === style) {
item.cart_quantity++;
}
});
},
minusQuantity(id, style) {
this.get_list.forEach(item => {
if (item.id_product === id && item.id_style === style) {
item.cart_quantity--;
}
});
}
}
Please remove watch property as well it seems not required.
The problem is that you are performing the add/minus operation on the quantity variable but in the template, you are using the cart_quantity variable which is not increasing/decreasing.
So, either use quantity or cart_quantity as per your logic.
addQuantity(id, style) {
this.cart_quantity++;
// If you are using quantity as v-model
// this.quantity++
this.updateQuantity(id, style);
},
minusQuantity(id, style) {
this.cart_quantity--;
// If you are using quantity as v-model
// this.quantity--
this.updateQuantity(id, style);
},
One more thing, you don't need to use value and v-model together at the same time. If you want to give some initial value to the input, simply assign that value to your cart_quantity on mounted and use it further.
The last thing, you don't need a watcher as well.
i want to show delete button for each comment that a particular user made, but i am unable to do it, i am using v-bind to disable delete buttton for others comment, so that user cant delete others comment, but its still visible for all the comments i.e (for other users as well ). suppose i am a user i comment 3 times then delete button should show on my comments only not on others comment. can some one please help me to achieve this?
My code snippet is below
<div class="comment-list" v-for="comment in comments" :key="comment._id">
<div class="paragraph" :class="[name, onCaretButtonClick ? 'paragraph' : 'hide']">
<span class="names" id="comment-desc">
<label class="comm-name">{{ comment.name }}</label>
<button class="like-btn" id="like-comment"><i class="fas fa-heart"></i></button>
<label> {{ comment.likes + ' likes' }} </label>
<button v-bind:disabled="isCommentIdMatched" v-on:click="deleteComment(comment.userId)"
class="del-btn">delete</button>
</span>
<p>{{ comment.comment }}</p>
</div>
</div>
below is deleteComment function and computed properties that i am using
computed: {
comments() {
return store.state.comments
},
getUserId() {
return store.state.user._id
},
isCommentIdMatched() {
let comments = store.state.comments
let value = false
if(comments) {
comments.forEach((comment) => {
if(comment.userId.match(this.getUserId)) {
value = true
}
})
return value
}
else {
return value
}
}
},
methods: {
deleteComment: function(commentUserId) {
let userId = store.state.user._id
if(commentUserId.match(userId)) {
console.log('yes matched')
}
},
}
there is no need to write isCommentIdMatched property, instead you can use change some lines.
add v-bind="comments" in below line
<div v-bind="comments" class="comment-list" v-for="comment in comments" :key="comment._id">
and add v-if="comment.userId && comment.userId.match(getUserId)" in below button
<button v-if="comment.userId && comment.userId.match(getUserId)" v-on:click="deleteComment(comment.userId)" class="del-btn">delete</button>
I'm currently trying to add line breaks to this Vue Bootstrap form checkbox group. The example that Vue Bootstrap docs (https://bootstrap-vue.js.org/docs/components/form-checkbox/) show how I can create a select all checkboxes group, but they are tightly grouped (without line breaks). Is there a way that I could add a line break within the flavours array to separate each object?
I have tried using v-html on a div tag and load in the flavours array, but it did not have the right outcome. I also tried :style="{marginBottom:'25px'}" and it also didn't work, the entire group of array move up and down the page together. I ran out of ideal after that.
HTML
<template>
<div>
<b-form-group>
<template slot="label">
<b>Choose your flavours:</b><br>
<b-form-checkbox
v-model="allSelected"
:indeterminate="indeterminate"
aria-describedby="flavours"
aria-controls="flavours"
#change="toggleAll"
>
{{ allSelected ? 'Un-select All' : 'Select All' }}
</b-form-checkbox>
</template>
<b-form-checkbox-group
id="flavors"
v-model="selected"
:options="flavours"
name="flavors"
class="ml-4"
aria-label="Individual flavours"
stacked
></b-form-checkbox-group>
</b-form-group>
<div>
Selected: <strong>{{ selected }}</strong><br>
All Selected: <strong>{{ allSelected }}</strong><br>
Indeterminate: <strong>{{ indeterminate }}</strong>
</div>
</div>
</template>
JavasScript
<script>
export default {
data() {
return {
flavours: ['Orange', 'Grape', 'Apple', 'Lime', 'Very Berry'],
selected: [],
allSelected: false,
indeterminate: false
}
},
methods: {
toggleAll(checked) {
this.selected = checked ? this.flavours.slice() : []
}
},
watch: {
selected(newVal, oldVal) {
// Handle changes in individual flavour checkboxes
if (newVal.length === 0) {
this.indeterminate = false
this.allSelected = false
} else if (newVal.length === this.flavours.length) {
this.indeterminate = false
this.allSelected = true
} else {
this.indeterminate = true
this.allSelected = false
}
}
}
}
</script>
Don't use the options array. Render each option as it's own <b-form-checkbox> inside of the <b-form-checkbox> group, and on each <b-form-checkbox> add the class mb-1, mb-2, mb-3, mb-4, or mb-5 (these are margin bottom spacing helper classes).
<b-form-checkbox-group
id="flavours"
v-model="selected"
name="flavours"
class="ml-4"
aria-label="Individual flavours"
stacked
>
<b-form-checkbox
v-for="flavour in flavours"
:value="flavour"
class="mb-5"
>
{{ flavour }}
</b-form-checkbox>
</b-form-checkbox-group>
Just started with Vue so I can't get this simple thing working. All I'm trying to do is toggle a class based on a condition.
<button type="button"
class="btn dropdown-toggle"
v-bind:class="{ btn-default: (search.category != 'all') }">
{{ filterCategoryText || 'Category' }}
</button>
Firstly, as you discovered, you should probably remove the duplicate class definition. You can mix static and dynamic classes in the bound class definition. (If you leave the duplicate there it still works, though)
Then, you have the choice...
Object syntax
// property names will be in the class list if their values are truthy
:class="{
'btn-default': search.category != "all",
'btn' : true,
'dropdown-toggle' : true
}"
Array syntax
// an item in the array becomes a class in the class list
:class="[
search.category != 'all' ? 'btn-default':'',
'btn',
'dropdown-toggle'
]"
Simple expression
// if you only have one item, just use a simple expression
:class="search.category != 'all' ? 'btn-default':''"
Docs are here
You still could have used Object syntax for the class binding. I guess the code in you example didn't work because you didn't wrap object property name with quotes. Moreover, you have at least three options here. In such case I would always stick with objects if possible as it's usually more readable. Take a look:
new Vue({
el: '#app',
data: {
red: 'nope',
},
methods: {
toggle() {
this.red = this.red === 'yes' ? 'nope' : 'yes';
}
},
})
.is-bold {
font-weight: 900;
}
.is-red {
color: red;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p class="is-bold" :class="{'is-red': red === 'yes'}">
Option
</p>
<p class="is-bold" :class="red === 'yes' ? 'is-red' : ''">
Option 1
</p>
<p class="is-bold" :class="[red === 'yes' ? 'is-red' : '']">
Option 2
</p>
<button #click="toggle">Toggle class</button>
</div>
jsfiddle: https://jsfiddle.net/oniondomes/06bg516h/
Figured it:
<button type="button"
:class="[(search.category) ? '' : 'btn-default', 'btn dropdown-toggle']"
{{ filterCategoryText || 'Category' }}
</button>
try this instead of v-bind:class="{ 'btn-default': search.category != 'all' }"