Autosync
work with data, not with DOM
Download
autosync.jsStandard version: IE 9+, Firefox 4.0+, Opera 12.1+, Chrome 5.0+
autosync-compat.jsExtended version: IE 6+, Firefox 1.0+, Opera 8.0+
Components

Components provide a way to extract large template fragments into reusable modules and attach all the neccessary methods to them (methods of the closest component are looked first when a user function is found in a condition or event handler). Now component is a plain object with template and funcs properties, which is added to the as.components object by key:


as.components['items-list'] = {
   template: '
  • {$value['title']}
', funcs: { handleClick: function(event) { console.log('Click!') } } }

Then you can use the component in any template as a custom element:


<div asmodel="data.tasks">
   /* ... */
   <items-list></items-list>
   /* ... */
</div>
               
Recursion

You can reference the component itself inside its template if your application logic requires that. Be careful though not to end up in infinite recursion doing this.

For example, an ideal option will be calling the component inside a collection rendering template: in real data you won't get infinite depth nesting, and eventually the recursion will stop on an empty list.

In order for the recursion to work you will have to use relative object paths. Take a look at the following example:


as.components['items-list'] = {
   template: '<ul asmodel=".items">\
      <li">{$value[\'title\']}</li>\
   </ul>'
}

var data = { items:
   [
      { title: 'Food', items:
         [
            { title: 'Apples', items: [] },
            { title: 'Cookies', items: [] },
            { title: 'Fish', items:
               [
                  { title: 'Salmon', items: [] },
                  { title: 'Herring', items: [] }
               ]
            },
            { title: 'Water', items: [] }
         ]
      },
      { title: 'Other', items:
         [
            { title: 'Wash powder', items: [] },
            { title: 'Paper towels', items: [] }
         ]
      }
   ]
}
               

<h1>Shopping list</h1>       
<ul asmodel="data.items">
   <li>
      <div>{$value['title']}</div>
      <items-list></items-list>
   </li>
</ul>
               

Notice how by rewriting the model and the template slightly you can make the list header the root element of the structure:


var data = { items:
   [
      { title: 'Shopping list', items:
         [
            { title: 'Food',  items: [ /* ... */ ] },
            { title: 'Other', items: [ /* ... */ ] }
         ]
      }
   ]
}
               
   
<ul asmodel="data.items">
   <li>
      <div>{$value['title']}</div>
      <items-list></items-list>
   </li>
</ul>
               
Template references

If you only need recursion and don't need methods, you can implement the above example without creating a component. Autosync supports the special asref attribute for that:


<div asmodel="data">
   <h1>Shopping list</h1>       
   <ul asmodel=".items" asref="items-list">
      <li>
         <div>{$value['title']}</div>
         <items-list></items-list>
      </li>
   </ul>
</div>
               

When Autosync encounters this attribute, it will automatically create a component with a template equal to outerHTML of the given element.

If the data comes from the server with the "redundant" root element, but you don't want to do data transformation on receive, you can set asmodel to data.items.0 in the outmost template, because integer number indexes are totally correct keys for Autosync.