Architecture & Design Patterns

Alto.js can be broken into four major areas: Foundation, Router, Data, UI.

architecture-visual.png

Foundation

The Foundation library is where the basic building blocks for Alto.js are defined. Philosophically, Alto.js embraces classes and promotes them as first class citizens. With that, we will jump right in with CoreObject. To define a new class that inherits from CoreObject. We use the .extend method.

import CoreObject from "framework/alto/foundation/core_object";

let MyClass = CoreObject.extend({});

While instantiating an instance of CoreObject we use the .create method.

let myInstance = CoreObject.create({});

Router

Router is responsible for defining routes, enforcing client-side security, pairs a URL to a component and/or dispatches an action. In its most basic form, an applications router is a singleton that lives throughout the entire life cycle of your application. As a user navigates your application. The URL representation of your application changes as well. This simple URL change starts a cascade of events to follow. Coordinating the events can be a challenge. However, with Alto a simple api to handle these events is exposed.

When a user navigates to the following url http://localhost:3000/todos, our router takes the location and splits it into an array as follows:

let path = route.split("/"); // path is now assigned the value ["todos"]

Next the path array is used to recursively traverse our defined routes. Below is how we would define our route for the url http://localhost:3000/todos.

import Router from"framework/alto/router";

let router = Router.create({

routes: {
todos:{
// more to come
}
}

});

export default router;

As you could imagine, our router subscribes to route changes, splits the route, and recursively walks the routes hash in our router. In the event no match is found. The router will redirect to a standard 404 route.

Data

The Data library provides a way to seamlessly query information from an in-memory partitioned row database and remote server(s). First lets define a database and register it to our datastore.

import Database from"framework/alto/data/database";

let TodosDatabase = Database.extend ({

remote: 'https://todos.com/api/todos',

partition: {},

schema: {

id: Number,

title: String,

primaryKey('id')

}

});

export default TodosDatabase

import Datastore from"framework/alto/data/datastore";
import TodosDatabase from "application/data/database/todos";

let applicationDatastore = Datastore.create ({

todos: {

controller: TodoController,

database: TodosDatabase

}

});

export default applicationDatastore;

Next, create a query and use it to find a record in our store.

import Query from"framework/alto/data/query";

let query = Query.create({

store: 'todos',

criteria: 'id=17'

});

query.find();

When we run a query. Our store will first look at our databases local partition. If todo with id 17 is found on the local partition, our store will load the result(s) into our controller. If not, the store will attempt to find the item from the remote server. After the store resolves the network call for todo with id 17, our store will load the result(s) into our controller. When a controller receives an update, a view that is bound to the controller with a property binding, automatically updates.

UI

Built on-top of React.js. The UI framework consists of observable components that are easy to theme, easy to refactor data connections, and are easy to share.

import React from"react";
import LabelView from"framework/alto/ui/label-view";
import TodoController from"application/controllers/todo_controller.js";

let TodoView = () => {

return (
<LabelView titleBinding={{controller: TodoController, key:'title'}}}/>
)

};