Using Vue.js
How to write client applications using Vue.jsWe will base this guide on Book Collection example - Vue.js, which shows an editable list of books, with their titles and authors. To try out the example, visit the link and follow the instructions.
Before we go into the code on how to use ResClient together with Vue.js, we need to have a look at how ResClient handles state.
State
ResClient stores and manages the state in model and collection objects, which represents the state as it is on the backend. The resource objects are to be considered immutable, and should only be managed and updated by ResClient itself, based on events coming from Resgate.
The basic idea of Resgate and ResClient is to subscribe to resources which is currently relevant to the user. Eg. if a user is browsing a list of company personel, it would be wasteful to store and update the state of the company’s inventory list when it is not in view. Since ResClient keeps track of which resources are being listened to, we can avoid redundant subscriptions by having components explicitly listen and unlisten to resource events, and not only rely on Vue.js’ reactivity system.
Initializing ResClient
To get data from Resgate, we need to create a ResClient instance. This can be done in many places, but in our example this is done inside the App
component’s created
hook:
created() {
this.client = new ResClient('ws://localhost:8080');
/* ... */
}
Getting a resource
We also want to load the resources needed for our components, in this case our list of books, which we store as data. With Vue.js, this can preferably be done in the created
hook as well:
data: {
this.books = null
},
created() {
this.client = new ResClient('ws://localhost:8080');
this.client.get('library.books').then(books => {
this.books = books;
});
},
The books
collection is then passed to the BookList
component as props:
<book-list v-if="books" :books="books"></book-list>
Tip
Instead of having the parent component (
App
) load the resources to pass them to the child components (BookList
) one may pass the ResClient instance (client
) to the child component instead.This way, the child component will have the responsibility of loading the data.
Rendering the list
When rendering the list, we use the books
collection object just like with any other Vue.js props:
<div class="book-list">
<book v-for="book in books" :key="book.id" :book="book"></book>
</div>
Note
ResClient collections are iterables, but not arrays. Since the
v-for
directive supports iterables, Vue.js will have no trouble iterating over the collections.
Listen to events
Once the component is created, we also want to listen to add and remove events. This is preferably done in the created
hook. While Vue.js may detect changes inside props, it will have problems reacting to items being added and removed by ResClient. Because of this, we will need to trigger a re-render ourself, using this.$forceUpdate
:
created() {
this.books.on('add', this.onUpdate);
this.books.on('remove', this.onUpdate);
},
methods: {
onUpdate() {
this.$forceUpdate();
}
}
Unlisten to events
Once the component is about to be destroyed, we need to unregister our callbacks so that ResClient may be free to unsubscribe. This is preferably done in the beforeDestroy
hook:
beforeDestroy() {
this.books.off('add', this.onUpdate);
this.books.off('remove', this.onUpdate);
},
Tip
To make a component reusable with non-ResClient objects, the registering of listeners can be made conditional:
created() { if (typeof this.books.on == "function") { this.books.on('add', this.onUpdate); this.books.on('remove', this.onUpdate); } }, beforeDestroy() { if (typeof this.books.off == "function") { this.books.off('add', this.onUpdate); this.books.off('remove', this.onUpdate); } },
Listening to model events
The above examples shows how to listen/unlisten to collection events. As shown in the example’s Book
component, listening to model events is close to identical:
created() {
this.book.on('change', this.onUpdate);
},
beforeDestroy() {
this.book.off('change', this.onUpdate);
},
methods: {
onUpdate() {
this.$forceUpdate();
}
}
Tip
Instead of using forceUpdate, one could use data variables which are initialized from props, and updated in the event callback methods:
data() { return { title: this.book.title, author: this.book.author }; }, methods: { onUpdate() { this.title = this.book.title; this.author = this.book.author; } }
Calling methods
Resources are not only data, but may also have methods that can be called. In the Book
component, we can see how such a method is called when editing the book’s fields:
this.book.set({
title: this.editTitle,
author: this.editAuthor
});
Conclusion
That’s it! Communication and real-time synchronization with backend is solved for your Vue.js app, and everything updates as expected.
What’s left?
This guide doesn’t bring up transition animations between different states. But that subject has more to do with Vue.js than with ResClient, and is better discussed by other people.
Enjoy using ResClient!
Note
By using a
res-vuejs
library, the amount of boilerplate code can be reduced. Unfortunately, no such library exists yet. Care to create it?