One line condition not working in data in Vue js - vue.js

I have a component that is going to have data named isVendorOrAgent that should be false or true based on a property that the component gets. When I put this condition on the data section of the component, it doesn't work and always returns false but when I put that in created() and change the isVendorOrAgent in created(), it works.
How can I make this work?
This is the condition that is not working:
data : () => {
return {
isVendorOrAgent : (this.entityName == "vendor" || this.entityName == "agent") ? true : false;
}
}
but this works when the default is false:
created(){
if(this.entityName == "vendor" || this.entityName == "agent"){
this.isVendorOrAgent = true;
}
}

Try this code sample:
data () {
return {
isVendorOrAgent: Boolean(this.entityName === "vendor" || this.entityName === "agent")
}
}
What is different?
Now data is not an arrow function, because arrow functions do not change the context, so this won't be what it should be inside the component
We now store a Boolean value
We are now using strict equality ===, which is just a good habit
You may also take a look at computed properties: https://v2.vuejs.org/v2/guide/computed.html
Your problem could be solved like this:
computed () {
return {
isVendorOrAgent: Boolean(this.entityName === "vendor" || this.entityName === "agent")
}
}
The second way is preferable if you need this property to be reactive.

Related

Why Am I getting error return in computed property?

I'm using Vuex, inside Getter Foo function I'm returning two values inside array:
return ["Try Again"] or return ["Data result", data], in computed, I'm checking the array length and returning depending on result
computed:{
Foo: function(){
const getFoo = this.$store.getters.Foo;
if(getFoo.length === 1) {
this.existFoo = false
return getFoo[0]
}
this.existFoo = true
return getFoo
}
}
but I'm getting this error, even reading others posts I cannot solve it
34:9 error Unexpected side effect in "Foo" computed property
vue/no-side-effects-in-computed-properties
37:7 error Unexpected
side effect in "Foo" computed property
vue/no-side-effects-in-computed-properties
You are not permitted to change the state in computeds.
Try using another computed instead of existFoo
computed:{
Foo(){
if(this.$store.getters.Foo.length === 1) {
return this.$store.getters.Foo[0]
}
return this.$store.getters.Foo
},
existFoo(){
return this.$store.getters.Foo.length > 1
}
}
Now you should remove existFoo from state
You could use a watcher to watch the store value and set your local variables.
computed: {
getFooFromStore() {
return this.$store.getters.Foo
}
}
watch: {
getFooFromStore: function() {
this.existFoo = this.getFooFromStore[0] ? false : true;
}
}

How to making sure at least one checkbox is checked using vuejs

I would like to guarantee that at least one checkboxes are checked and the price are correct calculated.
https://jsfiddle.net/snoke/1xrzy57u/1/
methods: {
calc: function (item) {
item.isChecked = !item.isChecked
this.total = 0;
for (i = 0; i < this.items.length; i++) {
if(this.items[i].isChecked === true) {
this.total += this.items[i].price;
}
}
// fullPackagePrice
if(this.items[0].isChecked === true && this.items[1].isChecked === true && this.items[2].isChecked === true) {
this.total = this.fullPackagePrice;
}
// Trying to guarantee that have at least one checkbox checked
if(this.items[0].isChecked === false && this.items[1].isChecked === false && this.items[2].isChecked === false) {
this.total = this.items[0].price;
this.items[0].isChecked = true;
}
}
}
A good fit for this would be using computed properties instead of a method.
Read more about these here: https://v2.vuejs.org/v2/guide/computed.html#Computed-Properties
A computed property observes all referenced data and when one piece changes, the function is re-run and re-evaluated.
What you could do is first create a allowCheckout computed property like this:
allowCheckout() {
return this.items[0].isChecked || this.items[1].isChecked || this.items[2].isChecked;
}
You will then use it within the button like this:
<button :disabled="allowCheckout"...
This will disable the button when no items are checked.
Next, you'll also want to create a second computed property for the total price
totalPrice() {
// Perform similar checking here to update this.total
}
Lastly, you'll want to change your checkboxes to no longer use v-on:change but to instead use v-model for the relevant parameter for each.
This way your checkbox status will be bound to the true/falseness of the variables.
If you still want to go with your method, you can implement at like shown in this updated fiddle and set a variable atLeastOneItemIsChecked like this:
this.atLeastOneItemIsChecked = this.items.find(item => item.isChecked) !== undefined
Do not force the user to always check a checkbox. Instead, display a hint and disable the button using :disable and tailwind css resulting in this:

Value is changed just in methods, VueJs

