Here is my components architecture
The component <ListButtonMenu>
emits a custom event display-error
as below. The emission works fine as I can see the event in VueDevtools:
<template>
<div>
<button type="button" class="btn btn-success" v-on:click="saveList()">
Save
</button>
</div>
</template>
<script>
export default {
props: {
list: Object
},
methods: {
saveList() {
this.$emit('display-error');
}
}
}
</script>
The component <ErrorMessage>
contains a div
element which listen to the custom event and calls a method display()
. The method changes the component CSS class in order to display himself: v-on:display-error="display"
. Unfortunately this does not work and the CSS class is not changed. What am I missing?
<template>
<div id="errorMessage" v-bind:class="cssClass" v-on:display-error="display()">
<div class="row justify-content-center alert alert-danger alert-dismissable text-danger">
Error: {{ errorMessage }}
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">
×
</button>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
'cssClass': 'd-none',
'errorMessage': 'Hello'
}
},
methods: {
display() {
this.cssClass = 'show';
this.errorMessage='Goodbye';
}
}
}
</script>
Because my ErrorMessage
and ListButtonMenu
components do not have a parent-child relationship, I opted for a different solution than using custom events.
Instead, I am using my application state (built using Vuex store) as an event bus to update an errorObject
and the ErrorMessage
component uses computed properties to capture the errorObject
and displays himself.
My component architecture remains the same as in the question. Here is the file store.js:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
errorObject: {
flag: false,
message: ''
}
}
});
Here is the ListButtonMenu component:
<template>
<div>
<button type="button" class="btn btn-success" v-on:click="saveList()">
Save
</button>
</div>
</template>
<script>
export default {
props: {
list: Object
},
methods: {
saveList() {
this.$store.state.errorObject.flag = true;
this.$store.state.errorObject.message = 'My error mesage';
}
}
}
</script>
And here the ErrorMessage component;
<template>
<div id="errorMessage" v-bind:class="cssClass">
<div class="row justify-content-center alert alert-danger alert-dismissable text-danger">
Error: {{ errorMessage }}
<button type="button" class="close" v-on:click="close()">
×
</button>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
}
},
computed: {
cssClass() {
if (this.$store.state.errorObject.flag) { return 'display' }
else { return 'd-none' }
},
errorMessage() {
return this.$store.state.errorObject.message;
}
},
methods: {
close() {
this.$store.state.errorObject.flag = false;
this.$store.state.errorObject.message= '';
}
}
}
</script>