The Plus Framework

Main goal of the Plus is to provide declarative data binding facilities - data (model) can be bound with its HTML representation in various ways.

Model declaration, the model attribute

Any DOM element-container can be linked with some namespace (object) that contains data (a.k.a. model) to be viewed inside the container. Such a link is established by special model attribute:

<body model="MyDataNamespace">
   ...
</body>

And if you have in your script this:

namespace MyDataNamespace {
   ...
}

then content of the body element (in this case) can be linked (bound) with the data in MyDataNamespace.

Topmost element that has such model attribute is known as a data model view - elements bound with the model data namespace / object reflect state of the data.

Bound elements

Element's value can be bound with some variable in the model. +plus framework uses attribute name that shall contain name or expression to bind with.

<body model="Data">
  <p>Whom to greet: <input|text(greeting) /></p>
  <p>Greeting: Hello <output(greeting) />!</p>
</body>

Two elements above are bound with the same variable Data.greeting in the model. Changes in the <input> element are reflected in the <output> element.

Normally data variable is bound with the value property of linked element directly. But if the element has setBoundValue(newVal) defined (on it or its behavior class) then the function will be called to set the value.

Bound attributes

Sciter also suppports attribute value binding with variables and object properties. To define bound attribute simply add '@' character in front of its name and provide variable name or expression as a value of the attribute:

<li><picture @src="customer.image" /> <output(customer.name)/></li>

Here src attribute will be bound with customer.image variable and the ouput will contain value of customer.name variable.

There are bound attributes that are mapped to state flags:

Repeatables

each repeatable

Any container may have attribute each="item in items" defined. In this case initial content of the container is used as a template markup that will be repeated for each element in items collection. Format of the each attribute:

[{index},]{item} in {items-expression} [ | {filter-expression}

where:

Example of the list that renders myCustomers items as list items:

  <ol each="customer in myCustomers">
      <li><picture @src="customer.image" /> <output(customer.name)/></li>
  </ol>

Example of list with filter function:

  <ol each="customer in myCustomers|myFilterFunction">
      <li><picture @src="customer.image" /> <output(customer.name)/></li>
  </ol>

Note that myFilter name gets resolved to myFilter variable / function defined in closest namespace to myCustomers

repeat repeatable

This kind of repeatable uses repeat attribute on the element that itself needs to be replicated: 

 <ol>
   <li repeat="customer in myCustomers">
      <picture @src="customer.image" /> <output(customer.name)/>
   </li> 
 </ol>

Where repeat attribute uses the same syntax as each above. 

In some cases repeat form of the repeatable is more convenient than each. 

Observing changes on data paths

The Plus defines @observing decorator that can be used to subscribe functions on particular changes in model data tree. Syntax of declaring such subscriptions:

@observing "path" ["path2"[, ... "pathN" ]] 
  function(path) {
      
  }

Where path is a string separated by . (dot) and [] (if element on the path is an array).

The function gets called with this set to rightmost object or array on the path.

Example:

namespace Data 
{ 
   var items = [
       { name:"Alan", state: true },
       { name:"Winston", state: false }
   ];

   @oberving "items[].state" function() {
      // .state property was changed in one of items
      // 'this' here is the item
   }
}

Basic event handlers

Elements may contain one of event attributes defining function to be executed on corresponding action. The handler function is called with this set to the DOM element and first parameter set to bound object.

List of event attributes: "click", "dblclick", "change", "enter", "escape", "focusin", "focusout".

Example:

  <b click="items.removeByValue(item)">x</b>

Click on such <b> element will call items.removeByValue() function passing it current item object.

Sub-models

Main data model view element may have inner elements with model attribute - sub-views that are looking on parts of data tree.

namespace MyDataNamespace
{
  var records = [ {name: "first", ...},
{name: "second", ...}, {name: "third", ...} ]; var currentRecord = {}; // used as sub-model; // function to set current record function setCurrentRecord(index) { currentRecord = records[index]; } }

Having such a model we can define sub-view element looking on sub-object or namespace inside the model ():

<body model="MyDataNamespace">
   <!-- records list -->
   <ol each="index,record in records">
      <li><output(record.name) click="setCurrentRecord(index)" /></li>
   </ol>
   <!-- current record view -->
   <section #record-details-view model="currentRecord">
      <input(name) />
      ...
   </section>
</body>

Sub-view elements are observing change of [sub-] model variable, therefore as soon as the variable changes all observing elements get rebound with new data.

In the example above click on the output(name) element in the list will cause currentRecord to be set to new object by calling  setCurrentRecord() on click. See demos/L-list-detail.htm example.