I have a nested component, and the child component should receive a parameter from the main instance, but the problem is that I have to call the event twice the get the parameter.
index.html
<div id="app">
<button @click="displayComponent">Display</button><br/><hr/>
{{ message }}
<mycomponent v-if="showComponent" @hide="hideComponents"></mycomponent>
</div>
code.js
window.bus = new Vue();
Vue.component('mycomponent', {
template: `
<div>
<h3>Im the parent component</h3>
<childcomponent></childcomponent>
<button @click="$emit('hide')">Hide components</button>
</div>
`
});
Vue.component('childcomponent', {
template:`
<div>
<h4>Im the child component</h4>
<p>{{ data }}</p>
</div>
`,
data() {
return {
text: 'Nothing loaded'
};
},
methods: {
test() {
alert('hello');
},
getData(x) {
this.text = x;
}
},
created(){
bus.$on('extraCall', data => {
this.getData(data);
this.test();
});
}
});
const app = new Vue({
el: '#app',
data: {
message: 'hello world!',
showComponent: false
},
methods: {
displayComponent() {
bus.$emit('extraCall', 'this is some extra text');
this.showComponent = true;
},
hideComponents() {
this.showComponent=false;
}
}
});
The text value inside the child component element is set to a default value, after the Display button is clicked it fires bus.$emit
with the extraCall
event with some text as a parameter, this should update the text value, and it happens only after a second click to the Display button.
What am I missing?
答案 0 :(得分:1)
<mycomponent>
(and its child <childcomponent>
) aren't instantiated at the time the Display button is clicked because of v-if="showComponent"
.
First click:
extraCall
is emitted on the bus, but there's no listeners for that event so it is ignored.<mycomponent>
is instantiated after setting showComponent
to true.<mycomponent>
registers a listener for the extraCall
event in its created
hook.Second click:
extraCall
is emitted on the bus and <mycomponent>
handles it.You might think that the bus.$emit()
and this.showComponent = true
lines should be swapped so that <mycomponent>
gets instantiated before the event is emitted, but this still will not work because Vue defers the creation of the component until the next microtask when the view is updated.
This might work:
displayComponent() {
this.showComponent = true;
// Wait for child component to be instantiated
this.$nextTick(() => {
bus.$emit('extraCall', 'this is some extra text');
});
}
If the above code works for you, I still don't really recommend it though. You shouldn't need to account for the creation of the child component before emitting the event (it couples your components together). You should share the data some other way, check other SO questions on best ways to share data across components.