UNPKG

jsviews

Version:

Next-generation MVVM and MVP framework - built on top of JsRender templates. Bringing templates to life...

291 lines (189 loc) 12.5 kB
## JsViews: next-generation MVVM and MVP framework - bringing templates to life [![CDNJS version](https://img.shields.io/cdnjs/v/jsviews.svg)](https://cdnjs.com/libraries/jsviews) *The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates and jQuery*<br/> **JsViews** builds on top of **[JsRender](http://www.jsviews.com/#jsrender)** templates, and adds data-binding and **[observable data](http://www.jsviews.com/#jsobservable)**, 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](http://www.jsviews.com/#jsv-quickstart)*. ## JsViews installation jsviews.js is available from [downloads](http://www.jsviews.com/#download) on the jsviews.com site. CDN delivery is available from the **_[cdnjs](https://cdnjs.com)_** CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews). Alternatively: - It can be installed with **_[Bower](http://bower.io/search/?q=jsviews)_**, using `$ bower install jsviews` - It can be loaded using an *AMD script loader*, such as RequireJS - For installation using *Node.js* (*npm*), and loading using [Browserify](http://browserify.org/) or [webpack](https://webpack.github.io/), see *[JsViews as a Browserify module](http://www.jsviews.com/#node/browserify@jsviews)* and *[JsViews as a webpack module](http://www.jsviews.com/#node/webpack@jsviews)* (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](http://www.jsviews.com/#jsr-quickstart)* and [JsRender GitHub repository](https://github.com/BorisMoore/jsrender)). *JsViews* incorporates *JsRender* templates, together with data-binding, *[observable data](http://www.jsviews.com/#jsoapi)* 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](https://github.com/BorisMoore/jquery-tmpl)*, and *[JQuery Data Link](https://github.com/BorisMoore/jquery-datalink)* -- 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: ```html <ul> {^{for people}} <!--List will update when people array changes--> <li>{^{:name}}</li> <!--Will update when name property changes--> {{/for}} </ul> ``` [Learn more...](http://www.jsviews.com/#linked-tag-syntax) **Data-linked HTML elements:** HTML elements within templates can be *data-linked* by adding a `data-link` attribute: ```html <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](#jsv-quickstart@toplink). [Learn more...](http://www.jsviews.com/#linked-elem-syntax) ## _Render and link a template_ With *JsRender*, you call the `render()` method, then insert the resulting HTML in the DOM. ```js var html = tmpl.render(data, helpersOrContext); $("#container").html(html); ``` With *JsViews*, you can instead call the `link()` method: ```js 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: - If you have a reference to the <em>template object</em>, call [`template.link(...)`](http://www.jsviews.com/#jsvtmpllink) - If you have registered the template by name (`"myTmpl"`), call [`link.myTmpl(...)`](http://www.jsviews.com/#jsv.d.link) **Example**: - Template from string ```js var tmpl = $.templates("{^{:name}} <input data-link='name' />"); var person = {name: "Jim"}; tmpl.link("#container", person); ``` **Example**: - Template from script block ```html <script id="myTemplate" type="text/x-jsrender"> {^{:name}} <input data-link="name" /> </script> ``` ```js var tmpl = $.templates("#myTemplate"); var person= {name: "Jim"}; tmpl.link("#container", person); ``` **Example**: - Named template from string ```js $.templates("myTmpl1", "{^{:name}} <input data-link='name' />"); var person= {name: "Jim"}; $.link.myTmpl1("#container", person); ``` **Example**: - Named template from script block ```html <script id="myTemplate" type="text/x-jsrender"> {^{:name}} <input data-link="name" /> </script> ``` ```js $.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: ```html 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](http://www.jsviews.com/#jsvplaying)* for working samples, such as [this one](http://www.jsviews.com/#jsvplaying@twoway) [Learn more...](http://www.jsviews.com/#jsvlinktmpl) <h3 id="jsv-quickstart@toplink"><i>Top-level data-linking</i></h3> You can use data-linking not only for templated content, but also to data-bind to top-level HTML content in your page: ```js $.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...](http://www.jsviews.com/#toplink) ### _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 <em>data-linking</em>, using the <em>JsObservable observer pattern</em>. The JsViews `$.observable()` API provides a way for you to change objects or arrays <em>observably</em>. Each change will raise a <a href="http://www.jsviews.com/#onpropchange">property change</a> or <a href="http://www.jsviews.com/#onarrchange">array change</a> event. **Modify an object observably** ```js $.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** ```js $.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...](http://www.jsviews.com/#$observable) ### _Responding to data changes_ JsViews uses the *<a href="http://www.jsviews.com/#onpropchange">property change</a>* or *<a href="http://www.jsviews.com/#onarrchange">array change</a>* events to make any <a href="http://www.jsviews.com/#linked-template-syntax">data-linked tags or elements</a> 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()`](http://www.jsviews.com/#observe) and [`$.observable().observeAll()`](http://www.jsviews.com/#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: ```js $.observe(person, "name", function(...) { // The "name" property of person has changed ... }); ``` ```js $.observable(person).observeAll(function(...) { // A property of person, or a nested object property, has changed ... }); ``` [Learn more...](http://www.jsviews.com/#observeobjectsarrays) ### _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](http://www.jsviews.com/#views) shows how the underlying data objects map to the rendered UI. **From UI back to data:** Use [`$.view(elem)`](http://www.jsviews.com/#jsv.d.view) 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](http://www.jsviews.com/#jsv.d.view@$view):* ```html {^{for people}} ... <button class="changeBtn">Change</button> ... {{/for}} ``` Click-handler code for <em>Change</em> button: ```js $(".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...](http://www.jsviews.com/#$view) ### _Data-linked paths_ JsViews data-linked templates (and the `$.observe()` API) use the same [paths and expressions](http://www.jsviews.com/#paths) as JsRender templates, but in addition provide *'leaf'* data-binding -- such as: ```html {^{: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: ```html {^{:team^manager.name}} <!--updates when name, manager, or team changes--> ``` [Learn more...](http://www.jsviews.com/#linked-paths) ### _Computed observables_ JsViews also allows you to data-bind to computed values, such as: ```html {^{:shoppingCart.totalAmount()}} <!--updates when totalAmount() changes--> <input data-link="person.fullName()" /> <!--two-way binding, computed fullName()--> ``` [Learn more...](http://www.jsviews.com/#computed) ### _Documentation and APIs_ See the [www.jsviews.com](http://www.jsviews.com) site, including the *[JsViews Quickstart](http://www.jsviews.com/#jsv-quickstart)*, [JsViews APIs](http://www.jsviews.com/#jsvapi) and [JsObservable APIs](http://www.jsviews.com/#jsoapi) topics. ### _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](https://github.com/BorisMoore/jsviews/tree/master/demos) folder of the GitHub repository - available [here](http://borismoore.github.io/jsviews/demos/index.html) as live samples).