Models are where Arva really shines. It's super easy to create models with two-way data binding to a realtime data source. Have a look for yourself:

Defining a new model

When creating a new model, we only have to extend the Model class and define which fields our model should contain.

The model will automagically create a handler that is fired when the model's properties are changed in code, hook the model up to the DataSource you want to use, and synchronise all changes between the two. Isn't that cool?

Let's create a simple model for a Monkey:

import {Model}              from 'arva-js/core/Model.js';

export class Monkey extends Model {
    get character() {}
    get tailLength() {}
    get currentMood() {}
}

Upon construction, all getters defined in our Monkey class are replaced with getter/setter properties, and connected to the change handlers. The Model will automatically deduce the path to your Monkey on the remote DataSource to be '/Monkeys', if you don't pass a path specifically yourself. It does this by appending 's' to the model's class name, which works fine in most cases.

Specifying a path

Don't like your Monkey being stored under /Monkeys? That's fine. Let's see how to save our monkey under /TinyGorillas instead.

import {Model}              from 'arva-js/core/Model.js';

export class Monkey extends Model {
    get character() {}
    get tailLength() {}
    get currentMood() {}
    constructor(id, data, options) {
        super(id, data, {...options, path: '/TinyGorillas'});
    }
}

Instantiating a model

You can create model instances everywhere, but a proper workflow will probably have you construct them in your Controllers. We'll show you how:

import {Controller}                 from 'arva-js/core/Controller.js';

export class MonkeyController extends Controller {
    constructor(){
        this.monkey = new Monkey('Caesar');
    }
}

This will create a new Monkey object that points to the remote DataSource at /TinyGorillas/Caesar.

All changes you do locally are reflected on the remote DataSource in real-time:

import {Controller}                 from 'arva-js/core/Controller.js';

export class MonkeyController extends Controller {

    constructor(){
        this.monkey = new Monkey('Caesar');
        this.monkey.currentMood = 'world domination';
    }
}

It won't start synchronising from the DataSource to local until you tell it you want to, to ensure performance. Let's see how we add an event listener for every time that the model is updated remotely:

import {Controller}                 from 'arva-js/core/Controller.js';

export class MonkeyController extends Controller {

    constructor(){
        this.monkey = new Monkey('Caesar');
        this.monkey.on('value', () => {
            console.log(`Caesar's mood changed to: ${this.monkey.currentMood}`);
        });
    }
}

Subscribing to the 'value' event will automatically start synchronisation from the DataSource to the local model.

Multiple changes

If you change a bunch of fields after each other, each of them will trigger a push to the DataSource individually. For example, this will trigger three seperate synchronisation pushes:

monkey.tailLength = 100;
monkey.character = 'evil';
monkey.currentMood = 'world domination';

Usually we don't want that, because everyone listening to this model will receive a bunch of updated events, and that is bad for UX.

You can use the Model's transaction() method to execute multiple changes, and only trigger one push to the DataSource at the end. You pass it a function to execute, and it will update to the DataSource itself afterwards:

monkey.transaction(() => {
    monkey.tailLength = 100;
    monkey.character = 'evil';
    monkey.currentMood = 'world domination';
});

This will only generate a single push. That's better.

Moving beyond basics

Arrays of models

Models start becoming cool when you can manipulate a bunch of them. Our PrioritisedArray allows you to subscribe to a list of monkeys. That way you can track how many of them are planning world domination all at once. Cool, right?

Two-way data bound ScrollViews

With our DataBoundScrollView, you can hook up a PrioritisedArray to a ScrollView super easily. Pass in the array, and define the renderable used to display each model. Simple as that, you have a scrollable view hooked up to your DataSource. It automatically handles new models, changed models, moved models, and removed models, and syncs the UI with them accordingly. In real-time.