{{props}} for rendering top-level hash/dictionary
Equivalent to http://www.jsviews.com/#samples/editable/tags but using hash/dictionary of movies, rather than array. Also using {{on}} binding for all button and click actions.
by BorisMoore
HTML
<script src="//www.jsviews.com/download/jsviews.js"></script>
<link rel="stylesheet" href="http://www.jsviews.com/samples/editable-data/sample.css">
<link rel="stylesheet" href="https://www.jsviews.com/samples/editable-data/sample.css">
<div class="buttons">
<button data-link="{on ~showData}">show data</button>
<button data-link="{on ~deleteLast}">delete last language</button>
</div>
<div class="comment">Click to select and edit</div>
<div id="movieList"></div>
<script id="movieTemplate" type="text/x-jsrender">
<table>
<thead><tr>
<th>Title</th><th>Languages</th>
<th class="addMovie" data-link="{on ~addMovie}">Add</th>
</tr></thead>
<tbody class="movies">
{^{props}}
<tr class="hover" data-link="css-background-color{:~bgColor()} {on ~select key}">
<td>
{^{:#index + 1}}: {^{>prop.title}}
</td>
<td>
{^{for prop.languages}}
<div>{^{>name}}</div>
{{/for}}
</td>
<td><span class="removeMovie" data-link="{on ~removeMovie key}"></span></td>
</tr>
{{/props}}
</tbody>
</table>
<div class="detail">
{^{for #data[~selectedKey]}}
<div>
<div class="title">Title:</div>
<div><input data-link="title" /></div>
<div class="title">
Languages: <span class="addLanguage" data-link="{on ~addLanguage languages}">Add</span>
</div>
{^{for languages ~languages=languages}}
<input data-link="name" />
<span class="removeLanguage" data-link="{on ~removeLanguage ~languages #index}"></span>
{{/for}}
</div>
{{/for}}
</div>
</script>
<script id="showData" type="text/x-jsrender">
{{props}}
<div>
<b>Movie:</b> {{>prop.title}}
<b>Languages:</b> {{for prop.languages}} {{>name}}{{/for}}
</div>
{{/props}}
</script>
<div id="console"></div>
JavaScript
"use strict";
var counter = 0,
movies = { // Hash/dictionary of movies
movJb: {
title:"Meet Joe Black",
languages: [
{name: "English"},
{name: "French"}
]
},
movEws: {
title:"Eyes Wide Shut",
languages: [
{name: "German"},
{name: "French"},
{name: "Spanish"}
]
}
},
helpers = {
bgColor: bgColor,
select: function select(key, ev, eventArgs) {
eventArgs.view.ctxPrm("selectedKey", key);
},
addMovie: function(ev, eventArgs) {
var newKey = "mov" + counter;
$.observable(movies).setProperty(
newKey,
{
title: "NewTitle" + counter,
languages: [
{name: "NewLanguage" + counter++}
]}
);
eventArgs.view.ctxPrm("selectedKey", newKey);
},
removeMovie: function(key, ev, eventArgs) {
eventArgs.view.ctxPrm("selectedKey", null);
$.observable(movies).removeProperty(key);
return false;
},
addLanguage: function(languages) {
$.observable(languages).insert({
name: "NewLanguage" + counter++
});
},
removeLanguage: function(languages, index) {
$.observable(languages).remove(index);
return false;
},
deleteLast: function() {
var propsArray = $.view("#movieList").get(true, "array").data;
if (propsArray.length) {
var lastMovie = propsArray[propsArray.length - 1].prop;
$.observable(lastMovie.languages).remove();
}
},
showData: function() {
$("#console").append("<hr/>" + $("#showData").render(movies));
}
},
movieTmpl = $.templates("#movieTemplate");
function bgColor() {
return this.ctxPrm("selectedKey")===this.data.key
? "yellow"
: (this.index%2 ? "#fdfdfe" : "#efeff2");
}
bgColor.depends = ["#index", "~selectedKey"];
// Render movies
movieTmpl.link("#movieList", movies, helpers);
// Data-link top-level buttons
$.link(true, ".buttons", movies, helpers);