Christof
Christof

Reputation: 3927

vuejs: v-if directive for event?

Can I react to an event in a vue template? Say a child component dispatches an event $dispatch('userAdded'), could I do something like this in the parent component:

<div class="alert alert-info" v-if="userAdded">
    User was created!
</div>

or, if not, can I access variables of the child component?

<div class="alert alert-info" v-if="$refs.addView.form.successful">
    User was created!
</div>

I tried both without success.

Also, while I'm here, is there an expressive way to hide elements after a certain amount of time? Something like (to hide after 2s):

<div class="alert alert-info" v-if="$refs.addView.form.successful" hide-after="2000">
    User was created!
</div>

Thanks!

edit: wrote my own hide-after directive:

Vue.directive('hide-after', {
  update: function(value) {
    setTimeout(() => this.el.remove(), value);
  }
});

<div class="alert alert-info" v-hide-after="2000">
    This will be shown for 2 seconds
</div>

Upvotes: 2

Views: 11028

Answers (2)

bbsimonbb
bbsimonbb

Reputation: 28992

The whole idea of events is that you can react to them. But you want the reaction to pass by the model. You really don't want unrelated bits of markup listening and reacting 'independently'. $dispatch is deprecated. To do this now, do the following...

In the child component, emit an event as follows

this.$emit('didIt' {wasItAwful:'yep',wereYouScared:'absolutely'});

In the parent, you register the event listener with v-on, as an attribute of the child's tag...

<adventure-seeking-child v-on:did-it='myChildDidIt' />

Then, in the parent's methods, define your handler.

methods : { myChildDidIt : function(payload){ ... } }

Docs are here.

Upvotes: 1

vbranden
vbranden

Reputation: 5986

Yes you can but you need to take this approach.

  1. Create a child that dispatches an event
  2. In the parent component create an event listener for the event and also a data property that the event listener will set locally on the component instance
  3. In the parent bind your v-if to the local data component

The code would look something like

parent

HTML

<div v-if="showAlert"></div>

Js

events: {
  'alert.show': function () {
    this.showAlert = true
  },
  'alert.hide': function () {
    this.showAlert = false
  }
},
data () {
  return {
    showAlert: false
  }
}

Child

Js

methods: {
  showAlert (show) {
    show ? this.$dispatch('alert.show') : this.$dispatch('alert.hide')
  }
}

The reason you should avoid using the $child and $parent is that it makes that component always depend on the fact that the parent will have the alert property and makes the child component lest modular

Since dispatch goes up until it hits a listener you can have several nested components in between the parent and child dispatching the alert control

UPDATE

Alternately, since you do not like the LOE of using events you can create a 2-way property on the child that either the parent or child can update

Example

Parent

HTML

<div v-if="showAlert"></div>
<child-component :show-alert.sync="showAlert"></child-component>

JS

data () {
  return {
    showAlert: false
  }
}

Child

js

props: {
  showAlert: {
    type: Boolean,
    twoWay: true
  }
},
methods: {
  showAlertInParent (show) {
    this.$set('showAlert', show)
  }
}

Upvotes: 4

Related Questions