Skip to content

Commit

Permalink
Commit 71 (v0.9.71 - Beta)
Browse files Browse the repository at this point in the history
- Many jsviews.com documentation improvements - including new JsViews
  Quickstart, and additional JsViews API topics.

- New "Search" feature on jsviews.com.
  (BorisMoore/jsviews.com#2 and
  BorisMoore/jsrender#274)

- #322: view.get(true)
  now returns the first inner (child) view (of any type)

- Added support for {else} in data-link expressions when doing
  top-level data-linking: data-link="{if a tmpl='yes'}{else tmpl='no'}"
  http://jsviews.com#search?s=%7D%7Belse%20tmpl%3D&l=linked-elem-syntax@0

- Simplified API for unlink:
  $(selector).unlink() replaces previous API: $(selector).unlink(true).
  $.unlink(selector) replaces previous API: $.unlink(true, selector).

- link methods on tags and views are only added if linked.

- Added support for <label> wrapping radio buttons in data-linked radio
  button group - so you can click on the label to change the radio button
  selection.
  Example: http://www.jsviews.com/#samples/tag-controls/edit/array-binding

Minor breaking change:
- {{mytag tmpl="foo"}} - "foo" template now replaces or wraps the content,
  as previously, but unlike previously, does not take precedence over a
  template declared in the tag definition. That template is still used to
  render {{mytag}}, but if it includes content, as {{include tmpl=#content/}},
  then the "foo" template will replace the rendered block content
  {{mytag}}...{{/mytag}}, or can itself wrap any block content using
  {{include tmpl=#content/}}

- Bug fixes:
  #326
  #329
  • Loading branch information
BorisMoore committed Dec 21, 2015
1 parent b4de844 commit cdaa002
Show file tree
Hide file tree
Showing 17 changed files with 1,201 additions and 734 deletions.
247 changes: 233 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,239 @@
## 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_<br/>
## 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*<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.
**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.

**JsRender** and **JsViews** together provide the next-generation implementation of both _JQuery Templates_, and _JQuery Data Link_ - and supersede those libraries.
<h3>Documentation and Downloads</h3>
**[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)**.

See also the _[JsRender](https://github.com/BorisMoore/jsrender)_ repository on GitHub<br/>
The content of this ***ReadMe*** is available also as a *[JsViews Quickstart](http://www.jsviews.com/#jsv-quickstart)*.

<h3>Documentation and Downloads</h3>
**[Documentation](http://www.jsviews.com/#jsviews)**, **[downloads](http://www.jsviews.com/#download)**,
**[samples](http://www.jsviews.com/#samples)** are available on the **[www.jsviews.com website](http://www.jsviews.com/#jsviews)**.
<br/>(JsViews and JsObservable **API docs and tutorials** are coming soon, as we move JsViews to the official beta and on to V1.0)
<h3>JsRender and JsViews</h3>
**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)).

**[JsRender](https://github.com/BorisMoore/jsrender)** and **[JsViews](https://github.com/BorisMoore/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.

<h2>JsViews Usage</h2>

<h3><i>Data-linked templates</i></h3>

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)

<h3><i>Render and link a template</i></h3>

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)

<h3><i>Making "observable" changes to objects and arrays</i></h3>

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)

<h3><i>Responding to data changes</i></h3>

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)

<h3><i>Accessing the view hierarchy</i></h3>

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)

<h3><i>Documentation and APIs</i></h3>

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.

<h3>Demos</h3>
In addition to the demos at [www.jsviews.com/#samples](http://www.jsviews.com/#samples), see also the [demos](https://github.com/BorisMoore/jsviews/tree/master/demos) folder of this GitHub repository - available [here](http://borismoore.github.io/jsviews/demos/index.html) as live samples.
<h3><i>Demos</i></h3>
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).

<h3>Current Status</h3>
JsViews is now a beta candidate release, which will be declared beta as soon as API documentation is complete on the [www.jsviews.com](http://www.jsviews.com) website, and then move to V1.0.
(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).
6 changes: 4 additions & 2 deletions demos/features/observability/computed-helper.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ <h3>Computed observables as helper functions (with declared dependencies, and op
// Setter for fullName - for two-way binding
fullName.set = function(val) {
val = val.split(" ");
$.observable(person).setProperty({
// The this pointer is the view, so this.data is the current data item
$.observable(this.data).setProperty({
lastName: val.pop(),
firstName: val.join(" ")
});
Expand Down Expand Up @@ -159,7 +160,8 @@ <h4>Script:</h4>

// For two-way binding of computed observables, provide a setter
fullName.set = function(val) {
$.observable(this).setProperty({
// The this pointer is the view, so this.data is the current data item
$.observable(this.data).setProperty({
lastName: ...,
firstName: ...
});
Expand Down
17 changes: 13 additions & 4 deletions jquery.observable.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*! JsObservable v1.0.0-beta.70 (Beta Candidate): http://jsviews.com/#jsobservable */
/*! JsObservable v0.9.71 (Beta): http://jsviews.com/#jsobservable */
/*
* Subcomponent of JsViews
* Data change events for data-linking
Expand Down Expand Up @@ -751,6 +751,9 @@ if (!$.observe) {
if ($isFunction(property)) {
if (property.set) {
// Case of property setter/getter - with convention that property is getter and property.set is setter
leaf = leaf._wrp // Case of JsViews 2-way data-linking to a helper function as getter, with a setter.
// The view will be the this pointer for getter and setter. Note: this is the one scenario where path is "".
|| leaf;
getter = property;
setter = property.set === true ? property : property.set;
property = property.call(leaf); // get - only treated as getter if also a setter. Otherwise it is simply a property of type function. See unit tests 'Can observe properties of type function'.
Expand All @@ -764,12 +767,18 @@ if (!$.observe) {
setter.call(leaf, value); //set
value = getter.call(leaf); //get updated value
} else if (removeProp = value === remove) {
delete leaf[path];
value = undefined;
if (property !== undefined) {
delete leaf[path];
value = undefined;
} else {
path = undefined; // If value was already undefined, don't trigger handler for removeProp
}
} else if (path) {
leaf[path] = value;
}
this._trigger(leaf, {change: "set", path: path, value: value, oldValue: property, remove: removeProp});
if (path) {
this._trigger(leaf, {change: "set", path: path, value: value, oldValue: property, remove: removeProp});
}
}
}
},
Expand Down
Loading

0 comments on commit cdaa002

Please sign in to comment.