4👍
Why not pass the current component as an event argument and use that to check if the event originated from this component or another one.
edit() {
this.editing = true;
EventBus.$emit('editing-another-field', this);
}
created() {
EventBus.$on('editing-another-field', source => {
if (source !== this) {
this.editing = false;
}
});
}
Or you can do it like this (it is important to unregister the event listener when the component is destroyed to avoid a memory leak):
edit() {
EventBus.$emit('editing-field', this);
}
created() {
this.editingFieldHandler = vm => {
this.editing = vm === this;
};
EventBus.$on('editing-field', this.editingFieldHandler);
}
destroyed() {
EventBus.$off('editing-field', this.editingFieldHandler);
}
Otherwise you can emit the event first and then set this.editing
to true.
0👍
Are you sure you want an event bus? This brings up bad memories of JQuery 😉 I think it would be cleaner to limit yourself to a tree of parents and children. Thinking MVVM, formLockedBy
is a perfectly valid and sensible property to store on the parent and pass to the children.
The solution below, running here, shows a form with two fields. The fields are both instances of modal-component
. The parent manages the formLockedBy
property. The child fields look at this property to know to disable themselves. When the user starts typing in a field, the field emits an editing
event and formLockedBy
gets set. Similarly, when a field emits a save
or cancel
event, the parent clears formLockedBy
and the other input(s) spring back to life.
Note the advantages…
- Only the parent listens for events.
- The identifier stored in
formLockedBy
is just the string name of the field. This is much safer than passing and storing a reference to the Vue component. If you don’t like this, you might consider adding a safe id to the object proto. - No surprises. The full list of events the parent will react to is declared in the tag instantiating the child. The child specifies in
props
everything it needs from the parent.
HTML
<div id="example">
<modal-input name='First Name'
:form-locked-by='this.formLockedBy'
v-on:save='formLockedBy = null'
v-on:cancel='formLockedBy = null'
v-on:editing='fieldActive'
></modal-input>
<modal-input name='Address'
:form-locked-by='this.formLockedBy'
v-on:save='formLockedBy = null'
v-on:cancel='formLockedBy = null'
v-on:editing='fieldActive'
></modal-input>
</div>
JS
Vue.component('modal-input', {
template: `<div>
{{name}} :
<input :name='name' type="text" v-on:keydown="active" :disabled="formLockedBy && formLockedBy != name"/>
<span v-if="editing && formLockedBy == name">
<input type="button" value="Save" v-on:click="$emit('save');editing=false;"></input>
<input type="button" value="Cancel" v-on:click="$emit('cancel');editing=false;"></input>
</span>
</div>`,
data : function(){
return {editing:false};
},
props: ['name','formLockedBy'],
methods : {
active : function(event){
if(!this.editing){
this.editing = true;
this.$emit('editing',{field:this.name})
}
return true;
}
}
});
// create a root instance
new Vue({
el: '#example',
data: {
formLockedBy : null
},
methods : {
fieldActive : function(args){
this.formLockedBy = args.field;
}
}
})