1

in my vuejs program i am trying to make a global instance of an alert/notification system. This would be at the rootmost instance of the app. and then my plan was to push to an array of objects and pass that through to the component. This only half works.

in my app.vue i have

<template>
  <div id="app">
    <alert-queue :alerts="$alerts"></alert-queue>
    <router-view></router-view>
  </div>
</template>

in my main.js i have

exports.install = function (Vue, options) {
  Vue.prototype.$alerts = []
}

and my alert_queue.vue is

<template>
  <div id="alert-queue">
    <div v-for="alert in alerts" >

    <transition name="fade">
      <div>
        <div class="alert-card-close">
          <span @click="dismissAlert(alert)"> &times; </span>
        </div>
        <div class="alert-card-message">
          {{alert.message}}
        </div>
      </div>
    </transition>

  </div>
  </div>
</template>

<script>
export default {
  name: 'alert',
  props: {
    alerts: {
      default: []
    }
  },
  data () {
    return {
    }
  },
  methods: {
    dismissAlert (alert) {
      for (let i = 0; i < this.alerts.length; i++) {
        if (this.alerts[i].message === alert.message) {
          this.alerts.splice([i], 1)
        }
      }
    }
  }
}

</script>

I can add to this list now by using this.$alerts.push({}) and i can see they are added by console.logging the results.

The problem is that the component doesn't recognise them unless i manually go in and force it to refresh by changing something in code and having webpack reload the results. as far as i can see, there is no way to do this programatically.... Is there a way to make prototype components be watched like the rest of the application?

I have tried making the root most file have a $alerts object but when i use $root.$alerts.push({}) it doesn't work because $root is readonly.

Is there another way i can go about this ?

3
  • vuejs.org/v2/guide/list.html#Caveats Commented Jul 18, 2017 at 20:17
  • @Jeff Vue can register pushing to an array, it just can't register updating an already-existing index of an array Commented Jul 18, 2017 at 20:21
  • You're right, I hadn't read your request closely enough! Commented Jul 18, 2017 at 20:30

2 Answers 2

2

You could make $alerts a Vue instance and use it as an event bus:

exports.install = function (Vue, options) {
  Vue.prototype.$alerts = new Vue({
    data: {alerts: []},
    events: { ... },
    methods: { ... }
  })
}

Then in your components you might call a method this.$alerts.addAlert() which in turn pushes to the array and broadcasts an event alert-added. In other places you could use this.$alerts.on('alert-added', (alert) => { ... }

Other than that, I think this is a good use case for Vuex, which is pretty much designed for this: https://github.com/vuejs/vuex

Sign up to request clarification or add additional context in comments.

1 Comment

thanks. This is a good start. it functions. with a few excentricities. But i think i can iron though out.
0

Properties defined on Vue.prototype are not reactive like a Vue instance's data properties.

I agree that, in most cases, Jeff's method or using Vuex is the way to go.


However, you could simply set this.$alerts as a Vue instance's data property and then updating that property (which would be reactive) would, by association, update the global $alerts array:

Vue.prototype.$alerts = ['Alert #1'];

Vue.component('child', {
  template: `<div><div v-for="i in items">{{ i }}</div></div>`,
  props: ['items'],
})

new Vue({
  el: '#app',
  data() {
    return {
      globalAlerts: this.$alerts,
    }
  },
  methods: {
    addToArray() {
      this.globalAlerts.push('Alert #' + (this.globalAlerts.length + 1));
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.min.js"></script>
<div id="app">
  <child :items="$alerts"></child>
  <button @click="addToArray">Add alert</button>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.