I have 2 components OperatorsList and OperatorButton. The OperatorsList contains of course my buttons and I simply want, when I click one button, to update some data :
- I emit select with the operator.id
This event is captured by OperatorList component, who calls setSelectedOperator in the store
First problem here, in Vue tools, I can see the store updated in real time on Vuex tab, but on the Components tab, the operator computed object is not updated until I click antoher node in the tree : I don't know if it's a display issue in Vue tools or a real data update issue.
However, when it's done, I have another computed property on Vue root element called selectedOperator that should return... the selected operator : its value stays always null, I can't figure out why.
Finally, on the button, I have a v-bind:class that should update when the operator.selected property is true : it never does, even though I can see the property set to true.
I just start using Vue, I'm pretty sure I do something wrong, but what ? I got the same problems before I used Vuex, using props.
Here is my OperatorList code :
<template>
<div>
<div class="conthdr">Operator</div>
<div>
<operator-button v-for="operator in operators" :op="operator.id"
:key="operator.id" @select="selectOp"></operator-button>
</div>
</div>
</template>
<script>
import OperatorButton from './OperatorButton';
export default {
name: 'operators-list',
components : {
'operator-button': OperatorButton
},
computed : {
operators() { return this.$store.getters.operators },
selected() {
this.operators.forEach(op =>{
if (op.selected) return op;
});
return null;
},
},
methods : {
selectOp(arg) {
this.$store.commit('setSelectedOperator', arg);
}
},
}
</script>
OperatorButton code is
<template>
<span>
<button type="button" v-bind:class="{ sel: operator.selected }"
@click="$emit('select', {'id':operator.id})">
{{ operateur.name }}
</button>
</span>
</template>
<script>
export default {
name: 'operator-button',
props : ['op'],
computed : {
operator() {
return this.$store.getters.operateurById(this.op);
}
},
}
</script>
<style scoped>
.sel{
background-color : yellow;
}
</style>
and finally my app.js look like that :
window.Vue = require('vue');
import Vuex from 'vuex';
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
const store = new Vuex.Store({
state: {
periods : [],
},
mutations: {
setInitialData (state, payload) {
state.periods = payload;
},
setSelectedOperator(state, payload) {
this.getters.operateurs.forEach( op => {
op.selected = (op.id==payload.id)
})
},
},
getters : {
operators : (state) => {
if (Array.isArray(state.periods))
{
let ops = state.periods
.map( item => {
return item.operators
}).flat();
ops.forEach(op => {
// op.selected=false; //replaced after Radu Diță answer by next line :
if (ops.selected === undefined) op.selected=false;
})
return ops;
}
},
operatorById : (state, getters) => (id) => {
return getters.operators.find(operator => operator.id==id);
},
}
});
import Chrono from './components/Chrono.vue';
var app = new Vue({
el: '#app',
store,
components : { Chrono },
mounted () {
this.$store.commit('setInitialData',
JSON.parse(this.$el.attributes.initialdata.value));
},
computed: {
...mapState(['periods']),
...mapGetters(['operators', 'operatorById']),
selectedOperator(){
this.$store.getters.operators.forEach(op =>{
if (op.selected) return op;
});
return null;
}
},
});