/jsviews

Interactive data-driven views, MVVM and MVP, built on top of JsRender templates

Primary LanguageJavaScriptOtherNOASSERTION

JsViews: next-generation MVVM and MVP framework - bringing templates to life

The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates and jQuery

JsViews builds on top of JsRender templates, and adds data-binding and observable data, to provide a fully-fledged MVVM platform for easily creating interactive data-driven single-page apps and websites.

Documentation and downloads

**[Documentation](http://www.jsviews.com/#jsviews)**, **[downloads](http://www.jsviews.com/#download)**, **[samples](http://www.jsviews.com/#samples)** and **[API docs and tutorials](http://www.jsviews.com/#jsvapi)** are available on the **[www.jsviews.com website](http://www.jsviews.com/#jsviews)**.

The content of this ReadMe is available also as a JsViews Quickstart.

JsViews installation

jsviews.js is available from downloads on the jsviews.com site.

CDN delivery is available from the cdnjs CDN at cdnjs.com/libraries/jsviews.

Alternatively:

(Note that jsviews.js includes all of jsrender.js code -- so jsrender.js does not need to be loaded first.)

JsRender and JsViews

JsRender is used for data-driven rendering of templates to strings, ready for insertion in the DOM. (See JsRender Quickstart and JsRender GitHub repository).

JsViews incorporates JsRender templates, together with data-binding, observable data and MVVM support. It provides a powerful platform for building dynamic interactive websites and single-page apps.

(Note: JsRender and JsViews together provide the next-generation implementation of the official jQuery plugins JQuery Templates, and JQuery Data Link -- and supersede those libraries.)

JsViews usage

Data-linked templates

JsViews provides data-linking - so that JsRender templates become data-bound:

  • Data-linked tags or elements in your templates will update automatically whenever the underlying data changes.
  • Some data-linked tags or elements provide two-way data-linking, so that user interactions will trigger "observable" changes to the underlying data (which may then trigger other updates elsewhere in your templated UI).

Data-linked template tags:

Any JsRender tag, {{...}} can be data-linked by writing {^{...}}, as in:

<ul>
  {^{for people}} <!--List will update when people array changes-->
    <li>{^{:name}}</li> <!--Will update when name property changes-->
  {{/for}}
</ul>

Learn more...

Data-linked HTML elements:

HTML elements within templates can be data-linked by adding a data-link attribute:

<input data-link="name"/> <!--Two-way data-binding to the name property-->
<span data-link="name"></span> <!--Will update when name property changes-->

HTML elements within 'top-level' page content can also be data-linked -- see below.

Learn more...

Render and link a template

With JsRender, you call the render() method, then insert the resulting HTML in the DOM.

var html = tmpl.render(data, helpersOrContext);
$("#container").html(html);

With JsViews, you can instead call the link() method:

tmpl.link("#container", data, helpersOrContext);

which in one line of code will:

  • render the template
  • insert the resulting HTML as content under the HTML container element
  • data-link that content to the underlying data

Now observable changes in the data will automatically trigger updates in the rendered UI.

There are two ways of calling the link() method:

Example: - Template from string

var tmpl = $.templates("{^{:name}} <input data-link='name' />");
var person = {name: "Jim"};
tmpl.link("#container", person);

Example: - Template from script block

<script id="myTemplate" type="text/x-jsrender">
{^{:name}} <input data-link="name" />
</script>
var tmpl = $.templates("#myTemplate");
var person= {name: "Jim"};
tmpl.link("#container", person);

Example: - Named template from string

$.templates("myTmpl1", "{^{:name}} <input data-link='name' />");
var person= {name: "Jim"};
$.link.myTmpl1("#container", person);

Example: - Named template from script block

<script id="myTemplate" type="text/x-jsrender">
{^{:name}} <input data-link="name" />
</script>
$.templates("myTmpl2", "#myTemplate");
var data = {name: "Jim"};
$.link.myTmpl2("#container", data);

Result: After each link() example above the container element will have the following content:

Jim <input value="Jim" />

with the name property of person object data-linked to the "Jim" text node and two-way data-linked to the <input />

See: Playing with JsViews for working samples, such as this one

Learn more...

You can use data-linking not only for templated content, but also to data-bind to top-level HTML content in your page:

$.link(true, "#target", data);

This will activate any declarative data-binding (data-link="..." expressions) on the target element - or on elements within its content.

Learn more...

Making "observable" changes to objects and arrays

In current JavaScript implementations, modifying objects or arrays does not raise any event, so there is no way for the change to be detected elsewhere. JsViews dynamic data-bound UI solves this through data-linking, using the JsObservable observer pattern.

The JsViews $.observable() API provides a way for you to change objects or arrays observably. Each change will raise a property change or array change event.

Modify an object observably

$.observable(person).setProperty("name", newName);

$.observable(person) makes the person object "observable", by providing a setProperty(...) method. Use setProperty to change a value, and the change will be "observed" by the declarative data-binding in the template.

Modify an array observably

$.observable(people).insert(newPerson);

$.observable(people) makes the people array "observable", by providing methods like insert(...) and remove(...). Use them to make changes to arrays, and the changes will be "observed" by data-bound elements and tags in the template - such as the {^{for dataArray}} tag.

Learn more...

Responding to data changes

JsViews uses the property change or array change events to make any data-linked tags or elements in your templates update automatically in response to each observable change in your underlying data. In addition, with two-way data-linking, it ensures that those events are raised when the user interacts with a data-linked template, and causes changes to the underlying data.

observe() and observeAll()

The $.observe() and $.observable().observeAll() APIs make it very easy for you to register event handlers or listeners, so your code can listen to specific observable changes made to your data objects or view models:

$.observe(person, "name", function(...) {
  // The "name" property of person has changed
  ...
});
$.observable(person).observeAll(function(...) {
  // A property of person, or a nested object property, has changed
  ...
});

Learn more...

Accessing the view hierarchy

Each instance of a rendered template or a template block tag is associated with a JsViews "view" object -- so nested tags lead to a hierarchy of view objects. The view hierarchy shows how the underlying data objects map to the rendered UI.

From UI back to data:

Use $.view(elem) to get from a DOM element to the corresponding view object for that part of the rendered content. From the view you can then get to the underlying data, the index, etc.

Example:

{^{for people}}
  ...
  <button class="changeBtn">Change</button>
  ...
{{/for}}

Click-handler code for Change button:

$(".changeBtn").on("click", function() {
  // From the clicked HTML element ('this'), get the view object
  var view = $.view(this);

  // Get the 'person' data object for clicked button
  var person = view.data;

  // Get index of this 'item view'. (Equals index of person in people array)
  var index = view.index;

  // Change the person.name
  $.observable(person).setProperty("name", person.name + " " + index);
});

Learn more...

Data-linked paths

JsViews data-linked templates (and the $.observe() API) use the same paths and expressions as JsRender templates, but in addition provide 'leaf' data-binding -- such as:

{^{:team.manager.name`}}                    <!--updates when name changes-->
<span data-link="team.manager.name"></span> <!--updates when name changes-->
<input data-link="team.manager.name" />     <!--two-way binding to name-->

But data-linked paths have additional support, such as linking deeper into paths:

{^{:team^manager.name}}   <!--updates when name, manager, or team changes-->

Learn more...

Computed observables

JsViews also allows you to data-bind to computed values, such as:

{^{:shoppingCart.totalAmount()}}        <!--updates when totalAmount() changes-->
<input data-link="person.fullName()" /> <!--two-way binding, computed fullName()-->

Learn more...

Documentation and APIs

See the www.jsviews.com site, including the JsViews Quickstart, JsViews APIs and JsObservable APIstopics.

Demos

Demos and samples can be found at [www.jsviews.com/#samples](http://www.jsviews.com/#samples), and throughout the [API documentation](http://www.jsviews.com/#jsvapi).

(See also the demos folder of the GitHub repository - available here as live samples).