I have a value with false default value, and inside a watch (for another value) I have chage it's value, but the value is changed just there, on second Click (event), the value is changed. Not sure why..
The value is change when I trigger that event twice..
<template>
<h1>{{hide_confidence}}</h1> //HERE IS NOT CHANGED
</template>
...
data() {
return {
mainSelect: '',
hide_confidence: true
};
},
watch: {
mainSelect(value) {
if (value !== "" && value !== "none") {
this.hide_confidence = false;
// this.confidence_score = "";
} else {
this.hide_confidence = true;
}
console.log("Value: ", this.hide_confidence); //HERE IS CHANGED
},
hide_confidence(value{
console.log("Value: ", value); //HERE IS NOT CHANGED
}
}
...
watch is not a method to change your data permanently. Just you can play with other properties with changing it temporary.
If you want to change a value permanently then you have to call an event.
Please take look in details here:
https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property

Using set() for computed values correctly in Vue

I'm having an issue with setting a computed property (which is an array). I have the following computed property in my Vue component:
posts: {
get () {
if ( this.type == 'businesses' || this.type == 'business' ) {
return this.$store.getters.getAllBusinesses.map(_business => {
return _business
})
} else if ( this.type == 'shops' || this.type == 'shop' ) {
return this.$store.getters.getAllShops.map(_shop => {
return _shop
})
} else if ( this.type == 'events' || this.type == 'event' ) {
return this.$store.getters.getAllEvents.map(_event => {
return _event
})
} else {
return this.$store.getters.getAllBusinesses.map(_business => {
return _business
})
}
},
set (posts) {
console.log(posts)
this.posts = posts // Doesn't work - this causes a maximum call stack error, recursively setting itself obviously.
return posts // Doesn't work either - this.posts doesn't seem to be changing...
}
},
The console.log(posts) is exactly what I want - a filtered array of posts, see the below console log output.
My question is simply this: how do I go about updated the computed posts value?
If it is useful, I am doing the following manipulation to the posts:
let filteredPosts = []
this.posts.filter(_post => {
_post.category.forEach(category => {
if ( this.categoryFilters.includes(category.slug) ) {
filteredPosts.push(_post)
}
})
})
let uniqueFilteredPosts = [...new Set(filteredPosts)];
this.posts = uniqueFilteredPosts
This is purely to filter them. What I am console.logging is absolutely correct to what I want. So this might be a red herring.
Any pro-Vue tips would be greatly appreciated!
If you want to use a computed setter, you normally assign to whatever values underlie the computed's get function. See the example at the link.
In your case, you examine this.type and return something from the store based on it. The setter should probably examine this.type and set something in the store based on it.

Binding class doesn't seem to work properly based on attached variable value

My banner-visible binding class is conditioned by my showMainBanner computed property:
<div :class="['view view-index', { 'banner-visible' : showMainBanner }]">
Here's how I define my computed property:
computed: {
showMainBanner () {
return (Cookies.get('banner_dismiss')) ? false : this.$store.state.config.showMainBanner
}
}
When I reload the page, I can see the value of my computed property by console logging it in the mounted() hook:
mounted () {
console.log('showMainBanner = ' + this.showMainBanner)
}
In the console on page load I see: showMainBanner = false
Yet, the banner-visible class is still there, despite the value of showMainBanner being false.
How is that possible?
The most puzzling thing is this: when I navigate the page away through a link, and come back to it through a link, this problem does NOT occur. But if I refresh the page, it does.
EDIT:
I changed my code to something even more explicit:
showMainBanner () {
if (Cookies.get('banner_dismiss')) {
console.log('RETURN FALSE')
return false
} else {
console.log('RETURN TRUE')
return this.$store.state.config.showMainBanner
}
}
After refreshing the page, I see in the console RETURN FALSE and I still see showMainBanner = false from the console.log() call in mounted() hook. So clearly, showMainBanner is definitely equal to false.
Is there black magic going on here?
Cookies is not reactive. After the first time showMainBanner is evaluated it does not get evaluated again by Vue.
When you navigate away and come back, Vue will evaluate the computed property again and this time the Cookie is already set.
Your issue is because your cookie returns a string:
console.log(typeof Cookies.get('banner_dismiss'))
//=> string
Try to change your condition like:
computed: {
showMainBanner () {
let dismiss = Cookies.get('banner_dismiss') === 'undefined' ? false : JSON.parse(Cookies.get('banner_dismiss'))
return dismiss ? false : this.$store.state.config.showMainBanner
}
}
Or if you want to avoid JSON's errors in case of empty Cookie, you can add a plain condition:
computed: {
showMainBanner () {
let dismiss = Cookies.get('banner_dismiss') === 'true'
return dismiss ? false : this.$store.state.config.showMainBanner
}
}