Skip to content

Commit cdaa002

Browse files
committed
Commit 71 (v0.9.71 - Beta)
- 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
1 parent b4de844 commit cdaa002

17 files changed

+1201
-734
lines changed

README.md

Lines changed: 233 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,239 @@
1-
## JsViews: Next-generation MVVM and MVP framework - bringing templates to life
2-
_The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates and jQuery_<br/>
1+
## JsViews: next-generation MVVM and MVP framework - bringing templates to life
2+
*The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates and jQuery*<br/>
33

4-
**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
5-
page apps and websites.
4+
**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.
65

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

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

11-
<h3>Documentation and Downloads</h3>
12-
**[Documentation](http://www.jsviews.com/#jsviews)**, **[downloads](http://www.jsviews.com/#download)**,
13-
**[samples](http://www.jsviews.com/#samples)** are available on the **[www.jsviews.com website](http://www.jsviews.com/#jsviews)**.
14-
<br/>(JsViews and JsObservable **API docs and tutorials** are coming soon, as we move JsViews to the official beta and on to V1.0)
11+
<h3>JsRender and JsViews</h3>
12+
**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)).
13+
14+
**[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.
15+
16+
<h2>JsViews Usage</h2>
17+
18+
<h3><i>Data-linked templates</i></h3>
19+
20+
JsViews provides *data-linking* - so that JsRender templates become data-bound:
21+
22+
- *Data-linked* tags or elements in your templates will update automatically whenever the underlying data changes.
23+
- 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).
24+
25+
**Data-linked template tags:**
26+
27+
Any JsRender tag, `{{...}}` can be *data-linked* by writing `{^{...}}`, as in:
28+
29+
```html
30+
<ul>
31+
{^{for people}} <!-- List will update when people array changes -->
32+
<li>{^{:name}}</li> <!-- Will update when name property changes -->
33+
{{/for}}
34+
</ul>
35+
```
36+
37+
[Learn more...](http://www.jsviews.com/#linked-tag-syntax)
38+
39+
**Data-linked HTML elements:**
40+
41+
HTML elements within templates can be *data-linked* by adding a `data-link` attribute:
42+
43+
```html
44+
<input data-link="name"/> <!-- Two-way data-binding to the name property -->
45+
<span data-link="name"></span> <!-- Will update when name property changes -->
46+
```
47+
48+
HTML elements within 'top-level' page content can also be data-linked -- see [below](#jsv-quickstart@toplink).
49+
50+
[Learn more...](http://www.jsviews.com/#linked-elem-syntax)
51+
52+
<h3><i>Render and link a template</i></h3>
53+
54+
With *JsRender*, you call the `render()` method, then insert the resulting HTML in the DOM.
55+
56+
```js
57+
var html = tmpl.render(data, helpersOrContext);
58+
$("#container").html(html);
59+
```
60+
61+
With *JsViews*, you can instead call the `link()` method:
62+
63+
```js
64+
tmpl.link("#container", data, helpersOrContext);
65+
```
66+
67+
which in one line of code will:
68+
- render the template
69+
- insert the resulting HTML as content under the HTML `container` element
70+
- data-link that content to the underlying `data`
71+
72+
Now *observable* changes in the data will automatically trigger updates in the rendered UI.
73+
74+
There are two ways of calling the `link()` method:
75+
- If you have a reference to the <em>template object</em>, call [`template.link(...)`](http://www.jsviews.com/#jsvtmpllink)
76+
- If you have registered the template by name (`"myTmpl"`), call [`link.myTmpl(...)`](http://www.jsviews.com/#jsv.d.link)
77+
78+
**Example**: - Template from string
79+
80+
```js
81+
var tmpl = $.templates("{^{:name}} <input data-link='name' />");
82+
var person = {name: "Jim"};
83+
tmpl.link("#container", person);
84+
```
85+
86+
**Example**: - Template from script block
87+
88+
```html
89+
<script id="myTemplate" type="text/x-jsrender">
90+
{^{:name}} <input data-link="name" />
91+
</script>
92+
```
93+
94+
```js
95+
var tmpl = $.templates("#myTemplate");
96+
var person= {name: "Jim"};
97+
tmpl.link("#container", person);
98+
```
99+
100+
**Example**: - Named template from string
101+
102+
```js
103+
$.templates("myTmpl1", "{^{:name}} <input data-link='name' />");
104+
var person= {name: "Jim"};
105+
$.link.myTmpl1("#container", person);
106+
```
107+
108+
**Example**: - Named template from script block
109+
110+
```html
111+
<script id="myTemplate" type="text/x-jsrender">
112+
{^{:name}} <input data-link="name" />
113+
</script>
114+
```
115+
116+
```js
117+
$.templates("myTmpl2", "#myTemplate");
118+
var data = {name: "Jim"};
119+
$.link.myTmpl2("#container", data);
120+
```
121+
122+
**Result:** After each `link()` example above the `container` element will have the following content:
123+
124+
```html
125+
Jim <input value="Jim" />
126+
```
127+
128+
with the `name` property of `person` object data-linked to the `"Jim"` text node and *two-way* data-linked to the `<input />`
129+
130+
See: [Playing with JsViews](http://www.jsviews.com/#jsvplaying) for working samples, such as [this one](http://www.jsviews.com/#jsvplaying@twoway)
131+
132+
[Learn more...](http://www.jsviews.com/#jsvlinktmpl)
133+
134+
<h3 id="jsv-quickstart@toplink"><i>Top-level data-linking</i></h3>
135+
136+
You can use data-linking not only for templated content, but also to data-bind to top-level HTML content in your page:
137+
138+
```js
139+
$.link(true, "#target", data);
140+
```
141+
142+
This will activate any declarative data-binding (`data-link="..."` expressions) on the target element - or on elements within its content.
143+
144+
[Learn more...](http://www.jsviews.com/#toplink)
145+
146+
<h3><i>Making "observable" changes to objects and arrays</i></h3>
147+
148+
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>.
149+
150+
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.
151+
152+
**Modify an object observably**
153+
154+
```js
155+
$.observable(person).setProperty("name", newName);
156+
```
157+
158+
`$.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.
159+
160+
**Modify an array observably**
161+
162+
```js
163+
$.observable(people).insert(newPerson);
164+
```
165+
166+
`$.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.
167+
168+
[Learn more...](http://www.jsviews.com/#$observable)
169+
170+
<h3><i>Responding to data changes</i></h3>
171+
172+
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.
173+
174+
**observe() and observeAll()**
175+
176+
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:
177+
178+
```js
179+
$.observe(person, "name", function(...) {
180+
// The "name" property of person has changed
181+
...
182+
});
183+
```
184+
185+
```js
186+
$.observable(person).observeAll(function(...) {
187+
// A property of person, or a nested object property, has changed
188+
...
189+
});
190+
```
191+
192+
[Learn more...](http://www.jsviews.com/#observeobjectsarrays)
193+
194+
<h3><i>Accessing the view hierarchy</i></h3>
195+
196+
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.
197+
198+
**From UI back to data:**
199+
200+
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.
201+
202+
*[Example](http://www.jsviews.com/#jsv.d.view@$view):*
203+
204+
```html
205+
{^{for people}}
206+
...
207+
<button class="changeBtn">Change</button>
208+
...
209+
{{/for}}
210+
```
211+
212+
Click-handler code for <em>Change</em> button:
213+
214+
```js
215+
$(".changeBtn").on("click", function() {
216+
// From the clicked HTML element ('this'), get the view object
217+
var view = $.view(this);
218+
219+
// Get the 'person' data object for clicked button
220+
var person = view.data;
221+
222+
// Get index of this 'item view'. (Equals index of person in people array)
223+
var index = view.index;
224+
225+
// Change the person.name
226+
$.observable(person).setProperty("name", person.name + " " + index);
227+
});
228+
```
229+
230+
[Learn more...](http://www.jsviews.com/#$view)
231+
232+
<h3><i>Documentation and APIs</i></h3>
233+
234+
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.
15235

16-
<h3>Demos</h3>
17-
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.
236+
<h3><i>Demos</i></h3>
237+
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).
18238

19-
<h3>Current Status</h3>
20-
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.
239+
(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).

demos/features/observability/computed-helper.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ <h3>Computed observables as helper functions (with declared dependencies, and op
9595
// Setter for fullName - for two-way binding
9696
fullName.set = function(val) {
9797
val = val.split(" ");
98-
$.observable(person).setProperty({
98+
// The this pointer is the view, so this.data is the current data item
99+
$.observable(this.data).setProperty({
99100
lastName: val.pop(),
100101
firstName: val.join(" ")
101102
});
@@ -159,7 +160,8 @@ <h4>Script:</h4>
159160

160161
// For two-way binding of computed observables, provide a setter
161162
fullName.set = function(val) {
162-
$.observable(this).setProperty({
163+
// The this pointer is the view, so this.data is the current data item
164+
$.observable(this.data).setProperty({
163165
lastName: ...,
164166
firstName: ...
165167
});

jquery.observable.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*! JsObservable v1.0.0-beta.70 (Beta Candidate): http://jsviews.com/#jsobservable */
1+
/*! JsObservable v0.9.71 (Beta): http://jsviews.com/#jsobservable */
22
/*
33
* Subcomponent of JsViews
44
* Data change events for data-linking
@@ -751,6 +751,9 @@ if (!$.observe) {
751751
if ($isFunction(property)) {
752752
if (property.set) {
753753
// Case of property setter/getter - with convention that property is getter and property.set is setter
754+
leaf = leaf._wrp // Case of JsViews 2-way data-linking to a helper function as getter, with a setter.
755+
// The view will be the this pointer for getter and setter. Note: this is the one scenario where path is "".
756+
|| leaf;
754757
getter = property;
755758
setter = property.set === true ? property : property.set;
756759
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'.
@@ -764,12 +767,18 @@ if (!$.observe) {
764767
setter.call(leaf, value); //set
765768
value = getter.call(leaf); //get updated value
766769
} else if (removeProp = value === remove) {
767-
delete leaf[path];
768-
value = undefined;
770+
if (property !== undefined) {
771+
delete leaf[path];
772+
value = undefined;
773+
} else {
774+
path = undefined; // If value was already undefined, don't trigger handler for removeProp
775+
}
769776
} else if (path) {
770777
leaf[path] = value;
771778
}
772-
this._trigger(leaf, {change: "set", path: path, value: value, oldValue: property, remove: removeProp});
779+
if (path) {
780+
this._trigger(leaf, {change: "set", path: path, value: value, oldValue: property, remove: removeProp});
781+
}
773782
}
774783
}
775784
},

0 commit comments

Comments
 (0)