Technology Overview
Learn the basics of CanJS’s technology.
Overview
CanJS, at its most simplified, consists of key-value observables connected to web browser APIs using various libraries.
The general idea is that you create observable objects that encapsulate the logic and state of your application and connect those observable objects to:
- The Document Object Model (DOM) to update your HTML automatically.
- The browser URL to support the forward and back buttons through Routing.
- Your service layer to make receiving, creating, updating, and deleting service data easier.
Instead of worrying about calling the various browser APIs, CanJS abstracts this away, so you can focus on the logic of your application. The logic of your application is contained within observables.
The rest of this page walks through the basics of observables and brief examples of connecting observables to browser APIs. For a deeper dive, please read through the HTML, Routing and Service Layer guides.
Key-Value Observables
The ObservableObject and ObservableArray observables define the logic and state in your application. For example, the following uses ObservableObject to:
- Model a simple
Counter
type. - Create instances of
Counter
, call its methods, and inspect its state.
myCounter
is an instance of Counter
. myCounter.count
is part of the state of the myCounter
instance. myCounter.increment
is part of the logic that controls the
state of myCounter
.
myCounter
is an observable because you can listen to when
its state changes. The following uses listenTo
to log each time the count changes:
ObservableArray creates observable lists. Observable lists are most commonly
used with the service layer. The following
defines a Counters
list type. Instances of Counters
will have a sum
property that returns the sum of
each Counter
within the list:
NOTE: CanJS application logic is coded within instances of ObservableObject and ObservableArray. You often don’t need the DOM for unit testing!
ObservableObject and ObservableArray have a wide variety of features and shorthands for defining property behavior. For more information about how to write logic within CanJS’s observables read the ObservableObject Use section and the DefinitionObject documentation.
Observables and HTML elements
CanJS applications use Components to connect observables
to a page's HTML elements. We can use StacheElement to create a counting widget
for the Counter
observables we just created.
The following widget counts the number of times the button is clicked:
- Demo
- HTML
- JS
In CanJS, widgets are encapsulated with custom elements. Custom elements allow us to put an
element in our HTML like <my-counter></my-counter>
, and the widget will spring to life.
The previous demo defines its view
and ViewModel
as separate entities. However,
a Component's ViewModel and view are typically defined inline as follows:
You might have noticed that StacheElements are mostly 2 parts:
- A view that specifies the HTML content within the custom element. In this case, we’re adding a
<span>
and a<button>
within the<my-counter>
element. Magic tags like{{count}}
are provided by stache and bindings likeon:click
are provided by stacheBindings. - Properties that manages the logic and state of the application.
These work together to receive input from the user, update the state of the application, and then update the HTML the user sees accordingly. See how in this 2 minute video:
For more information on how to connect observables to the DOM, read the HTML guide.
Observables and the browser's location
CanJS applications use route (or mixin RoutePushstate) to connect an observable to the browser's URL. The observable acts like a key-value store of the data in the URL.
The following example shows that:
- When the observable state updates, the URL changes.
- When the URL changes, the observable state updates.
The following shows the browser's forward and back buttons connected to the <my-counter>
Component's observable state. Click +1
a few times, then click
the forward (⇦
) and back (⇨
) buttons to see the count change:
- Demo
- HTML
- JS
Notice how the URL changes when you click the +1
button AND the Count changes when the
forward and back button are clicked.
The following connects the <my-counter>
to the browser's URL:
Use route.register to create routing rules.
Instead of URLs like #!&count=1
, #!&count=2
, #!&count=3
;
the following changes the URLs to look like #!1
, #!2
, #!3
:
For more information on how to connect observables to the browser's URL, read the Routing guide.
Observables and the service layer
CanJS applications use models to connect
observables to backend services. For example,
lets say the service layer is providing a JSON list of todo data at /api/todos
. The
response looks like:
The following loads this list of data and logs it to the console by:
- Defining an observable data type to represent individual todos (
Todo
). - Defining an observable data type to represent a list of todos (
Todo.List
). - Connecting those observable data types to the RESTFUL service layer with restModel.
- Using the getList method mixed-into the
Todo
type to get the todos from the server and log them to the console.
The following lists the todos in the page by defining a <todo-list>
component
that:
- Gets a promise that resolves to a list of all todos with
Todo.getList({})
. - Loops through the list of todos and creates an
<li>
for each one with{{# for(todo of todosPromise.value) }}
.
You can do a lot more with CanJS’s data layer besides showing a list of data. Read the Service Layer guide for more information on how to:
- Create, update and delete data.
- Automatically insert or remove items from lists when data is created, updated or deleted (automatic list management).
Next Steps
Now that you've got a rough idea idea on the major pieces of CanJS, we suggest: