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;
}
}
})