Using Modapp

How to write client applications using Modapp

We will base this guide on Book Collection example, 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 Modapp components, we need to have a look at what Modapp is.

What is Modapp?

Modapp1 is a framework developed by Samuel Jirénius, creator of Resgate, and is described as:

A thin framework for building modular web applications.

In itself, it contains no code for component rendering. Instead it defines a set of simple interfaces which can be used together to build powerful applications.

Note

Modapp components generally renders faster, with less code, and smaller footprint, than virtual DOM based renderers such as React, Angular, and Vue.js.

Modapp defines the following interfaces relevant to ResClient.

Component interface

A Modapp component2 is a self contained UI component that can render itself on the DOM. It must have the following methods:

  • render(el) - Renders the component by appending its elements to the provided parent element
  • unrender() - Unrenders the component and removes its elements to from the parent element

Model interface

A Modapp model3 is a key/value object that can be listened to for changes. It must have the following methods:

  • on(event, handler) - Adds a callback handler for an event. Only defined model event is change
  • off(event, handler) - Removes a callback handler for an event.

Collection interface

A Modapp collection4 is an iterable object that can be listened to for changes. It must have the following methods:

  • on(event, handler) - Adds a callback handler for an event. Defined collection events are add, and remove
  • off(event, handler) - Removes a callback handler for an event.

ResClient and Modapp

ResClient has nothing to do with Modapp. However, since ResClient’s models and collections implement the interface defined by Modapp, any library that expects Modapp models and collections will work out of the box together with ResClient.

The component libraries used in the example implements these interfaces:

  • modapp-base-component5 - basic components used to render simple or nested HTML elements
  • modapp-resource-component6 - components that can listen and react to events in models and collections

Note

The libraries are written with pure Javascript without any third party dependencies. They only have a few shared internal dependencies where Modapp itself is not one of them.

Loading dependencies

Often you wish to use a module bundler, such as Webpack, to load dependencies using CommonJS / AMD / ES6 modules. To simplify the Book Collection example, all dependencies are loaded as UMD bundles in HTML script tags:

<script src="https://cdn.jsdelivr.net/npm/resclient@latest/dist/resclient.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/modapp-base-component@latest/dist/modapp-base-component.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/modapp-resource-component@latest/dist/modapp-resource-component.min.js"></script>

In the javascript code, the class constructors can be retrieved from the global scope, like this:

const { Elem, Txt, Button, Input } = window["modapp-base-component"];
const { CollectionList, ModelTxt } = window["modapp-resource-component"];
const ResClient = resclient.default;

Note

Because ResClient is written as an ES6 module, its class constructor will be found under the global resclient.default property when using the UMD script build.

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 directly inside the <script> tag:

let client = new ResClient('ws://localhost:8080');

Getting a resource

Once we’ve created the ResClient instance, we can load the resources needed for our components:

client.get('library.books').then(books => {
	/* Rendering of book list */
});

Rendering the list

When rendering the list of books, we use the CollectionList component. It requires two arguments:

  • Modapp collection to use as data source
  • Component factory function that gets an item from the collection, and returns a Modapp component
new CollectionList(books, book => (
	/* ... */
)).render(document.getElementById('books'));

As long as it is rendered, CollectionList will listen for any updates on the collection. If a book is added or removed, the component will handle the change with a nice transition animation.

Building a DOM structure

Modapp components are pure Javascript, using no template system. In order to create complex DOM structures, we can use the Elem component. An Elem component can render a node tree that may contain other embedded components.

Looking at the incomplete component factory function in the previous section, we can have it return such an Elem component for each book in the list:

book => new Elem(n =>
	n.elem('div', { className: 'list-item' }, [
		n.elem('div', { className: 'card shadow' }, [
			/* ... */
		])
	])
)

Reactive text components

Some texts, such as the title or author of a book, may be changed due to events from Resgate, and the components need to be updated. For this, we use the ModelTxt component. It requires two arguments:

  • Modapp model to use as data source
  • Callback function that takes the model and returns the text string to be displayed
new ModelTxt(book, book => book.author)

As long as it is rendered, ModelTxt will listen for any changes to the model. Whenever there is a change, the component will call the callback function to see if the text has been modified. If modified, it will make a nice fading transition to the new text.

Note

While the components’ render methods are seldom called explicitly, they will be called from within the Elem or CollectionList component that contains them.

Conclusion

That’s it! Modapp Components works out of the box together with ResClient, keeping your client view synchronized in real-time with your backend, while doing so with nice transition animations between states.

This done with increased speed, less code, and fewer dependencies compared to the worlds more famous component systems. All we need now is just some improvements to the documentation ;) .

Enjoy using ResClient and Modapp components!