Vue: Is there a way to detect changes data coming from API

Viewed 7337

What Im looking is simple. As soon as I render my template it will make an API-Call to my Webserver and render the data to the template. Now I want to watch these datas in the vue component for coming changes. Whenever something has changed I want to update the template with the data coming from the API.

One Solution is that I could write something like a refresh method that will be called every 10 seconds. (Tbh. that is sth. that i dont want)

I want a way like Angular with observers.

Btw. Im new to vue and I started learning Vue with Laravel

Edit: My Code:

Vue.component

<template>
<div class="w-50">
    <table class="table ">
        <thead>
        <tr>
            <th scope="col"></th>
            <th scope="col"></th>
        </tr>
        </thead>
        <tbody>
            <tr v-for="user in users" v-bind:key="user.id">
                <td>{{ user.name }}</td>
                <td>{{ user.timer }}</td>
            </tr>
        </tbody>
    </table>
</div>
</template>

<script>
    export default {
        data() {
            return {
                users: [],
                user: {
                    id: '',
                    active: ''
                }
            };
        },
        mounted() {
            axios.get('/users')
                .then(res => {
                    this.users = res.data;
                    console.log(res.data);
                })
        }
    }
</script>

I did as you mention below. But the view is not updating if the data changes.

5 Answers

You can use vue-rx to work with Observables in Vue.js.

The following demo makes an AJAX call every 10 seconds to the API service that returns a random joke:

new Vue({
  el: '#demo',
  subscriptions: function () {
    return {
      joke: rxjs.timer(0, 10000).pipe(
        rxjs.operators.switchMap(() => rxjs.ajax.ajax('https://geek-jokes.sameerkumar.website/api')),
        rxjs.operators.map(res => res.response) 
      )
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.js"></script>
<script src="https://unpkg.com/vue-rx@6.1.0/dist/vue-rx.js"></script>
<div id="demo">{{ joke }}</div>

You didn't include any code, so I'll just add my example:

that is a template tag:

<template>
    <div>
        <h1> {{title}} </h1>
    </div>
</template>

script:

data(){
    return {
        title: '',
    },
},
mounted(){
    axios.get('/api/items/all').then(response => {
        this.title = response.data.title;
    });
}

and that should be enough for Vue.js to pick up changes and render properly a new title (in my example). If you want to watch for changes before they are rendered, you can add a watch property like that:

watch:{
    'title': function (newVal, oldVal) {
        // you can work with a new value here
    },
}

If you need more information on this, you can read Vue docs on Computed Properties and Watchers.

You are sort-of asking 2 or 3 questions at the same time, so I will try to answer this in parts.

Angular observables in Vue

A direct replacement for Angular observables is the Vue event system. You can listen for events with this.$on and stop listening with this.$off. To do this application wide you need to make something like an event bus:

Vue.prototype.$bus = new Vue();

// in components
mounted () {
  this.$bus.$on('myMessage', this.handleMyMessage);
},

beforeDestroy () {
  this.$bus.$off('myMessage', this.handleMyMessage);
}

That said, it doesn't sound like this is what you actually want to use.

Refreshing data

I suspect that you want to abuse the retry() method to redo the request over and over, but there is honestly no reason to use that. You can just put the request in a method and call it within an interval.

A better method to update your data may be to use a websocket server, but that is something you would need to set up. Without it you either have to do the api requests repeatedly, or don't bother refreshing it until the user wants to.

Updating the template

The data in Vue is always reactive. If the data that is referenced in the template changes, the template automatically rerenders. If you change an object, you may need to use the helper methods Vue.set or Vue.delete (docs). This will ensure the data stays reactive, and thus updates the rendered template.

I'd take a look at something like Socket.IO. It utilises websocket's so which is a 2 way connection to and from your client to the server. This allows the server to tell your website about changes and feed that data down without you having to poll for it (worth noting, socketio will poll for information is websocket's aren't supported though).

Laravel comes with an out of the box solution for my problem. The key word for this is Broadcast events. With this approach it is really easy to handle socket connections. Adding to this wonderful feature you can use Socket.io and Redis.

Laravel Doc: https://laravel.com/docs/5.7/broadcasting

Since I didnt know that vue always rerenders the template whenever my data has changed, there is no longer need for sth. like a observer in Angular

Related