Tomonso Ejang
Tomonso Ejang

Reputation: 1366

v-if not triggered on computed property

I have a vuex store. on change of state preference in the vuex store. i want to rerender the DOM. i want the checkValue method to be called everytime the state preference in the vuex store changes.

index.html

<div id="app">
    <my-component></my-component>
    <my-other-component></my-other-component>
</div>

vue is initialised, and also store is imported here

my_component.js

Vue.component('my-component',require('./MyComponent.vue'));
import store from "./store.js"
Vue.component('my-other-component',require('./MyOtherComponent.vue'));
import store from "./store.js"

new Vue({
    el : "#app",
    data : {},
    store,
    method : {},
})

component where DOM needs to be change on change of the state preference in store

MyComponent.vue

<template>
    <div v-for="object in objects" v-if="checkValue(object)">
        <p>hello</p>
    </div>
</template>


<script>
    methods : {
        checkValue : function(object) {
            if(this.preference) {
                // perform some logic on preference
                // logic results true or false
                // return the result
            }
        }
    },

    computed : {
        preference : function() {
            return this.$store.getters.getPreference;
        }
    }


</script>

Vuex store file

store.js

const store = new Vuex.Store({
state : {
    preferenceList : {components : {}},
},
getters : {
    getPreference : state => {
        return state.preferenceList;
    }
},
mutations : {
    setPreference : (state, payload) {
        state.preference['component'] = {object_id : payload.object_id}
    }
}

component from where the vuex store is updated on clicking in the li element.

MyOtherComponent.vue

<div>
    <li v-for="component in components" @click="componentClicked(object)">
    </li>
</div>


<script type="text/javascript">
    methods : {
        componentClicked : function(object) {
            let payload = {};
            payload.object_id = object.id;
            this.$store.commit('setPreference', payload);
        }
    }
</script>

Upvotes: 16

Views: 37390

Answers (3)

Florian Haider
Florian Haider

Reputation: 1912

I think your main issue is your mutation: VueJS creates everything it needs for reactivity during initialization, so your state.components object is already initialized when you try to override it with a new object with your mutation payload, which will then not be configured for reactivity (see https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats).

Try changing your mutations to:

mutations: {
  setPreference (state, payload) {
    Vue.set(state.preferenceList.components, 'object_id', payload.object_id);
  }
}

Upvotes: 1

Tomer
Tomer

Reputation: 17930

Methods are not reactive,

which means they will not track changes and re-run when something changes. That's what you have computed for.

So it means you need to use a computed to calculate what you need, but computed does not accept parameters and you need the object, so the solution is to create another component that accepts the object as a property and then perform the logic there:

MyOtherComponent.vue:

<template>
    <div v-if="checkValue">
        <p>hello</p>
    </div>
</template>


<script>
    props:['object','preference']
    computed : {
        checkValue : function() {
             if(this.preference) {
               // perform some logic on preference
               // logic results true or false
               return true
             }
             
             return false
        }
    }


</script>

And then in the original component:

<template>
    <my-other-component v-for="object in objects" :object="object" :preference="preference">
        <p>hello</p>
    </my-other-component>
</template>

Upvotes: 9

bbsimonbb
bbsimonbb

Reputation: 28982

v-if should not contain a function call. Just the existence of the function will likely cause the v-if to always be true. v-if should test a variable or a computed property, and it should have a name that's a noun, not a verb ! If checkValue just proxies preference, why do you need it. Why not just v-if="preference" ?

Upvotes: 2

Related Questions