From 6e42405cb126d23d1b2aa910413c911c4b69c42f Mon Sep 17 00:00:00 2001 From: BorisMoore Date: Sun, 25 Nov 2018 15:29:59 -0800 Subject: [PATCH] Commit v1.0.0 JsRender, JsObservable and JsViews are now all stable v1.0.0 releases: - This update moves from the previous beta releases to the first official non-beta release: v1.0.0, both for jsrender.js and jsviews.js. - There will be no further major breaking changes before v2.0.0 TypeScript definition fles now available: - This update provides TypeScript definition files, see https://www.jsviews.com#typescript Documentation: - API documentation for JsViews, JsObservable and JsViews is now complete. It includes extensive new documentation, including: - JsRender objects - at https://www.jsviews.com#jsrobjects - JsViews objects - at https://www.jsviews.com#jsvobjects Minor bug fixes: - This update includes some minor bug fixes, and some added code comments. - Issue https://github.com/BorisMoore/jsviews/issues/409 Datepicker fails when convertors in use - Issue https://github.com/BorisMoore/jsviews/issues/209 Improved support for void elements with no self-closing slash, and for upper-case element tag names - Issue https://github.com/BorisMoore/jsviews/issues/175 Provide TypeScript definition files - Issue https://github.com/BorisMoore/jsrender/issues/211 Provide TypeScript definitions --- _src/jquery.observable.js | 4 +- _src/jquery.views.js | 75 +- _src/jsrender-node-starter/package.json | 6 +- _src/jsrender.js | 172 +- _src/jsrender/package.json | 2 +- _src/jsviews/package.json | 4 +- _src/templates/-jsr-version.txt | 1 - _src/templates/-jsv-version.txt | 1 - _src/templates/jsviews.js | 4 +- documentation/contents-categories.js | 262 +- documentation/contents-categories.min.js | 2 +- documentation/contents-categories.min.js.map | 2 +- documentation/contents-download.js | 57 +- documentation/contents-download.min.js | 4 +- documentation/contents-download.min.js.map | 2 +- documentation/contents-getstarted.js | 8 +- documentation/contents-getstarted.min.js | 4 +- documentation/contents-getstarted.min.js.map | 2 +- documentation/contents-jsoapi.js | 74 +- documentation/contents-jsoapi.min.js | 8 +- documentation/contents-jsoapi.min.js.map | 2 +- documentation/contents-jsrapi.js | 265 +- documentation/contents-jsrapi.min.js | 23 +- documentation/contents-jsrapi.min.js.map | 2 +- documentation/contents-jsvapi.js | 374 +- documentation/contents-jsvapi.min.js | 35 +- documentation/contents-jsvapi.min.js.map | 2 +- documentation/contents-samples.js | 75 +- documentation/contents-samples.min.js | 16 +- documentation/contents-samples.min.js.map | 2 +- documentation/find-download.js | 42 +- documentation/find-download.min.js | 2 +- documentation/find-download.min.js.map | 2 +- documentation/find-getstarted.js | 8 +- documentation/find-getstarted.min.js | 2 +- documentation/find-getstarted.min.js.map | 2 +- documentation/find-jsoapi.js | 9 +- documentation/find-jsoapi.min.js | 4 +- documentation/find-jsoapi.min.js.map | 2 +- documentation/find-jsrapi.js | 186 +- documentation/find-jsrapi.min.js | 18 +- documentation/find-jsrapi.min.js.map | 2 +- documentation/find-jsvapi.js | 236 +- documentation/find-jsvapi.min.js | 30 +- documentation/find-jsvapi.min.js.map | 2 +- documentation/find-samples.js | 39 +- documentation/find-samples.min.js | 10 +- documentation/find-samples.min.js.map | 2 +- download/jquery.observable.js | 8 +- download/jquery.observable.min.js | 4 +- download/jquery.observable.min.js.map | 2 +- download/jquery.views.js | 79 +- download/jquery.views.min.js | 6 +- download/jquery.views.min.js.map | 2 +- download/jsrender-node.js | 176 +- download/jsrender-node.min.js | 4 +- download/jsrender-node.min.js.map | 2 +- download/jsrender.js | 176 +- download/jsrender.min.js | 4 +- download/jsrender.min.js.map | 2 +- download/jsviews.js | 259 +- download/jsviews.min.js | 8 +- download/jsviews.min.js.map | 2 +- .../areaslider/areaslider.js | 2 +- .../areaslider/areaslider.min.js | 2 +- .../areaslider/areaslider.min.js.map | 2 +- .../colorpicker/colorpicker-multiformat.js | 2 +- .../colorpicker-multiformat.min.js | 2 +- .../colorpicker-multiformat.min.js.map | 2 +- .../colorpicker/colorpicker-multiformat2.js | 2 +- .../colorpicker/colorpicker.js | 2 +- .../colorpicker/colorpicker.min.js | 2 +- .../colorpicker/colorpicker.min.js.map | 2 +- download/sample-tag-controls/grid/grid.css | 98 +- .../sample-tag-controls/jsonview/jsonview.js | 124 +- .../jsonview/jsonview.min.js | 2 +- .../jsonview/jsonview.min.js.map | 2 +- .../jsviews-jqueryui-widgets.js | 18 +- .../jsviews-jqueryui-widgets.min.js | 4 +- .../jsviews-jqueryui-widgets.min.js.map | 2 +- download/sample-tag-controls/range/range.js | 2 +- .../sample-tag-controls/range/range.min.js | 2 +- .../range/range.min.js.map | 2 +- download/sample-tag-controls/slider/slider.js | 2 +- .../sample-tag-controls/slider/slider.min.js | 2 +- .../slider/slider.min.js.map | 2 +- .../spinblock/spinblock.js | 2 +- .../spinblock/spinblock.min.js | 2 +- .../spinblock/spinblock.min.js.map | 2 +- download/sample-tag-controls/tabs/tabs.js | 2 +- download/sample-tag-controls/tabs/tabs.min.js | 2 +- .../sample-tag-controls/tabs/tabs.min.js.map | 2 +- download/sample-tag-controls/tabs/tabs2.js | 2 +- .../sample-tag-controls/tabs/tabs2.min.js | 2 +- .../sample-tag-controls/tabs/tabs2.min.js.map | 2 +- download/sample-tag-controls/tabs/tabs3.js | 2 +- .../sample-tag-controls/tabs/tabs3.min.js | 2 +- .../sample-tag-controls/tabs/tabs3.min.js.map | 2 +- .../textbox/simple-textbox.js | 2 +- .../textbox/simple-textbox.min.js | 2 +- .../textbox/simple-textbox.min.js.map | 2 +- .../sample-tag-controls/treeview/tree-if.js | 2 +- .../treeview/tree-if.min.js | 2 +- .../treeview/tree-if.min.js.map | 2 +- .../treeview/tree-visible.js | 2 +- .../treeview/tree-visible.min.js | 2 +- .../treeview/tree-visible.min.js.map | 2 +- .../sample-tag-controls/validate/validate.js | 2 +- .../validate/validate.min.js | 2 +- .../validate/validate.min.js.map | 2 +- download/typescript/jsrender/index.d.ts | 371 ++ download/typescript/jsviews/index.d.ts | 376 ++ index.js | 16 +- index.min.js | 2 +- index.min.js.map | 2 +- indexNotMinified.js | 16 +- package.json | 6 +- samples/computed/fullname/data.html | 2 +- samples/computed/fullname/helper.html | 2 +- samples/computed/fullname/prototype.html | 2 +- samples/computed/shopping-cart/tmpl.html | 2 +- samples/computed/shopping-cart/top-level.html | 2 +- samples/computed/team-manager/sample.html | 2 +- samples/data-link/10_linked-visibility.html | 2 +- samples/data-link/11_linked-hover.html | 2 +- samples/data-link/11b_linked-hover.html | 2 +- samples/data-link/11c_linked-hover.html | 2 +- samples/data-link/12_linked-css.html | 2 +- samples/data-link/13_linked-svg.html | 2 +- samples/data-link/1_if-tag-in-attribute.html | 2 +- .../data-link/2_mouse-events-in-template.html | 2 +- .../data-link/3_include-tag-in-attribute.html | 2 +- samples/data-link/4_linked-for-tag.html | 2 +- samples/data-link/5_linked-for-tag.html | 2 +- samples/data-link/6_linked-if-tag.html | 2 +- samples/data-link/7_link-to-class.html | 2 +- samples/data-link/8_toggle-class.html | 2 +- samples/data-link/9_linked-attributes.html | 2 +- samples/editable-data/compiled/sample.html | 2 +- .../editable-data/hash-dictionary/sample.html | 2 +- .../editable-data/linked-elems/sample.html | 2 +- samples/editable-data/linked-tags/sample.html | 2 +- samples/editable-data/observe/sample.html | 2 +- samples/editable-data/submit/sample.html | 2 +- .../editable-data/toplevel-for/sample.html | 2 +- samples/form-els/array-binding/sample.html | 2 +- samples/form-els/converters/day-to-int.html | 2 +- samples/form-els/converters/sample.html | 2 +- samples/form-els/simple/template.html | 2 +- samples/form-els/simple/top-level.html | 2 +- samples/form-els/visible-binding/sample.html | 2 +- .../composition/from-strings/sample.html | 2 +- .../composition/remote-tmpl/sample.html | 2 +- .../composition/remote-tmpl/sample.js | 2 +- .../jsrender/composition/sub-tmpl/sample.html | 2 +- .../composition/tmpl-objects/sample.html | 2 +- samples/jsrender/composition/tmpl/sample.html | 2 +- samples/jsrender/converters/sample.html | 2 +- samples/jsrender/helpers/sample.html | 2 +- samples/jsrender/paths/sample.html | 2 +- samples/jsrender/tags/extend-for/sample.html | 2 +- .../jsrender/tags/wrap-content/sample.html | 2 +- samples/tag-controls/areaslider/sample.html | 2 +- .../colorpicker/colorpicker-multiformat.html | 2 +- .../colorpicker/colorpicker-multiformat2.html | 2 +- .../tag-controls/colorpicker/colorpicker.html | 2 +- .../jqui/accordion/collapsible.html | 6 +- .../tag-controls/jqui/accordion/sortable.html | 6 +- .../accordion/sortablearray-toplevel.html | 6 +- .../jqui/accordion/sortablearray.html | 6 +- .../jqui/autocomplete/variants.html | 6 +- .../jqui/datepicker/date-formats/basic.html | 8 +- .../jqui/datepicker/date-formats/custom.html | 8 +- .../jqui/datepicker/simple/sample.html | 6 +- .../jqui/datepicker/variants/sample.html | 6 +- .../with-validation-wizard/sample.html | 6 +- .../datepicker/with-validation/sample.html | 6 +- .../jqui/draggable-droppable/draggable.html | 8 +- .../jqui/draggable-droppable/draggable.js | 2 +- .../jqui/draggable-droppable/draggable2.html | 12 +- .../jqui/draggable-droppable/draggable2.js | 2 +- .../draggable-droppable/photomanager.html | 10 +- samples/tag-controls/jqui/menu/menu.html | 6 +- .../jqui/progressbar/variants.html | 6 +- samples/tag-controls/jqui/resizable/grid.html | 6 +- .../tag-controls/jqui/resizable/grid2.html | 6 +- .../tag-controls/jqui/resizable/grid3.html | 6 +- .../selectable/sortablearray-toplevel.html | 6 +- .../jqui/selectable/sortablearray.html | 6 +- .../jqui/selectmenu/product-selection.html | 6 +- .../jqui/slider/colorpicker/sample.html | 6 +- .../jqui/slider/simple-toplevel/sample.html | 6 +- .../jqui/slider/simple/sample.html | 6 +- .../jqui/slider/variants/sample.html | 6 +- .../jqui/slider/with-validation/sample.html | 6 +- .../tag-controls/jqui/sortable/variants.html | 6 +- .../tag-controls/jqui/spinner/accounting.html | 10 +- .../tag-controls/jqui/spinner/dataformat.html | 10 +- .../tag-controls/jqui/spinner/globalize.html | 14 +- samples/tag-controls/jqui/spinner/moment.html | 10 +- samples/tag-controls/jqui/spinner/sample.html | 14 +- .../tag-controls/jqui/tabs/collapsible.html | 6 +- samples/tag-controls/jqui/tabs/sortable.html | 6 +- .../jqui/tabs/sortablearray-toplevel.html | 6 +- .../tag-controls/jqui/tabs/sortablearray.html | 6 +- .../jqui/timespinner/dataformat.html | 10 +- .../jqui/timespinner/globalize.html | 14 +- .../tag-controls/jqui/timespinner/moment.html | 10 +- .../tag-controls/jqui/toolbar/toolbar.html | 6 +- .../jqui/toolbar/toolbararray.html | 6 +- samples/tag-controls/jsonview/sample.html | 2 +- samples/tag-controls/multiselect/sample.html | 2 +- .../tag-controls/purchases/sample-jsr.html | 2 +- .../tag-controls/purchases/sample-jsv.html | 2 +- .../tag-controls/simple-textbox/sample.html | 2 +- samples/tag-controls/slider/sample.html | 2 +- samples/tag-controls/spinblock/sample.html | 2 +- samples/tag-controls/tabs/sample.html | 2 +- .../tag-controls/tree/editable/sample.html | 2 +- .../tag-controls/tree/if-binding/sample.html | 2 +- .../tree/visible-binding/sample.html | 2 +- .../validate/array-binding/sample.html | 2 +- .../tag-controls/validate/simple/sample.html | 2 +- .../validate/validation-group/sample.html | 2 +- test/browserify/1-unit-tests.js | 4 +- test/browserify/10-errors-unit-tests.js | 24 +- test/browserify/11-errors-unit-tests.js | 10 +- test/browserify/12-nested-unit-tests.js | 4 +- test/browserify/2-unit-tests.js | 4 +- test/browserify/3-unit-tests.js | 4 +- test/browserify/4-unit-tests.js | 4 +- test/browserify/5-unit-tests.js | 4 +- test/browserify/6-unit-tests.js | 4 +- test/browserify/7-unit-tests.js | 4 +- test/browserify/8-unit-tests.js | 4 +- test/browserify/8B-unit-tests.js | 4 +- test/browserify/9-unit-tests.js | 4 +- test/browserify/bundles/1-bundle.js | 184 +- test/browserify/bundles/10-errors-bundle.js | 4049 +++++++++------- test/browserify/bundles/11-errors-bundle.js | 4286 ++++++++++------- test/browserify/bundles/12-nested-bundle.js | 184 +- test/browserify/bundles/2-bundle.js | 3944 ++++++++------- test/browserify/bundles/3-bundle.js | 3944 ++++++++------- test/browserify/bundles/4-bundle.js | 3780 ++++++++------- test/browserify/bundles/5-bundle.js | 3780 ++++++++------- test/browserify/bundles/6-bundle.js | 4029 +++++++++------- test/browserify/bundles/7-bundle.js | 4029 +++++++++------- test/browserify/bundles/8-bundle.js | 4023 +++++++++------- test/browserify/bundles/8B-bundle.js | 4181 +++++++++------- test/browserify/bundles/9-bundle.js | 4023 +++++++++------- .../bundles/htm-jsrender-tmpl-bundle.js | 182 +- .../bundles/html-jsr-tmpl-bundle.js | 182 +- test/browserify/htm-jsrender-tmpl.js | 4 +- test/browserify/html-jsr-tmpl.js | 4 +- test/browserify/tests-browserify-completed.js | 6 +- test/unit-tests-all-jsviews-jq1.html | 4 +- test/unit-tests-all-jsviews-jq2.html | 4 +- test/unit-tests-all-jsviews-slim.html | 4 +- test/unit-tests-all-jsviews.html | 5 +- ...nit-tests-all-observable-render-views.html | 4 +- ...nit-tests-all-render-observable-views.html | 4 +- test/unit-tests-amd-scriptloader.html | 4 +- test/unit-tests-browserify.html | 4 +- ...nit-tests-jsobservable-no-jqueryviews.html | 4 +- test/unit-tests-jsrender-no-jquery.html | 4 +- test/unit-tests-jsrender-with-jquery.html | 4 +- test/unit-tests-jsviews.html | 4 +- test/unit-tests-multiple-loads.html | 4 +- test/unit-tests/tests-jsobservable.js | 679 ++- .../tests-jsrender-amd-scriptloader.js | 14 +- test/unit-tests/tests-jsrender-no-jquery.js | 956 ++-- test/unit-tests/tests-jsrender-with-jquery.js | 140 +- .../tests-jsviews-amd-scriptloader.js | 14 +- test/unit-tests/tests-jsviews.js | 2809 ++++++----- test/unit-tests/tests-node.js | 32 +- 275 files changed, 31525 insertions(+), 22447 deletions(-) create mode 100644 download/typescript/jsrender/index.d.ts create mode 100644 download/typescript/jsviews/index.d.ts diff --git a/_src/jquery.observable.js b/_src/jquery.observable.js index 2e91e6b2..0c9ec313 100644 --- a/_src/jquery.observable.js +++ b/_src/jquery.observable.js @@ -105,7 +105,7 @@ if (!$.observe) { ctx = ev.data, observeAll = ctx.observeAll, cb = ctx.cb, - noArray = ctx.arOk ? 0 : 1, + noArray = ctx._arOk ? 0 : 1, paths = ctx.paths, ns = ctx.ns; @@ -312,7 +312,7 @@ if (!$.observe) { fullPath: fullPath, paths: pathStr ? [pathStr] : [], prop: prop, - arOk: allowArray + _arOk: allowArray }; evData.ns = initialNs; evData.cb = cb; diff --git a/_src/jquery.views.js b/_src/jquery.views.js index 237b93f2..1f1207af 100644 --- a/_src/jquery.views.js +++ b/_src/jquery.views.js @@ -134,8 +134,8 @@ function updateValues(sourceValues, tagElse, bindId, ev) { } // Set linkCtx on view, dynamically, just during this handler call - oldLinkCtx = view.linkCtx; - view.linkCtx = linkCtx; + oldLinkCtx = view._lc; + view._lc = linkCtx; l = tos.length; while (l--) { if (to = tos[l]) { @@ -183,7 +183,7 @@ function updateValues(sourceValues, tagElse, bindId, ev) { } } } - view.linkCtx = oldLinkCtx; + view._lc = oldLinkCtx; } if (tag) { tag._.chg = undefined; // Clear marker @@ -217,7 +217,7 @@ function onElemChange(ev) { function onDataLinkedTagChange(ev, eventArgs) { // Update or initial rendering of any tag (including {{:}}) whether inline or data-linked element. - var attr, sourceValue, noUpdate, forceUpdate, hasError, onError, bindEarly, + var attr, sourceValue, noUpdate, forceUpdate, hasError, onError, bindEarly, tagCtx, l, linkCtx = this, linkFn = linkCtx.fn, tag = linkCtx.tag, @@ -226,11 +226,11 @@ function onDataLinkedTagChange(ev, eventArgs) { cvt = linkCtx.convert, parentElem = target.parentNode, view = linkCtx.view, - oldLinkCtx = view.linkCtx, + oldLinkCtx = view._lc, onEvent = eventArgs && changeHandler(view, onBeforeChangeStr, tag); // Set linkCtx on view, dynamically, just during this handler call - view.linkCtx = linkCtx; + view._lc = linkCtx; if (parentElem && (!onEvent || onEvent.call(tag || linkCtx, ev, eventArgs) !== false) // If data changed, the ev.data is set to be the path. Use that to filter the handler action... && (!eventArgs || ev.data.prop === "*" || ev.data.prop === eventArgs.path)) { @@ -281,7 +281,7 @@ function onDataLinkedTagChange(ev, eventArgs) { // from the sourceValue (which may optionally have been modifed in onUpdate()...) and then bind, and we are done observeAndBind(linkCtx, source, target); } - view.linkCtx = oldLinkCtx; + view._lc = oldLinkCtx; if (eventArgs && (onEvent = changeHandler(view, onAfterChangeStr, tag))) { onEvent.call(tag || linkCtx, ev, eventArgs); } @@ -295,6 +295,13 @@ function onDataLinkedTagChange(ev, eventArgs) { tag.onUnbind(tag.tagCtx, linkCtx, tag.ctx, ev, eventArgs); } + tag.linkedElems = tag.linkedElem = tag.mainElem = tag.displayElem = undefined; + l = tag.tagCtxs.length; + while (l--) { + tagCtx = tag.tagCtxs[l]; + tagCtx.linkedElems = tagCtx.mainElem = tagCtx.displayElem = undefined; + } + sourceValue = tag.tagName === ":" // Call convertVal if it is a {{cvt:...}} - otherwise call renderTag ? $sub._cnvt(tag.convert, view, sourceValue[0]) // convertVal() // convertVal(converter, view, tagCtx, onError) : $sub._tag(tag, view, view.tmpl, sourceValue, true, onError); // renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) @@ -337,7 +344,7 @@ function onDataLinkedTagChange(ev, eventArgs) { onEvent.call(tag || linkCtx, ev, eventArgs); } // Remove dynamically added linkCtx from view - view.linkCtx = oldLinkCtx; + view._lc = oldLinkCtx; } } @@ -359,7 +366,7 @@ function updateContent(sourceValue, linkCtx, attr, tag) { $target = $(target), view = linkCtx.view, targetVal = linkCtx._val, - oldLinkCtx = view.linkCtx, + oldLinkCtx = view._lc, change = tag; if (tag) { @@ -449,7 +456,7 @@ function updateContent(sourceValue, linkCtx, attr, tag) { if (setter = fnSetters[attr]) { if (attr === HTML) { // Set linkCtx on view, dynamically, just during this handler call - view.linkCtx = linkCtx; + view._lc = linkCtx; if (tag && tag.inline) { nodesToRemove = tag.nodes(true); if (tag._elCnt) { @@ -499,7 +506,7 @@ function updateContent(sourceValue, linkCtx, attr, tag) { } } // Remove dynamically added linkCtx and ctx from view - view.linkCtx = oldLinkCtx; + view._lc = oldLinkCtx; } else { if (change = change || targetVal !== sourceValue) { if (attr === "text" && target.children && !target.children[0]) { @@ -900,7 +907,7 @@ function $link(tmplOrLinkExpr, to, from, context, noIteration, parentView, prevN } if ("" + tmplOrLinkExpr === tmplOrLinkExpr) { // tmplOrLinkExpr is a string: treat as data-link expression. - addDataBinding(late = [], tmplOrLinkExpr, targetEl, parentView, undefined, true, from, context); + addDataBinding(late = [], tmplOrLinkExpr, targetEl, parentView, undefined, "expr", from, context); } else { if (tmplOrLinkExpr.markup !== undefined) { // This is a call to template.link() @@ -927,7 +934,7 @@ function $link(tmplOrLinkExpr, to, from, context, noIteration, parentView, prevN } } else if (tmplOrLinkExpr === true && parentView === topView) { // $.link(true, selector, data, ctx) - where selector points to elem in top-level content. (If not top-level content, no-op) - refresh = {lnk: 1}; + refresh = {lnk: "top"}; } else { break; // no-op - $.link(true, selector, data, ctx) targeting within previously linked rendered template } @@ -994,7 +1001,7 @@ function viewLink(outerData, parentNode, prevNode, nextNode, html, refresh, cont inTag = 0; return all; } - tag = tag1 || tag2 || ""; + tag = (tag1 || tag2 || "").toLowerCase(); closeTag = closeTag || closeTag2; selfClose = selfClose || selfClose2; if (isVoid && !selfClose && (!all || closeTag || tag || id && !inTag)) { // !all = end of string @@ -1003,6 +1010,7 @@ function viewLink(outerData, parentNode, prevNode, nextNode, html, refresh, cont } closeTag = closeTag || selfClose; if (closeTag) { + closeTag = closeTag.toLowerCase(); inTag = 0; isVoid = undefined; // TODO: smart insertion of - to be completed for robust insertion of deferred bindings etc. @@ -1618,13 +1626,12 @@ function addDataBinding(late, linkMarkup, node, currentView, boundTagId, isLink, tagExpr += delimCloseChar1 + delimOpenChar0 + delimOpenChar1 + "/" + tokens[4] + delimCloseChar0; } linkCtx = { - type: isLink ? "top" : "link", + type: isLink || "link", data: data, // source elem: node, // target view: currentView, ctx: context, attr: attr, - isLk: isLink, // top-level linking? _toLk : 1, // Flag to data-link on initial data-link call rendering call _noUpd : tokens[2] // Flag for data-link="^{...}" so on initial data-link call will bind, but not render) }; @@ -1666,8 +1673,9 @@ function bindDataLinkTarget(linkCtx, late) { onDataLinkedTagChange.call(linkCtx, ev, eventArgs); // If the link expression uses a custom tag, the onDataLinkedTagChange call will call renderTag, which will set tagCtx on linkCtx } - var view; - if (linkCtx.isLk) { + var view, + linkCtxType = linkCtx.type; + if (linkCtxType === "top" || linkCtxType === "expr") { // Top-level linking: .link(expressionOrTrue, data, context) - so we need to create a view for the linking, with the data and ctx // which may be different than the current context of the target. Note that this view is not a standard data-linked view, so it will // be disposed only when its parent view is disposed. @@ -1678,7 +1686,7 @@ function bindDataLinkTarget(linkCtx, late) { linkCtx._ctxCb = $sub._gccb(view = linkCtx.view); // getContextCallback: _ctxCb, for filtering/appending to dependency paths: function(path, object) { return [(object|path)*]} linkCtx._hdl = handler; // handler._ctx = linkCtx; Could pass linkCtx for use in a depends = function() {} call, so depends is different for different linkCtx's - if (linkCtx.elem.nodeName === "SELECT" && linkCtx.type === "link" && !linkCtx.attr) { + if (linkCtx.elem.nodeName === "SELECT" && linkCtxType === "link" && !linkCtx.attr) { var $elem = $(linkCtx.elem); $elem.on("jsv-domchange", function() { // If the options have changed dynamically under the select, we need to refresh the data-linked selection, using the new options @@ -1820,9 +1828,9 @@ function callAfterLink(tag, ev, eventArgs) { l = linkedElements.length; while (l--) { if (linkedElements[l]) { + linkCtxElem = !tag.inline && $linkCtxElem.filter(linkedElements[l]); m = tagCtxslength; while (m--) { - linkCtxElem = !m && !tag.inline && $linkCtxElem.filter(linkedElements[l]); tagCtxElse = tagCtxs[m]; linkedElems = tagCtxElse.linkedElems = tagCtxElse.linkedElems || new Array(l); linkedElem = linkCtxElem[0] ? linkCtxElem : tagCtxElse.contents(true, linkedElements[l]); @@ -1836,9 +1844,9 @@ function callAfterLink(tag, ev, eventArgs) { if (linkedElements = tag.mainElement) { // tag.mainElement: - selector for identifying mainElem in template/rendered content // (But for tag bindings on data-linked elements, defaults to data-linked element) + linkCtxElem = !tag.inline && $linkCtxElem.filter(linkedElements); m = tagCtxslength; while (m--) { - linkCtxElem = !m && !tag.inline && $linkCtxElem.filter(linkedElements); tagCtxElse = tagCtxs[m]; linkedElem = linkCtxElem[0] ? linkCtxElem : tagCtxElse.contents(true, linkedElements).eq(0); if (linkedElem[0]) { @@ -1849,16 +1857,13 @@ function callAfterLink(tag, ev, eventArgs) { if (linkedElements = tag.displayElement) { // tag.displayElement: - selector for identifying displayElem in template/rendered content // (But for tag bindings on data-linked elements, defaults to data-linked element) + linkCtxElem = !tag.inline && $linkCtxElem.filter(linkedElements); m = tagCtxslength; while (m--) { - linkCtxElem = !m && !tag.inline && $linkCtxElem.filter(linkedElements); tagCtxElse = tagCtxs[m]; linkedElem = linkCtxElem[0] ? linkCtxElem : tagCtxElse.contents(true, linkedElements).eq(0); if (linkedElem[0]) { tagCtxElse.displayElem = linkedElem; - if (!m) { - tag.displayElem = linkedElem; - } } } } @@ -1909,12 +1914,12 @@ function callAfterLink(tag, ev, eventArgs) { } if (!tag.flow && !tag._.chg) { - if (tag.inline && tag._.unlinked && (tag.linkedElems || tag.bindTo)) { + if (tag._tgId && tag._.unlinked && (tag.linkedElems || tag.bindTo)) { defineBindToDataTargets(bindingStore[tag._tgId], tag); } m = tagCtxs.length; while (m--) { - props = tag.cvtArgs(1, m); // array of bindFrom args/props + props = tag.cvtArgs(m, 1); // array of bindFrom args/props l = props.length; while (l--) { val = props[l]; @@ -1922,7 +1927,7 @@ function callAfterLink(tag, ev, eventArgs) { } if (tag._.unlinked) { tagCtx = tagCtxs[m]; - linkedElems = tagCtx.linkedElems || tag.linkedElem && [tag.linkedElem]; + linkedElems = tagCtx.linkedElems || !m && tag.linkedElem && [tag.linkedElem]; indexTo = (tag.bindTo || [0]).length; while (indexTo--) { if ((linkedElem = linkedElems && linkedElems[indexTo]) && (l = linkedElem.length)) { @@ -2453,6 +2458,7 @@ function disposeTokens(tokens, elem) { //============================================ function updateValue(val, index, tagElse, async, bindId, ev) { +// async, bindId and ev not documented - used internally, e.g. for paged and sorted arrays on tags with dataMap, such as {{for}} // Observably update a data value targeted by the binding.to binding of a 2way data-link binding. Called when elem changes // Called when linkedElem of a tag control changes: as updateValue(val, index, tagElse, bindId, ev) - this: undefined // Called directly as tag.updateValue(val, index, tagElse) - this: tag @@ -2917,6 +2923,7 @@ function addLinkMethods(tagOrView) { // tagOrView is View prototype or tag insta renderAndLink(view, view.index, view.tmpl, parent.views, view.data, undefined, true); setArrayChangeLink(view); } + return view; }; theView.fixIndex = function(fromIndex) { @@ -3426,7 +3433,7 @@ $extend($, { if (node) { if (inner) { getInnerView(node._df, true); - if (!view) { + if (!view && node.tagName) { // Not a text node // Treat supplied node as a container element and return the first view encountered. elems = qsa ? node.querySelectorAll(bindElsSel) : $(bindElsSel, node).get(); l = elems.length; @@ -3626,7 +3633,7 @@ $sub._gccb = function(view) { // Return a callback for accessing the context of }; //=================== -// ctxPrm helpers +// ctxPrm helpers //=================== // The following helper functions for observable contextual parameters are needed by render.js in data-linking scenarios // Implemented here rather than in render.js to keep render.js size down, and exposed via $.sub... @@ -3636,12 +3643,14 @@ $sub._cp = function(paramVal, paramExpr, view, tagCtxPrm) { // Create tag or inl // Called for tag parameter (two-way binding), from renderTag. (tagCtxPrm is {tag: ..., ind: ...}) if (view.linked) { // In JsViews, returns [view, linkFn] where linkFn is compiled function for expression, or observable contextual parameter object if (tagCtxPrm && (tagCtxPrm.cvt || tagCtxPrm.tag._.toIndex[tagCtxPrm.ind] === undefined)) { - paramVal = [{_ocp: paramVal}]; // Uninitialized observable contextual parameter object - tagCtxPrm.updateValue = function(val, path) { + paramVal = [{_ocp: paramVal}]; // With convert, or with bindTo/bindFrom different, the tag contextual parameter object will be 'local' to the tag. + // It will be updated by bindFrom binding, and by tag.setValue(...), but not by tag.updateValue() (which will update bindTo value externally) + tagCtxPrm.updateValue = function(val) { $.observable(paramVal._cxp.data).setProperty(_ocp, val); // Set the value (res[0]._ocp) return this; }; - } else if (paramExpr) { + } else if (paramExpr) { // With no convert/convertBack and no bindTo/bindFrom difference, tag contextual parameter 2way binds to bindTo/bindFrom value. + // So tag.updateValue() updates external value, which updates contextual parameter through 2way binding var params = delimOpenChar1 + ":" + paramExpr + delimCloseChar0, links = topView.tmpl.links, // Use topView links, as for compiled top-level linking expressions. To do - should this ever get disposed? linkFn = links[params]; diff --git a/_src/jsrender-node-starter/package.json b/_src/jsrender-node-starter/package.json index 249cd7af..a384367a 100644 --- a/_src/jsrender-node-starter/package.json +++ b/_src/jsrender-node-starter/package.json @@ -1,6 +1,6 @@ { "name": "jsrender-node-starter", - "version": "0.9.91", + "version": "1.0.0", "description": "Starter app for JsRender server-rendered templates on Node.js using Express 4 or Hapi, and optionally Browserify and JsRenderify", "main": "index-express.js", "scripts": { @@ -20,8 +20,8 @@ "hapi": "^11.1.3", "inert": "^3.0.1", "jquery": "^3.0.0", - "jsrender": "^0.9.91", - "jsviews": "^0.9.91", + "jsrender": "^1.0.0", + "jsviews": "^1.0.0", "serve-favicon": "^2.3.0", "through2": "^2.0.0", "vision": "^3.0.0" diff --git a/_src/jsrender.js b/_src/jsrender.js index a00f7c4e..e28c39cc 100644 --- a/_src/jsrender.js +++ b/_src/jsrender.js @@ -79,7 +79,7 @@ template: function(name, item) { if (item === null) { delete $render[name]; - } else { + } else if (name) { $render[name] = item; } } @@ -203,22 +203,40 @@ function $extend(target, source) { // views.delimiters //=================== + /** + * Set the tag opening and closing delimiters and 'link' character. Default is "{{", "}}" and "^" + * openChars, closeChars: opening and closing strings, each with two characters + * $.views.settings.delimiters(...) + * + * @param {string} openChars + * @param {string} [closeChars] + * @param {string} [link] + * @returns {Settings} + * + * Get delimiters + * delimsArray = $.views.settings.delimiters() + * + * @returns {string[]} + */ function $viewsDelimiters(openChars, closeChars, link) { - // Set the tag opening and closing delimiters and 'link' character. Default is "{{", "}}" and "^" - // openChars, closeChars: opening and closing strings, each with two characters if (!openChars) { return $subSettings.delimiters; } if ($isArray(openChars)) { return $viewsDelimiters.apply($views, openChars); } + linkChar = link ? link[0] : linkChar; + if (!/^(\W|_){5}$/.test(openChars + closeChars + linkChar)) { + error("Invalid delimiters"); // Must be non-word characters, and openChars and closeChars must each be length 2 + } + delimOpenChar0 = openChars[0]; + delimOpenChar1 = openChars[1]; + delimCloseChar0 = closeChars[0]; + delimCloseChar1 = closeChars[1]; - $subSettings.delimiters = [openChars, closeChars, linkChar = link ? link.charAt(0) : linkChar]; + $subSettings.delimiters = [delimOpenChar0 + delimOpenChar1, delimCloseChar0 + delimCloseChar1, linkChar]; - delimOpenChar0 = openChars.charAt(0); // Escape the characters - since they could be regex special characters - delimOpenChar1 = openChars.charAt(1); - delimCloseChar0 = closeChars.charAt(0); - delimCloseChar1 = closeChars.charAt(1); + // Escape the characters - since they could be regex special characters openChars = "\\" + delimOpenChar0 + "(\\" + linkChar + ")?\\" + delimOpenChar1; // Default is "{^{" closeChars = "\\" + delimCloseChar0 + "\\" + delimCloseChar1; // Default is "}}" // Build regex with new delimiters @@ -253,8 +271,8 @@ function getView(inner, type) { //view.get(inner, type) var views, i, l, found, view = this, - root = !type || type === "root"; - // If type is undefined, returns root view (view under top view). + root = type === "root"; + // view.get("root") returns view.root, view.get() returns view.parent, view.get(true) returns view.views[0]. if (inner) { // Go through views - this one, and all nested ones, depth-first - and return first one with given type. @@ -277,14 +295,16 @@ function getView(inner, type) { //view.get(inner, type) } else if (root) { // Find root view. (view whose parent is top view) found = view.root; - } else { + } else if (type) { while (view && !found) { // Go through views - this one, and all parent ones - and return first one with given type. found = view.type === type ? view : undefined; view = view.parent; } + } else { + found = view.parent; } - return found; + return found || undefined; } function getNestedIndex() { @@ -302,11 +322,13 @@ function getIndex() { getIndex.depends = "index"; -//========== -// View.hlp -//========== +//================== +// View.ctxPrm, etc. +//================== -function getPathObject(ob, path, ltOb, fn) { // Iterate through path to late paths: @a.b.c paths +/* Internal private: view._getOb() */ +function getPathObject(ob, path, ltOb, fn) { + // Iterate through path to late paths: @a.b.c paths // Return "" (or noop if leaf is a function @a.b.c(...) ) if intermediate object not yet available var prevOb, tokens, l, i = 0; @@ -340,7 +362,6 @@ function contextParameter(key, value, get) { storeView = this, isUpdate = !isRenderCall && arguments.length > 1, store = storeView.ctx; - if (key) { if (!storeView._) { // tagCtx.ctxPrm() call tagElse = storeView.index; @@ -355,7 +376,7 @@ function contextParameter(key, value, get) { } else { store = undefined; } - if (storeView.tagCtx || storeView.linked) { // Data-linked view, or tag instance + if (!isRenderCall && storeView.tagCtx || storeView.linked) { // Data-linked view, or tag instance if (!res || !res._cxp) { // Not a contextual parameter // Set storeView to tag (if this is a tag.ctxPrm() call) or to root view ("data" view of linked template) @@ -401,7 +422,7 @@ function contextParameter(key, value, get) { tagElse = obsCtxPrm.tagElse; newRes = res[1] // linkFn for compiled expression ? obsCtxPrm.tag && obsCtxPrm.tag.cvtArgs - ? obsCtxPrm.tag.cvtArgs(1, tagElse)[obsCtxPrm.ind] // = tag.bndArgs() - for tag contextual parameter + ? obsCtxPrm.tag.cvtArgs(tagElse, 1)[obsCtxPrm.ind] // = tag.bndArgs() - for tag contextual parameter : res[1](res[0].data, res[0], $sub) // = fn(data, view, $sub) for compiled binding expression : res[0]._ocp; // Observable contextual parameter (uninitialized, or initialized as static expression, so no path dependencies) if (isUpdate) { @@ -428,6 +449,7 @@ function contextParameter(key, value, get) { } } +/* Internal private: view._getTmpl() */ function getTemplate(tmpl) { return tmpl && (tmpl.fn ? tmpl @@ -444,7 +466,7 @@ function convertVal(converter, view, tagCtx, onError) { var tag, value, argsLen, bindTo, // If tagCtx is an integer, then it is the key for the compiled function to return the boundTag tagCtx boundTag = typeof tagCtx === "number" && view.tmpl.bnds[tagCtx-1], - linkCtx = view.linkCtx; // For data-link="{cvt:...}"... + linkCtx = view._lc; // For data-link="{cvt:...}"... if (onError === undefined && boundTag && boundTag._lr) { // lateRender onError = ""; @@ -503,13 +525,16 @@ function convertVal(converter, view, tagCtx, onError) { return value != undefined ? value : ""; } -function convertArgs(bound, tagElse) { // tag.cvtArgs() or tag.cvtArgs(trueOrFalse, tagElse) +function convertArgs(tagElse, bound) { // tag.cvtArgs() or tag.cvtArgs(tagElse?, true?) var l, key, boundArgs, args, bindFrom, tag, converter, tagCtx = this; if (tagCtx.tagName) { tag = tagCtx; - tagCtx = tag.tagCtxs ? tag.tagCtxs[tagElse || 0] : tag.tagCtx; + tagCtx = (tag.tagCtxs || [tagCtx])[tagElse||0]; + if (!tagCtx) { + return; + } } else { tag = tagCtx.tag; } @@ -569,13 +594,14 @@ function argOrProp(context, key) { } function convertBoundArgs(tagElse) { // tag.bndArgs() - return this.cvtArgs(1, tagElse); + return this.cvtArgs(tagElse, 1); } //============= -// views._tag +// views.tag //============= +/* view.getRsc() */ function getResource(resourceType, itemName) { var res, store, view = this; @@ -612,7 +638,7 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { content, callInit, mapDef, thisMap, args, bdArgs, props, tagDataMap, contentCtx, key, bindFromLength, bindToLength, linkedElement, defaultCtx, i = 0, ret = "", - linkCtx = parentView.linkCtx || 0, + linkCtx = parentView._lc || false, ctx = parentView.ctx, parentTmpl = tmpl || parentView.tmpl, // If tagCtxs is an integer, then it is the key for the compiled function to return the boundTag tagCtxs @@ -657,7 +683,7 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { } if (tmpl = tagCtx.props.tmpl) { // If the tmpl property is overridden, set the value (when initializing, or, in case of binding: ^tmpl=..., when updating) - tagCtx.tmpl = parentView.getTmpl(tmpl); + tagCtx.tmpl = parentView._getTmpl(tmpl); tagCtx.content = tagCtx.content || tagCtx.tmpl; } @@ -675,8 +701,8 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { if (linkCtx) { tag.inline = false; linkCtx.tag = tag; - tag.linkCtx = linkCtx; } + tag.linkCtx = linkCtx; if (tag._.bnd = boundTag || linkCtx.fn) { // Bound if {^{tag...}} or data-link="{tag...}" tag._.ths = tagCtx.params.props.this; // Tag has a this=expr binding, to get javascript reference to tag instance @@ -782,9 +808,9 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { attr = tag.attr; tag._.noVws = attr && attr !== HTML; } - args = tag.cvtArgs(undefined, i); + args = tag.cvtArgs(i); if (tag.linkedCtxParam) { - bdArgs = tag.cvtArgs(1, i); + bdArgs = tag.cvtArgs(i, 1); m = bindFromLength; defaultCtx = tag.constructor.prototype.ctx; while (m--) { @@ -840,8 +866,11 @@ function renderTag(tagName, parentView, tmpl, tagCtxs, isUpdate, onError) { } itemRet = tagCtx.render(contentCtx, true) || (isUpdate ? undefined : ""); } - // No return value from render, and no template/content tagCtx.render(...), so return undefined - ret = ret ? ret + (itemRet || "") : itemRet; // If no rendered content, this will be undefined + ret = ret + ? ret + (itemRet || "") + : itemRet !== undefined + ? "" + itemRet + : undefined; // If no return value from render, and no template/content tagCtx.render(...), return undefined } tag.rendering = tag.rendering.rndr; // Remove tag.rendering object (if this is outermost render call. (In case of nested calls) } @@ -915,10 +944,10 @@ function View(context, type, parentView, data, template, key, onRender, contentT View.prototype = { get: getView, getIndex: getIndex, - getRsc: getResource, - getTmpl: getTemplate, ctxPrm: contextParameter, - getOb: getPathObject, + getRsc: getResource, + _getTmpl: getTemplate, + _getOb: getPathObject, _is: "view" }; @@ -1234,7 +1263,7 @@ function compileViewModel(name, type) { arr.push(ob); }); - ob = this.apply(this, arr); // Insantiate this View Model, passing getters args array to constructor + ob = this.apply(this, arr); // Instantiate this View Model, passing getters args array to constructor for (prop in data) { // Copy over any other properties. that are not get/set properties if (@@if (!context.isNode) {prop !== $expando && }!getterNames[prop]) { ob[prop] = data[prop]; @@ -1407,14 +1436,27 @@ function tmplObject(markup, options) { // registerStore //============== +/** +* Internal. Register a store type (used for template, tags, helpers, converters) +*/ function registerStore(storeName, storeSettings) { +/** +* Generic store() function to register item, named item, or hash of items +* Also used as hash to store the registered items +* Used as implementation of $.templates(), $.views.templates(), $.views.tags(), $.views.helpers() and $.views.converters() +* +* @param {string|hash} name name - or selector, in case of $.templates(). Or hash of items +* @param {any} [item] (e.g. markup for named template) +* @param {template} [parentTmpl] For item being registered as private resource of template +* @returns {any|$.views} item, e.g. compiled template - or $.views in case of registering hash of items +*/ function theStore(name, item, parentTmpl) { // The store is also the function used to add items to the store. e.g. $.templates, or $.views.tags // For store of name 'thing', Call as: // $.views.things(items[, parentTmpl]), - // or $.views.things(name, item[, parentTmpl]) + // or $.views.things(name[, item, parentTmpl]) var compile, itemName, thisStore, cnt, onStore = $sub.onStore[storeName]; @@ -1471,6 +1513,15 @@ function registerStore(storeName, storeSettings) { $views[storeNames] = theStore; } +/** +* Add settings such as: +* $.views.settings.allowCode(true) +* @param {boolean} value +* @returns {Settings} +* +* allowCode = $.views.settings.allowCode() +* @returns {boolean} +*/ function addSetting(st) { $viewsSettings[st] = function(value) { return arguments.length @@ -1510,6 +1561,17 @@ function dataMap(mapDef) { // renderContent //============== +/** Render the template as a string, using the specified data and helpers/context +* $("#tmpl").render(), tmpl.render(), tagCtx.render(), $.render.namedTmpl() +* +* @param {any} data +* @param {hash} [context] helpers or context +* @param {boolean} [noIteration] +* @param {View} [parentView] internal +* @param {string} [key] internal +* @param {function} [onRender] internal +* @returns {string} rendered template internal +*/ function renderContent(data, context, noIteration, parentView, key, onRender) { var i, l, tag, tmpl, tagCtx, isTopRenderCall, prevData, prevIndex, view = parentView, @@ -1526,7 +1588,7 @@ function renderContent(data, context, noIteration, parentView, key, onRender) { // This is a call from renderTag or tagCtx.render(...) tagCtx = this; view = view || tagCtx.view; - tmpl = view.getTmpl(tag.template || tagCtx.tmpl); + tmpl = view._getTmpl(tag.template || tagCtx.tmpl); if (!arguments.length) { data = tag.contentCtx && $isFunction(tag.contentCtx) ? data = tag.contentCtx(data) @@ -1629,7 +1691,7 @@ function renderWithViews(tmpl, data, context, noIteration, view, key, onRender, context.link = false; } if (itemVar = tagCtx.props.itemVar) { - if (itemVar.charAt(0) !== "~") { + if (itemVar[0] !== "~") { syntaxError("Use itemVar='~myItem'"); } itemVar = itemVar.slice(1); @@ -1730,7 +1792,7 @@ function onRenderError(e, view, fallback) { message = fallback; // There is a settings.debugMode(handler) onError override. Call it, and use return value (if any) to replace message } - return view && !view.linkCtx ? $converters.html(message) : message; + return view && !view._lc ? $converters.html(message) : message; } function error(message) { @@ -1852,7 +1914,7 @@ function tmplFn(markup, tmpl, isLinkExpr, convertBack, hasElse) { keyValue = "undefined"; // this=some.path is always a to parameter (one-way), so don't need to compile/evaluate some.path initialization } if (param) { - isLateOb = isLateOb || param.charAt(0) === "@"; + isLateOb = isLateOb || param[0] === "@"; } key = "'" + keyToken + "':"; if (arg) { @@ -2010,7 +2072,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) { syntaxError(allPath); } if (!subPath) { - allPath = (late // late path @a.b.c: not throw on 'property of undefined' if a undefined, and will use getOb() after linking to resolve late. + allPath = (late // late path @a.b.c: not throw on 'property of undefined' if a undefined, and will use _getOb() after linking to resolve late. ? (isLinkExpr ? '' : '(ltOb.lt=ltOb.lt||') + '(ob=' : "" ) @@ -2020,7 +2082,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) { ? "view" : "data") + (late - ? ')===undefined' + (isLinkExpr ? '' : ')') + '?"":view.getOb(ob,"' + ? ')===undefined' + (isLinkExpr ? '' : ')') + '?"":view._getOb(ob,"' : "" ) + (leafToken @@ -2052,7 +2114,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) { path = "^" + path.slice(1); } theOb.sb = path; - theOb.bnd = theOb.bnd || path.charAt(0) === "^"; + theOb.bnd = theOb.bnd || path[0] === "^"; } } else { binds.push(path); @@ -2071,7 +2133,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) { lftPrn = lftPrn || lftPrn0 || lftPrn2; path = path || path2; - if (late && (late = !/\)|]/.test(full.charAt(index-1)))) { + if (late && (late = !/\)|]/.test(full[index-1]))) { path = path.slice(1).split(".").join("^"); // Late path @z.b.c. Use "^" rather than "." to ensure that deep binding will be used } // Could do this - but not worth perf cost?? :- @@ -2192,7 +2254,7 @@ function parseParams(params, pathBindings, tmpl, isLinkExpr) { pathStart = {}, // tracks the start of the current path such as c^d() in the above example result; - if (params.charAt(0) === "@") { + if (params[0] === "@") { params = params.replace(rBracketQuote, "."); } result = (params + (tmpl ? " " : "")).replace(rParams, parseTokens); @@ -2335,8 +2397,8 @@ function buildCode(ast, tmpl, isLinkExpr) { : (getsVal = true, "((v=" + params[0] + ')!=null?v:' + (isLinkExpr ? 'null)' : '"")')) // Non strict equality so data-link="title{:expr}" with expr=null/undefined removes title attribute ) - : (hasTag = true, "\n{view:view,tmpl:" // Add this tagCtx to the compiled code for the tagCtxs to be passed to renderTag() - + (content ? nestedTmpls.length : "0") + "," // For block tags, pass in the key (nestedTmpls.length) to the nested content template + : (hasTag = true, "\n{view:view,content:false,tmpl:" // Add this tagCtx to the compiled code for the tagCtxs to be passed to renderTag() + + (content ? nestedTmpls.length : "false") + "," // For block tags, pass in the key (nestedTmpls.length) to the nested content template + tagCtx + "},")); if (tagAndElses && !nextIsElse) { @@ -2517,6 +2579,14 @@ function getTargetSorted(value, tagCtx) { return value; } +/** Render the template as a string, using the specified data and helpers/context +* $("#tmpl").render() +* +* @param {any} data +* @param {hash} [helpersOrContext] +* @param {boolean} [noIteration] +* @returns {string} rendered template +*/ function $fnRender(data, context, noIteration) { var tmplElem = this.jquery && (this[0] || error('Unknown template')), // Targeted element not found for jQuery template selector such as "#myTmpl" tmpl = tmplElem.getAttribute(tmplAttr); @@ -2648,6 +2718,14 @@ $viewsSettings = $views.settings; addSetting(setting); } + /** + * $.views.settings.debugMode(true) + * @param {boolean} debugMode + * @returns {Settings} + * + * debugMode = $.views.settings.debugMode() + * @returns {boolean} + */ ($viewsSettings.debugMode = function(debugMode) { return debugMode === undefined ? $subSettings.debugMode diff --git a/_src/jsrender/package.json b/_src/jsrender/package.json index a1a14429..929a875d 100644 --- a/_src/jsrender/package.json +++ b/_src/jsrender/package.json @@ -1,6 +1,6 @@ { "name": "jsrender", - "version": "v0.9.91", + "version": "v1.0.0", "description": "Best-of-breed templating in browser or on Node.js (with Express 4, Hapi and Browserify integration)", "main": "./jsrender-node.js", "browser": "./jsrender.js", diff --git a/_src/jsviews/package.json b/_src/jsviews/package.json index 402a4bb5..dc50382f 100644 --- a/_src/jsviews/package.json +++ b/_src/jsviews/package.json @@ -1,6 +1,6 @@ { "name": "jsviews", - "version": "v0.9.91", + "version": "v1.0.0", "description": "Next-generation MVVM and MVP framework - built on top of JsRender templates. Bringing templates to life...", "main": "./jsviews.js", "author": { @@ -34,7 +34,7 @@ "browserify": "^11.0.1", "glob-stream": "^5.0.0", "gulp": "^3.9.0", - "jsrender": "^0.9.91", + "jsrender": "^1.0.0", "qunit": "^0.7.6" }, "dependencies": { diff --git a/_src/templates/-jsr-version.txt b/_src/templates/-jsr-version.txt index cfbb958d..e69de29b 100644 --- a/_src/templates/-jsr-version.txt +++ b/_src/templates/-jsr-version.txt @@ -1 +0,0 @@ - (Beta) \ No newline at end of file diff --git a/_src/templates/-jsv-version.txt b/_src/templates/-jsv-version.txt index cfbb958d..e69de29b 100644 --- a/_src/templates/-jsv-version.txt +++ b/_src/templates/-jsv-version.txt @@ -1 +0,0 @@ - (Beta) \ No newline at end of file diff --git a/_src/templates/jsviews.js b/_src/templates/jsviews.js index 32a8a3bb..fd70dc25 100644 --- a/_src/templates/jsviews.js +++ b/_src/templates/jsviews.js @@ -55,7 +55,7 @@ var versionNumber = "v@@include("templates/-version.txt")", //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< JsObservable >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /* JsObservable: - * See http://www.jsviews.com/#jsobservable and http://github.com/borismoore/jsviews + * See https://www.jsviews.com/#jsobservable and http://github.com/borismoore/jsviews @@include("templates/-copyright.txt") */ @@ -70,7 +70,7 @@ $expando = $.expando; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< JsViews >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /* JsViews: * Interactive data-driven views using templates and data-linking. - * See http://www.jsviews.com/#jsviews and http://github.com/BorisMoore/jsviews + * See https://www.jsviews.com/#jsviews and http://github.com/BorisMoore/jsviews @@include("templates/-copyright.txt") */ diff --git a/documentation/contents-categories.js b/documentation/contents-categories.js index 53cc2359..1ae34eed 100644 --- a/documentation/contents-categories.js +++ b/documentation/contents-categories.js @@ -237,8 +237,7 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "jsv-quickstart", - "label": "JsViews Quickstart", - "hidden": false + "label": "JsViews Quickstart" }, { "name": "temp", @@ -403,11 +402,6 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV ], "expanded": false }, - { - "name": "tagsOld", - "label": "OldCustom tags", - "hidden": true - }, { "name": "converters", "label": "Converters", @@ -425,7 +419,6 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "name": "settings", "label": "Settings", - "hidden": false, "categories": [ { "name": "settings/delimiters", @@ -450,14 +443,9 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "name": "onerror", "label": "Error handling" }, - { - "name": "settings/advanced", - "label": "Advanced settings" - }, { "name": "nojqueryapi", - "label": "JsRender without jQuery", - "hidden": true + "label": "JsRender without jQuery" }, { "name": "jsrobjects", @@ -466,13 +454,11 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "name": "viewsobject", "label": "$.views object", - "expanded": true, - "hidden": false + "expanded": true }, { "name": "templateobject", - "label": "template object", - "hidden": false + "label": "template object" }, { "name": "viewobject", @@ -480,26 +466,22 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "tagobject", - "label": "tag object", - "hidden": false + "label": "tag object" }, { - "name": "viewcontextobject", - "label": "View context object (ctx)", - "hidden": true + "name": "ctxobject", + "label": "View context object (ctx)" }, { - "name": "tagcontextobject", - "label": "Tag context object (tagCtx)", - "hidden": false + "name": "tagctxobject", + "label": "Tag context object (tagCtx)" + }, + { + "name": "globals", + "label": "Globals" } ], "expanded": true - }, - { - "name": "lifecycle", - "label": "Life-cycle events", - "hidden": true } ], "expanded": false @@ -564,33 +546,11 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "link2way", - "label": "Two-way binding", - "hidden": false + "label": "Two-way binding" }, { "name": "link-events", - "label": "Event bindings", - "hidden": false - }, - { - "name": "jsvviews", - "label": "View hierarchy", - "categories": [ - { - "name": "jsvgetindex", - "label": "getIndex()" - }, - { - "name": "jsvcontextualparams", - "label": "Contextual parameters" - }, - { - "name": "jsvparentdata", - "label": "Accessing parent data" - } - ], - "expanded": true, - "hidden": true + "label": "Event bindings" } ], "expanded": true @@ -601,33 +561,27 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "categories": [ { "name": "jsvassigntag", - "label": "{^{: ...}}", - "hidden": false + "label": "{^{: ...}}" }, { "name": "jsvhtmltag", - "label": "{^{> ...}}", - "hidden": false + "label": "{^{> ...}}" }, { "name": "jsvincludetag", - "label": "{^{include ...}}", - "hidden": false + "label": "{^{include ...}}" }, { "name": "jsvfortag", - "label": "{^{for ...}}", - "hidden": false + "label": "{^{for ...}}" }, { "name": "jsviftag", - "label": "{^{if ...}}", - "hidden": false + "label": "{^{if ...}}" }, { "name": "jsvpropstag", - "label": "{^{props ...}}", - "hidden": false + "label": "{^{props ...}}" }, { "name": "jsvradiogrouptag", @@ -635,18 +589,11 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "jsvelsetag", - "label": "{{else ...}}", - "hidden": false + "label": "{{else ...}}" }, { "name": "jsvontag", - "label": "{^{on ...}}", - "hidden": false - }, - { - "name": "jsvcustomtags", - "label": "Custom tags", - "hidden": true + "label": "{^{on ...}}" } ], "expanded": true @@ -664,8 +611,7 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "label": "$.link.myTmpl()" } ], - "expanded": true, - "hidden": false + "expanded": true }, { "name": "jsvapps", @@ -737,17 +683,14 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "mvvm-views", - "label": "MVVM -- Dynamic view hierarchy", - "hidden": false + "label": "MVVM -- Dynamic view hierarchy" } ], - "expanded": true, - "hidden": false + "expanded": true }, { "name": "toplink", "label": "Top-level data-linking", - "hidden": false, "categories": [ { "name": "jsv.toplink-true", @@ -793,80 +736,53 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "link-button", - "label": "button", - "hidden": false + "label": "button" } ], "expanded": true }, { "name": "link-text-html", - "label": "innerText / innerHTML", - "hidden": false + "label": "innerText / innerHTML" }, { "name": "link-css", - "label": "CSS attributes", - "hidden": false + "label": "CSS attributes" }, { "name": "link-class", - "label": "class", - "hidden": false + "label": "class" }, { "name": "link-visibility", - "label": "visibility", - "hidden": false + "label": "visibility" }, { "name": "link-elemattribs", - "label": "Element attributes/properties", - "hidden": false + "label": "Element attributes/properties" }, { "name": "link-tags", - "label": "Tag bindings", - "hidden": false + "label": "Tag bindings" }, { "name": "link-computed", - "label": "Computed observables", - "hidden": false + "label": "Computed observables" }, { "name": "link-svg", - "label": "SVG elements", - "hidden": false + "label": "SVG elements" }, { "name": "link-contenteditable", "label": "contenteditable elements" } ], - "expanded": true, - "hidden": false - }, - { - "name": "jsvunlink", - "label": "unlink()", - "categories": [ - { - "name": "jsv.d.unlink", - "label": "$.unlink()" - }, - { - "name": "jsv.db.unlink", - "label": "$(...).unlink()" - } - ], - "expanded": true, - "hidden": true + "expanded": true }, { "name": "jsvsettings", "label": "Settings", - "hidden": false, "categories": [ { "name": "jsvsettings/delimiters", @@ -878,8 +794,7 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "jsvsettings/trigger", - "label": "Trigger", - "hidden": false + "label": "Trigger" }, { "name": "jsvsettings/allowcode", @@ -903,13 +818,11 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "name": "jsvviewsobject", "label": "$.views object", - "expanded": true, - "hidden": false + "expanded": true }, { "name": "jsvtemplateobject", - "label": "template object", - "hidden": false + "label": "template object" }, { "name": "jsvviewobject", @@ -918,46 +831,36 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "jsvtagobject", - "label": "tag object", - "hidden": false + "label": "tag object" }, { - "name": "jsvviewcontextobject", - "label": "View context object (ctx)", - "hidden": true + "name": "jsvctxobject", + "label": "View context object (ctx)" }, { - "name": "jsvtagcontextobject", - "label": "Tag context object (tagCtx)", - "hidden": true + "name": "jsvtagctxobject", + "label": "Tag context object (tagCtx)" }, { - "name": "jsvlinkcontextobject", - "label": "Link context object (linkCtx)", - "hidden": true + "name": "jsvlinkctxobject", + "label": "Link context object (linkCtx)" }, { "name": "eventArgs", - "label": "eventArgs object", - "hidden": true + "label": "eventArgs object" + }, + { + "name": "jsvglobals", + "label": "Globals" } ], "expanded": true }, { - "name": "other", - "label": "And computed observable, {{on}}, DataMap. lateRender...", - "hidden": true - }, - { - "name": "jsvlifecycle", - "label": "Life-cycle events", - "hidden": true - }, - { - "name": "replace-target", - "label": "Replace placeholder target", - "hidden": true + "name": "jsvunlink", + "label": "$.unlink()", + "categories": [], + "expanded": true } ], "expanded": false @@ -1028,23 +931,19 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "observe", - "label": "$.observe()", - "hidden": false + "label": "$.observe()" }, { "name": "unobserve", - "label": "$.unobserve()", - "hidden": false + "label": "$.unobserve()" }, { "name": "observeAll", - "label": "$.observable().observeAll()", - "hidden": false + "label": "$.observable().observeAll()" }, { "name": "unobserveAll", - "label": "$.observable().unobserveAll()", - "hidden": false + "label": "$.observable().unobserveAll()" } ], "expanded": true @@ -1088,7 +987,7 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "categories": [ { "name": "samples/jsr/composition/tmpl", - "label": "tmpl parameter" + "label": "tmpl property" }, { "name": "samples/jsr/composition/from-strings", @@ -1136,10 +1035,10 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "expanded": true }, { - "hidden": true, "filter": "jsv", "name": "samples/jso", - "label": "JsObservable samples" + "label": "JsObservable samples", + "hidden": true }, { "filter": "jsv", @@ -1273,8 +1172,7 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV "categories": [ { "name": "samples/computed/fullname", - "label": "fullName variants", - "hidden": false + "label": "fullName variants" }, { "name": "samples/computed/shopping-cart", @@ -1371,53 +1269,43 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV }, { "name": "samples/tag-controls/jqui/toolbar", - "label": "button radio checkbox...", - "hidden": false + "label": "button radio checkbox..." }, { "name": "samples/tag-controls/jqui/tabs", - "label": "tabs control (jQuery UI)", - "hidden": false + "label": "tabs control (jQuery UI)" }, { "name": "samples/tag-controls/jqui/menu", - "label": "menu control", - "hidden": false + "label": "menu control" }, { "name": "samples/tag-controls/jqui/selectmenu", - "label": "selectmenu control", - "hidden": false + "label": "selectmenu control" }, { "name": "samples/tag-controls/jqui/progressbar", - "label": "progressbar control", - "hidden": false + "label": "progressbar control" }, { "name": "samples/tag-controls/jqui/accordion", - "label": "accordion control", - "hidden": false + "label": "accordion control" }, { "name": "samples/tag-controls/jqui/autocomplete", - "label": "autocomplete control", - "hidden": false + "label": "autocomplete control" }, { "name": "samples/tag-controls/jqui/selectable", - "label": "selectable control", - "hidden": false + "label": "selectable control" }, { "name": "samples/tag-controls/jqui/sortable", - "label": "sortable control", - "hidden": false + "label": "sortable control" }, { "name": "samples/tag-controls/jqui/resizable", - "label": "resizable control", - "hidden": false + "label": "resizable control" }, { "name": "samples/tag-controls/jqui/draggable-droppable", @@ -1564,6 +1452,10 @@ content.categories = content.useStorage && $.parseJSON(localStorage.getItem("JsV } ], "expanded": true + }, + { + "name": "typescript", + "label": "TypeScript declaration files" } ], "expanded": true diff --git a/documentation/contents-categories.min.js b/documentation/contents-categories.min.js index d5e17d80..24b32ce9 100644 --- a/documentation/contents-categories.min.js +++ b/documentation/contents-categories.min.js @@ -1,2 +1,2 @@ -var content=$.views.documentation.content;content.categories=content.useStorage&&$.parseJSON(localStorage.getItem("JsViewsDocCategories"))||[{jsrender:{loaded:!0,name:"home",label:"JsRender",heading:"Best-of-breed templating",description:"Simple and intuitive, powerful and extensible, lightning fast",key:"jsrender","class":"home",home:{prefix:"jsr",next:"jsrplaying",leftsections:[{_type:"para",title:"Here's a first example of the power and simplicity of JsRender templates:",text:""},{_type:"data",title:"Some data:",data:[{name:"Robert",nickname:"Bob",showNickname:!0},{name:"Susan",nickname:"Sue",showNickname:!1}]},{_type:"template",title:"A template (with a conditional section using an {{if...}} tag):",markup:"
\n Name: {{:name}}\n {{if showNickname && nickname}}\n (Goes by {{:nickname}})\n {{/if}}\n
"}],sections:[{_type:"para",title:"",text:"And a working demo, you can play with and modify:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{:name}}\n```\n\nRender the `name` property of the current data item\n\n```jsr\n{{if showNickname && nickname}}...{{/if}}\n```\n\nAn `{{if}}` tag: Render the block content only if the expression (`showNickname && nickname`) is true..."}],data:[{name:"Robert",nickname:"Bob",showNickname:!0},{name:"Susan",nickname:"Sue",showNickname:!1}],markup:"
\n Name: {{:name}}\n {{if showNickname && nickname}}\n (Goes by {{:nickname}})\n {{/if}}\n
",jsrJsvJqui:"jsr",height:"85",header:"",action:""}],title:""},loading:""},jsviews:{loaded:!0,name:"home",label:"JsViews",heading:"The next-generation MVVM framework - bringing templates to life",description:"The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates",key:"jsviews","class":"home",home:{prefix:"jsv",next:"jsvplaying",leftsections:[{_type:"code",title:"The JsViews framework brings declarative data-binding to JsRender templates, supports MVVM and MVP (custom tag controls), and much more...

Here's a small example. We'll start with some data:",code:'...\n{\n "name": "Robert",\n "nickname": "Bob",\n "showNickname": true\n}\n...'},{_type:"template",title:"and a data-bound template:",markup:'
\n Name: {^{>name}}\n {^{if showNickname && nickname}}\n (Goes by )\n {{/if}}\n
\n'},{_type:"template",title:"And within the template we will use two-way binding to allow editing of the underlying data:",markup:'{^{if editable}}\n
\n \n \n \n
\n{{/if}}\n'}],sections:[{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{^{>name}} ... {^{if showNickname && nickname}}...\n```\n\nThese are data-bound tags. When the underlying data changes the data-value within the rendered template automatically updates too.\n\nChanging `{{if ...}}` to `{^{if ...}}` makes it data-bound. Now, when the underlying data value or expression changes the whole rendered block content is automatically removed or reinserted.\n\n```jsr\n\n```\n\nYou can use element-based data-linking too. Here, the inner-text of the `` element is data-bound to the `nickname` data value.\n\n```jsr\n\n```\n\nAnd here, the input is automatically two-way data-bound to the `name` property of the underlying data. Change the value in the text box, and the underlying data automatically updates. Any other parts of the template that are data-linked to the same data property will then immediately update too.'}],markup:"",height:"115",html:'
\n\n',code:'var data = [\n {\n "name": "Robert",\n "nickname": "Bob",\n "showNickname": true\n },\n {\n "name": "Susan",\n "nickname": "Sue",\n "showNickname": false\n }\n];\n\nvar template = $.templates("#theTmpl");\n\ntemplate.link("#result", data);',nocss:!1,action:"append",header:""}]},loading:""},jsobservable:{loaded:!0,name:"home",label:"JsObservable",heading:"Live observable data in the browser",description:"Code and declarative data-binding working hand-in-hand, adding interactivity and responsiveness to your single-page apps",key:"jsobservable","class":"home",home:{prefix:"jso",next:"getstarted",leftsections:[{_type:"para",title:"The JsObservable library is part of JsViews.",text:"It is used by JsViews to provide the declarative data-binding. And it also allows your code in a JsViews app to trigger data changes, or to 'observe' data-changes programmatically."},{_type:"code",title:'We\'ll add some code to a "declarative" JsViews sample. Take some data, and a data-bound template:',code:'var people = [\n {name: "Adriana"},\n {name: "Robert"}\n];'},{_type:"template",title:"",markup:'{^{for people}}\n ...\n \n ...\n{{/for}}'},{_type:"code",title:"And add some button click handlers which call JsObservable APIs to make observable changes to the underlying data:",code:'$("#result")\n .on("click", ".change", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", ...);\n })\n .on("click", ".remove", function() {\n var index = $.view(this).index;\n $.observable(people).remove(index);\n });\n'},{_type:"code",title:"",code:"$.observable(people).insert({name: ...});\n"}],sections:[{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.observable(object).setProperty(...);\n```\n\n`$.observable(dataItem)` makes `dataItem` *"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.\n\n`$.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 people}}` tag. Here the rendered block content of the tag will be incrementally added/removed for each added/removed array item - in response to your change.\n\n```js\n$.observable(array).insert(...);\n```\n\n`$.view(elem)` allows you to get from any DOM element to the *view* object for that part of the rendered content, and hence to the underlying data, index, etc.'}],markup:"",height:"175",html:'
\n\n',code:'var template = $.templates("#theTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar counter = 1;\n\ntemplate.link("#result", {people: people});\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name" + counter++});\n})\n\n$("#result")\n .on("click", ".change", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", dataItem.name + "*");\n })\n .on("click", ".remove", function() {\n var index = $.view(this).index;\n $.observable(people).remove(index);\n });'}]},loading:""}},{name:"getstarted",label:"Getting started",heading:"Getting Started",description:"First steps with JsRender, JsViews and JsObservable",categories:[{name:"jsrplaying",label:"Playing with JsRender"},{name:"jsr-quickstart",label:"JsRender Quickstart",expanded:!0},{name:"jsr-node-quickstart",label:"JsRender Node.js Quickstart"},{name:"jsvplaying",label:"Playing with JsViews"},{name:"jsv-quickstart",label:"JsViews Quickstart",hidden:!1},{name:"temp",label:"JsViews QS end",hidden:!0}],expanded:!0},{filter:"jsr",name:"jsrapi",label:"JsRender API - Templated UI",heading:"JsRender API documentation",description:"Detailed API docs on using JsRender templates",categories:[{name:"tmplsyntax",label:"Template syntax and structure",categories:[{name:"tagsyntax",label:"Tag syntax"},{name:"paths",label:"Paths and expressions"},{name:"views",label:"View hierarchy",categories:[{name:"getindex",label:"getIndex()"},{name:"contextualparams",label:"Contextual parameters"},{name:"parentdata",label:"Accessing parent data"}],expanded:!0}],expanded:!0},{name:"jsrtags",label:"Template tags",categories:[{name:"assigntag",label:"{{: ...}}"},{name:"htmltag",label:"{{> ...}}"},{name:"includetag",label:"{{include ...}}"},{name:"fortag",label:"{{for ...}}"},{name:"propstag",label:"{{props ...}}"},{name:"iftag",label:"{{if ...}}"},{name:"elsetag",label:"{{else ...}}"},{name:"allowcodetag",label:"{{* ... }} and {{*: ...}}"},{name:"customtagsapi",label:"Custom tags"},{name:"commenttag",label:"{{!-- ... --}}"}],expanded:!0},{name:"rendertmpl",label:"Render a template",categories:[{name:"tmplrender",label:"myTmpl.render()"},{name:"d.render",label:"$.render.myTmpl()"},{name:"db.render",label:'$("#myTmpl").render()'}],expanded:!0},{name:"apps",label:"Building apps",categories:[{name:"jsrmodel",label:"Data / View Model",categories:[{name:"viewmodelsapi",label:"$.views.viewModels()"}],expanded:!1},{name:"compiletmpl",label:"Templates",categories:[{name:"d.templates",label:"$.templates()"}],expanded:!1},{name:"helpers",label:"Helpers",categories:[{name:"helpersapi",label:"$.views.helpers()"}],expanded:!1},{name:"tags",label:"Custom tags",categories:[{name:"tagsapi",label:"$.views.tags()"}],expanded:!1},{name:"tagsOld",label:"OldCustom tags",hidden:!0},{name:"converters",label:"Converters",categories:[{name:"convertersapi",label:"$.views.converters()"}],expanded:!1}],expanded:!0},{name:"settings",label:"Settings",hidden:!1,categories:[{name:"settings/delimiters",label:"Delimiters"},{name:"settings/debugmode",label:"Debug mode"},{name:"settings/allowcode",label:"Allow code"}],expanded:!1},{name:"advanced",label:"Advanced",categories:[{name:"onerror",label:"Error handling"},{name:"settings/advanced",label:"Advanced settings"},{name:"nojqueryapi",label:"JsRender without jQuery",hidden:!0},{name:"jsrobjects",label:"JsRender objects",categories:[{name:"viewsobject",label:"$.views object",expanded:!0,hidden:!1},{name:"templateobject",label:"template object",hidden:!1},{name:"viewobject",label:"view object"},{name:"tagobject",label:"tag object",hidden:!1},{name:"viewcontextobject",label:"View context object (ctx)",hidden:!0},{name:"tagcontextobject",label:"Tag context object (tagCtx)",hidden:!1}],expanded:!0},{name:"lifecycle",label:"Life-cycle events",hidden:!0}],expanded:!1},{name:"jsrnode",label:"JsRender on Node.js",categories:[{name:"node/install",label:"Installation and usage"},{name:"node/filetmpls",label:"File-based templates"},{name:"node/express-hapi",label:"Express and Hapi integration"},{name:"node/server-browser",label:"Server/browser shared templates"},{name:"node/browserify",label:"Browserify support",expanded:!0},{name:"node/webpack",label:"Webpack support"}],expanded:!0}],expanded:!0},{filter:"jsv",name:"jsvapi",label:"JsViews API - Data-driven UI",heading:"JsViews API documentation",description:"Detailed API docs on using JsViews for dynamic data-driven sites, or MVVM",categories:[{name:"linked-template-syntax",label:"Data-linked template syntax",categories:[{name:"linked-tag-syntax",label:"Data-linked tags"},{name:"linked-elem-syntax",label:"Data-linked elements"},{name:"linked-paths",label:"Data-linked paths"},{name:"link2way",label:"Two-way binding",hidden:!1},{name:"link-events",label:"Event bindings",hidden:!1},{name:"jsvviews",label:"View hierarchy",categories:[{name:"jsvgetindex",label:"getIndex()"},{name:"jsvcontextualparams",label:"Contextual parameters"},{name:"jsvparentdata",label:"Accessing parent data"}],expanded:!0,hidden:!0}],expanded:!0},{name:"jsvtags",label:"Template tags",categories:[{name:"jsvassigntag",label:"{^{: ...}}",hidden:!1},{name:"jsvhtmltag",label:"{^{> ...}}",hidden:!1},{name:"jsvincludetag",label:"{^{include ...}}",hidden:!1},{name:"jsvfortag",label:"{^{for ...}}",hidden:!1},{name:"jsviftag",label:"{^{if ...}}",hidden:!1},{name:"jsvpropstag",label:"{^{props ...}}",hidden:!1},{name:"jsvradiogrouptag",label:"{^{radiogroup ...}}"},{name:"jsvelsetag",label:"{{else ...}}",hidden:!1},{name:"jsvontag",label:"{^{on ...}}",hidden:!1},{name:"jsvcustomtags",label:"Custom tags",hidden:!0}],expanded:!0},{name:"jsvlinktmpl",label:"Render and link a template",categories:[{name:"jsvtmpllink",label:"myTmpl.link()"},{name:"jsv.d.link",label:"$.link.myTmpl()"}],expanded:!0,hidden:!1},{name:"jsvapps",label:"Building apps",categories:[{name:"jsvmodel",label:"Data / View Model",categories:[{name:"jsvviewmodelsapi",label:"$.views.viewModels()"}],expanded:!1},{name:"linkedtmpls",label:"Data-linked templates"},{name:"jsvtagcontrols",label:"Custom tag controls",categories:[{name:"tagoptions",label:"Tag control options"},{name:"tagstructure",label:"Tag control structure",expanded:!0},{name:"taglifecycle",label:"Tag control life-cycle"},{name:"tagpatterns",label:"Tag design patterns",categories:[{name:"renderingpatterns",label:"Layout and rendering"},{name:"bindingpatterns",label:"Data binding",expanded:!0},{name:"hierarchypatterns",label:"Tag hierarchy"},{name:"todo",label:"TODO",hidden:!0}],expanded:!1}],expanded:!0},{name:"jsvhelpers-converters",label:"Helpers and converters"},{name:"mvvm-views",label:"MVVM -- Dynamic view hierarchy",hidden:!1}],expanded:!0,hidden:!1},{name:"toplink",label:"Top-level data-linking",hidden:!1,categories:[{name:"jsv.toplink-true",label:"Declarative: $.link(true, ...)"},{name:"jsv.toplink-expr",label:"Programmatic: $.link(...)"}],expanded:!0},{name:"$view",label:"Views: from UI to data",categories:[{name:"jsv.d.view",label:"$.view()"}],expanded:!0},{name:"link-targets",label:"Targets for data-linking",categories:[{name:"link-formelems",label:"Form elements",categories:[{name:"link-input",label:"textbox / checkbox / radio"},{name:"link-select",label:"select"},{name:"link-textarea",label:"textarea"},{name:"link-button",label:"button",hidden:!1}],expanded:!0},{name:"link-text-html",label:"innerText / innerHTML",hidden:!1},{name:"link-css",label:"CSS attributes",hidden:!1},{name:"link-class",label:"class",hidden:!1},{name:"link-visibility",label:"visibility",hidden:!1},{name:"link-elemattribs",label:"Element attributes/properties",hidden:!1},{name:"link-tags",label:"Tag bindings",hidden:!1},{name:"link-computed",label:"Computed observables",hidden:!1},{name:"link-svg",label:"SVG elements",hidden:!1},{name:"link-contenteditable",label:"contenteditable elements"}],expanded:!0,hidden:!1},{name:"jsvunlink",label:"unlink()",categories:[{name:"jsv.d.unlink",label:"$.unlink()"},{name:"jsv.db.unlink",label:"$(...).unlink()"}],expanded:!0,hidden:!0},{name:"jsvsettings",label:"Settings",hidden:!1,categories:[{name:"jsvsettings/delimiters",label:"Delimiters"},{name:"jsvsettings/debugmode",label:"Debug mode"},{name:"jsvsettings/trigger",label:"Trigger",hidden:!1},{name:"jsvsettings/allowcode",label:"Allow code"}],expanded:!1},{name:"jsvadvanced",label:"Advanced",categories:[{name:"jsvsettings/advanced",label:"Advanced settings"},{name:"jsvobjects",label:"JsViews objects",categories:[{name:"jsvviewsobject",label:"$.views object",expanded:!0,hidden:!1},{name:"jsvtemplateobject",label:"template object",hidden:!1},{name:"jsvviewobject",label:"view object",expanded:!0},{name:"jsvtagobject",label:"tag object",hidden:!1},{name:"jsvviewcontextobject",label:"View context object (ctx)",hidden:!0},{name:"jsvtagcontextobject",label:"Tag context object (tagCtx)",hidden:!0},{name:"jsvlinkcontextobject",label:"Link context object (linkCtx)",hidden:!0},{name:"eventArgs",label:"eventArgs object",hidden:!0}],expanded:!0},{name:"other",label:"And computed observable, {{on}}, DataMap. lateRender...",hidden:!0},{name:"jsvlifecycle",label:"Life-cycle events",hidden:!0},{name:"replace-target",label:"Replace placeholder target",hidden:!0}],expanded:!1}],expanded:!0},{filter:"jsv",name:"jsoapi",label:"JsObservable API - Observing data",heading:"JsObservable API documentation",description:"Detailed API docs on using JsObservable for observing or triggering data changes in a single-page app",categories:[{name:"$observable",label:"Observable objects and arrays"},{name:"propchange",label:"Modify an object observably",categories:[{name:"setprop",label:"$.observable(object).setProperty()"},{name:"removeprop",label:"$.observable(obj).removeProperty()"}],expanded:!0},{name:"arrchange",label:"Modify an array observably",categories:[{name:"insert",label:"$.observable(array).insert()"},{name:"remove",label:"$.observable(array).remove()"},{name:"move",label:"$.observable(array).move()"},{name:"refresh",label:"$.observable(array).refresh()"}],expanded:!0},{name:"observeobjectsarrays",label:"Respond to data changes",categories:[{name:"onpropchange",label:"onPropertyChange"},{name:"onarrchange",label:"onArrayChange"},{name:"observe",label:"$.observe()",hidden:!1},{name:"unobserve",label:"$.unobserve()",hidden:!1},{name:"observeAll",label:"$.observable().observeAll()",hidden:!1},{name:"unobserveAll",label:"$.observable().unobserveAll()",hidden:!1}],expanded:!0},{name:"computed",label:"Computed observables"},{name:"jsoadvanced",label:"Advanced",categories:[{name:"namespaces",label:"Namespaces"}],expanded:!1}],expanded:!0},{name:"samples",label:"Samples",heading:"Samples for JsRender, JsViews or JsObservable",description:"Examples of some of the ways you can use JsRender templates, JsViews tag controls, and more",categories:[{filter:"jsr",name:"samples/jsr",label:"JsRender samples",categories:[{name:"samples/jsr/converters",label:"Converters and encoding"},{name:"samples/jsr/composition",label:"Template composition",categories:[{name:"samples/jsr/composition/tmpl",label:"tmpl parameter"},{name:"samples/jsr/composition/from-strings",label:"From strings"},{name:"samples/jsr/composition/remote-tmpl",label:"Remote templates"},{name:"samples/jsr/composition/sub-tmpl",label:"Using sub-templates"},{name:"samples/jsr/composition/tmpl-objects",label:"Contextual template objects"}],expanded:!0},{name:"samples/jsr/tags",label:"Custom tags",categories:[{name:"samples/jsr/tags/wrap-content",label:"Wrapping content"},{name:"samples/jsr/tags/extend-for",label:"Extending for"}],expanded:!0},{name:"samples/jsr/helpers",label:"Helpers"},{name:"samples/jsr/paths",label:"Paths"}],expanded:!0},{hidden:!0,filter:"jsv",name:"samples/jso",label:"JsObservable samples"},{filter:"jsv",name:"samples/jsv",label:"JsViews samples",categories:[{name:"samples/data-link",label:"Data-linking tags and elements",categories:[{name:"samples/data-link/from-render-to-link",label:"From rendering to linking"},{name:"samples/data-link/for-and-if",label:"Linking {^{for}} and {^{if}}"},{name:"samples/data-link/class",label:"Linking class"},{name:"samples/data-link/toggle",label:"Toggling class with data-link"},{name:"samples/data-link/attributes",label:"Linking attributes"},{name:"samples/data-link/visibility",label:"Linking visibility"},{name:"samples/data-link/hover",label:"Linking visibility and hover"},{name:"samples/data-link/css",label:"Linking CSS attributes"},{name:"samples/data-link/svg",label:"Linking SVG elements"},{name:"samples/data-link/computed",label:"Computed ....!!",hidden:!0}],expanded:!0},{name:"samples/editable",label:"Editable data",categories:[{name:"samples/editable/tags",label:"Data-linked tags"},{name:"samples/editable/elems",label:"Data-linked elements"},{name:"samples/editable/toplevel-for",label:"Top-level elems with {for...}"},{name:"samples/editable/observe",label:"$.observe()"},{name:"samples/editable/compiled",label:"Compiled View Models"},{name:"samples/editable/submit",label:"Submit changes"},{name:"samples/editable/hash",label:"hash/dictionary"}],expanded:!0},{name:"samples/form-elems",label:"Form elements",categories:[{name:"samples/form-els/simple",label:"Form element binding"},{name:"samples/form-els/array-binding",label:"Array binding"},{name:"samples/form-els/converters",label:"2-way binding and converters"},{name:"samples/form-els/visible-binding",label:"Form elements and visibility"},{name:"samples/form-els/edit",label:"Edit tag control",hidden:!0},{name:"samples/form-els/validation",label:"With validation",hidden:!0},{name:"samples/form-els/submit",label:"Submitting the form",hidden:!0}],expanded:!0},{name:"samples/computed",label:"Computed observables",categories:[{name:"samples/computed/fullname",label:"fullName variants",hidden:!1},{name:"samples/computed/shopping-cart",label:"Shopping cart"},{name:"samples/computed/team-manager",label:"Team manager"}],expanded:!1},{name:"samples/tag-controls",label:"Tag controls",categories:[{name:"samples/tag-controls/jqui",label:"jQueryUI widget controls",categories:[{name:"samples/tag-controls/jqui/api",label:"Accessing widget APIs"},{name:"samples/tag-controls/jqui/datepicker",label:"datepicker control",categories:[{name:"samples/tag-controls/jqui/datepicker/simple",label:"Simple datepicker"},{name:"samples/tag-controls/jqui/datepicker/variants",label:"datepicker variants"},{name:"samples/tag-controls/jqui/datepicker/formats",label:"Date formats"},{name:"samples/tag-controls/jqui/datepicker/with-validation",label:"With validation"},{name:"samples/tag-controls/jqui/datepicker/with-validation-wizard",label:"With validation wizard"}],expanded:!1},{name:"samples/tag-controls/jqui/slider",label:"slider control (jQuery UI)",categories:[{name:"samples/tag-controls/jqui/slider/simple",label:"Simple slider"},{name:"samples/tag-controls/jqui/slider/variants",label:"slider variants"},{name:"samples/tag-controls/jqui/slider/with-validation",label:"With validation"},{name:"samples/tag-controls/jqui/slider/color-picker",label:"Color picker"}],expanded:!1},{name:"samples/tag-controls/jqui/spinner",label:"spinner control",categories:[{name:"samples/tag-controls/jqui/spinner/variants",label:"spinner variants",expanded:!0},{name:"samples/tag-controls/jqui/spinner/formats",label:"Formats and cultures"},{name:"samples/tag-controls/jqui/timespinner",label:"timespinner control"}],expanded:!1},{name:"samples/tag-controls/jqui/toolbar",label:"button radio checkbox...",hidden:!1},{name:"samples/tag-controls/jqui/tabs",label:"tabs control (jQuery UI)",hidden:!1},{name:"samples/tag-controls/jqui/menu",label:"menu control",hidden:!1},{name:"samples/tag-controls/jqui/selectmenu",label:"selectmenu control",hidden:!1},{name:"samples/tag-controls/jqui/progressbar",label:"progressbar control",hidden:!1},{name:"samples/tag-controls/jqui/accordion",label:"accordion control",hidden:!1},{name:"samples/tag-controls/jqui/autocomplete",label:"autocomplete control",hidden:!1},{name:"samples/tag-controls/jqui/selectable",label:"selectable control",hidden:!1},{name:"samples/tag-controls/jqui/sortable",label:"sortable control",hidden:!1},{name:"samples/tag-controls/jqui/resizable",label:"resizable control",hidden:!1},{name:"samples/tag-controls/jqui/draggable-droppable",label:"draggable droppable"}],expanded:!0},{name:"samples/tag-controls/tabs",label:"tabs control"},{name:"samples/tag-controls/multiselect",label:"multiselect control"},{name:"samples/tag-controls/tree",label:"tree control",categories:[{name:"samples/tag-controls/tree/visible-binding",label:"tree with 'visible' binding"},{name:"samples/tag-controls/tree/if-binding",label:"tree with if-binding"},{name:"samples/tag-controls/tree/editable",label:"Editable tree"}],expanded:!1},{name:"samples/tag-controls/validate",label:"validate control",categories:[{name:"samples/tag-controls/validate/simple",label:"Simple validate"},{name:"samples/tag-controls/validate/group",label:"Validation group"},{name:"samples/tag-controls/validate/array-binding",label:"Array binding"}],expanded:!1},{name:"samples/tag-controls/simple-textbox",label:"simple textbox control",expanded:!0},{name:"samples/tag-controls/purchases",label:"purchases control"},{name:"samples/tag-controls/slider",label:"slider control"},{name:"samples/tag-controls/areaslider",label:"areaslider control"},{name:"samples/tag-controls/spinblock",label:"spinblock control"},{name:"samples/tag-controls/colorpicker",label:"colorpicker control"},{name:"samples/tag-controls/jsonview",label:"jsonview control"}],expanded:!0}],expanded:!0}],expanded:!0},{name:"download",label:"Download",heading:"Downloading JsViews, JsRender and JsObservable",description:"",categories:[{name:"download",label:"Latest version"},{name:"download/specific",label:"Specific versions",expanded:!0,hidden:!0},{name:"download/pages",label:"Example pages",categories:[{name:"download/pages-jsr-jq",label:"JsRender with jQuery"},{name:"download/pages-jsr",label:"JsRender without jQuery"},{name:"download/pages-jsv",label:"JsViews"}],expanded:!0},{name:"download/jsrplugins",label:"JsRender plugins",expanded:!0},{name:"download/jsvplugins",label:"JsViews plugins",categories:[{name:"download/sample-tagcontrols",label:"Sample tag controls"},{name:"download/jqueryui-tagcontrols",label:"jQuery UI tag controls"}],expanded:!0}],expanded:!0},{name:"community",label:"JsViews Community",heading:"JsViews and JsRender Community",description:"Viewing the source code, filing bugs or feature requests...",categories:[{name:"github",label:"GitHub",expanded:!0}],expanded:!0}]; +var content=$.views.documentation.content;content.categories=content.useStorage&&$.parseJSON(localStorage.getItem("JsViewsDocCategories"))||[{jsrender:{loaded:!0,name:"home",label:"JsRender",heading:"Best-of-breed templating",description:"Simple and intuitive, powerful and extensible, lightning fast",key:"jsrender","class":"home",home:{prefix:"jsr",next:"jsrplaying",leftsections:[{_type:"para",title:"Here's a first example of the power and simplicity of JsRender templates:",text:""},{_type:"data",title:"Some data:",data:[{name:"Robert",nickname:"Bob",showNickname:!0},{name:"Susan",nickname:"Sue",showNickname:!1}]},{_type:"template",title:"A template (with a conditional section using an {{if...}} tag):",markup:"
\n Name: {{:name}}\n {{if showNickname && nickname}}\n (Goes by {{:nickname}})\n {{/if}}\n
"}],sections:[{_type:"para",title:"",text:"And a working demo, you can play with and modify:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{:name}}\n```\n\nRender the `name` property of the current data item\n\n```jsr\n{{if showNickname && nickname}}...{{/if}}\n```\n\nAn `{{if}}` tag: Render the block content only if the expression (`showNickname && nickname`) is true..."}],data:[{name:"Robert",nickname:"Bob",showNickname:!0},{name:"Susan",nickname:"Sue",showNickname:!1}],markup:"
\n Name: {{:name}}\n {{if showNickname && nickname}}\n (Goes by {{:nickname}})\n {{/if}}\n
",jsrJsvJqui:"jsr",height:"85",header:"",action:""}],title:""},loading:""},jsviews:{loaded:!0,name:"home",label:"JsViews",heading:"The next-generation MVVM framework - bringing templates to life",description:"The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates",key:"jsviews","class":"home",home:{prefix:"jsv",next:"jsvplaying",leftsections:[{_type:"code",title:"The JsViews framework brings declarative data-binding to JsRender templates, supports MVVM and MVP (custom tag controls), and much more...

Here's a small example. We'll start with some data:",code:'...\n{\n "name": "Robert",\n "nickname": "Bob",\n "showNickname": true\n}\n...'},{_type:"template",title:"and a data-bound template:",markup:'
\n Name: {^{>name}}\n {^{if showNickname && nickname}}\n (Goes by )\n {{/if}}\n
\n'},{_type:"template",title:"And within the template we will use two-way binding to allow editing of the underlying data:",markup:'{^{if editable}}\n
\n \n \n \n
\n{{/if}}\n'}],sections:[{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{^{>name}} ... {^{if showNickname && nickname}}...\n```\n\nThese are data-bound tags. When the underlying data changes the data-value within the rendered template automatically updates too.\n\nChanging `{{if ...}}` to `{^{if ...}}` makes it data-bound. Now, when the underlying data value or expression changes the whole rendered block content is automatically removed or reinserted.\n\n```jsr\n\n```\n\nYou can use element-based data-linking too. Here, the inner-text of the `` element is data-bound to the `nickname` data value.\n\n```jsr\n\n```\n\nAnd here, the input is automatically two-way data-bound to the `name` property of the underlying data. Change the value in the text box, and the underlying data automatically updates. Any other parts of the template that are data-linked to the same data property will then immediately update too.'}],markup:"",height:"115",html:'
\n\n',code:'var data = [\n {\n "name": "Robert",\n "nickname": "Bob",\n "showNickname": true\n },\n {\n "name": "Susan",\n "nickname": "Sue",\n "showNickname": false\n }\n];\n\nvar template = $.templates("#theTmpl");\n\ntemplate.link("#result", data);',nocss:!1,action:"append",header:""}]},loading:""},jsobservable:{loaded:!0,name:"home",label:"JsObservable",heading:"Live observable data in the browser",description:"Code and declarative data-binding working hand-in-hand, adding interactivity and responsiveness to your single-page apps",key:"jsobservable","class":"home",home:{prefix:"jso",next:"getstarted",leftsections:[{_type:"para",title:"The JsObservable library is part of JsViews.",text:"It is used by JsViews to provide the declarative data-binding. And it also allows your code in a JsViews app to trigger data changes, or to 'observe' data-changes programmatically."},{_type:"code",title:'We\'ll add some code to a "declarative" JsViews sample. Take some data, and a data-bound template:',code:'var people = [\n {name: "Adriana"},\n {name: "Robert"}\n];'},{_type:"template",title:"",markup:'{^{for people}}\n ...\n \n ...\n{{/for}}'},{_type:"code",title:"And add some button click handlers which call JsObservable APIs to make observable changes to the underlying data:",code:'$("#result")\n .on("click", ".change", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", ...);\n })\n .on("click", ".remove", function() {\n var index = $.view(this).index;\n $.observable(people).remove(index);\n });\n'},{_type:"code",title:"",code:"$.observable(people).insert({name: ...});\n"}],sections:[{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.observable(object).setProperty(...);\n```\n\n`$.observable(dataItem)` makes `dataItem` *"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.\n\n`$.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 people}}` tag. Here the rendered block content of the tag will be incrementally added/removed for each added/removed array item - in response to your change.\n\n```js\n$.observable(array).insert(...);\n```\n\n`$.view(elem)` allows you to get from any DOM element to the *view* object for that part of the rendered content, and hence to the underlying data, index, etc.'}],markup:"",height:"175",html:'
\n\n',code:'var template = $.templates("#theTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar counter = 1;\n\ntemplate.link("#result", {people: people});\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name" + counter++});\n})\n\n$("#result")\n .on("click", ".change", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", dataItem.name + "*");\n })\n .on("click", ".remove", function() {\n var index = $.view(this).index;\n $.observable(people).remove(index);\n });'}]},loading:""}},{name:"getstarted",label:"Getting started",heading:"Getting Started",description:"First steps with JsRender, JsViews and JsObservable",categories:[{name:"jsrplaying",label:"Playing with JsRender"},{name:"jsr-quickstart",label:"JsRender Quickstart",expanded:!0},{name:"jsr-node-quickstart",label:"JsRender Node.js Quickstart"},{name:"jsvplaying",label:"Playing with JsViews"},{name:"jsv-quickstart",label:"JsViews Quickstart"},{name:"temp",label:"JsViews QS end",hidden:!0}],expanded:!0},{filter:"jsr",name:"jsrapi",label:"JsRender API - Templated UI",heading:"JsRender API documentation",description:"Detailed API docs on using JsRender templates",categories:[{name:"tmplsyntax",label:"Template syntax and structure",categories:[{name:"tagsyntax",label:"Tag syntax"},{name:"paths",label:"Paths and expressions"},{name:"views",label:"View hierarchy",categories:[{name:"getindex",label:"getIndex()"},{name:"contextualparams",label:"Contextual parameters"},{name:"parentdata",label:"Accessing parent data"}],expanded:!0}],expanded:!0},{name:"jsrtags",label:"Template tags",categories:[{name:"assigntag",label:"{{: ...}}"},{name:"htmltag",label:"{{> ...}}"},{name:"includetag",label:"{{include ...}}"},{name:"fortag",label:"{{for ...}}"},{name:"propstag",label:"{{props ...}}"},{name:"iftag",label:"{{if ...}}"},{name:"elsetag",label:"{{else ...}}"},{name:"allowcodetag",label:"{{* ... }} and {{*: ...}}"},{name:"customtagsapi",label:"Custom tags"},{name:"commenttag",label:"{{!-- ... --}}"}],expanded:!0},{name:"rendertmpl",label:"Render a template",categories:[{name:"tmplrender",label:"myTmpl.render()"},{name:"d.render",label:"$.render.myTmpl()"},{name:"db.render",label:'$("#myTmpl").render()'}],expanded:!0},{name:"apps",label:"Building apps",categories:[{name:"jsrmodel",label:"Data / View Model",categories:[{name:"viewmodelsapi",label:"$.views.viewModels()"}],expanded:!1},{name:"compiletmpl",label:"Templates",categories:[{name:"d.templates",label:"$.templates()"}],expanded:!1},{name:"helpers",label:"Helpers",categories:[{name:"helpersapi",label:"$.views.helpers()"}],expanded:!1},{name:"tags",label:"Custom tags",categories:[{name:"tagsapi",label:"$.views.tags()"}],expanded:!1},{name:"converters",label:"Converters",categories:[{name:"convertersapi",label:"$.views.converters()"}],expanded:!1}],expanded:!0},{name:"settings",label:"Settings",categories:[{name:"settings/delimiters",label:"Delimiters"},{name:"settings/debugmode",label:"Debug mode"},{name:"settings/allowcode",label:"Allow code"}],expanded:!1},{name:"advanced",label:"Advanced",categories:[{name:"onerror",label:"Error handling"},{name:"nojqueryapi",label:"JsRender without jQuery"},{name:"jsrobjects",label:"JsRender objects",categories:[{name:"viewsobject",label:"$.views object",expanded:!0},{name:"templateobject",label:"template object"},{name:"viewobject",label:"view object"},{name:"tagobject",label:"tag object"},{name:"ctxobject",label:"View context object (ctx)"},{name:"tagctxobject",label:"Tag context object (tagCtx)"},{name:"globals",label:"Globals"}],expanded:!0}],expanded:!1},{name:"jsrnode",label:"JsRender on Node.js",categories:[{name:"node/install",label:"Installation and usage"},{name:"node/filetmpls",label:"File-based templates"},{name:"node/express-hapi",label:"Express and Hapi integration"},{name:"node/server-browser",label:"Server/browser shared templates"},{name:"node/browserify",label:"Browserify support",expanded:!0},{name:"node/webpack",label:"Webpack support"}],expanded:!0}],expanded:!0},{filter:"jsv",name:"jsvapi",label:"JsViews API - Data-driven UI",heading:"JsViews API documentation",description:"Detailed API docs on using JsViews for dynamic data-driven sites, or MVVM",categories:[{name:"linked-template-syntax",label:"Data-linked template syntax",categories:[{name:"linked-tag-syntax",label:"Data-linked tags"},{name:"linked-elem-syntax",label:"Data-linked elements"},{name:"linked-paths",label:"Data-linked paths"},{name:"link2way",label:"Two-way binding"},{name:"link-events",label:"Event bindings"}],expanded:!0},{name:"jsvtags",label:"Template tags",categories:[{name:"jsvassigntag",label:"{^{: ...}}"},{name:"jsvhtmltag",label:"{^{> ...}}"},{name:"jsvincludetag",label:"{^{include ...}}"},{name:"jsvfortag",label:"{^{for ...}}"},{name:"jsviftag",label:"{^{if ...}}"},{name:"jsvpropstag",label:"{^{props ...}}"},{name:"jsvradiogrouptag",label:"{^{radiogroup ...}}"},{name:"jsvelsetag",label:"{{else ...}}"},{name:"jsvontag",label:"{^{on ...}}"}],expanded:!0},{name:"jsvlinktmpl",label:"Render and link a template",categories:[{name:"jsvtmpllink",label:"myTmpl.link()"},{name:"jsv.d.link",label:"$.link.myTmpl()"}],expanded:!0},{name:"jsvapps",label:"Building apps",categories:[{name:"jsvmodel",label:"Data / View Model",categories:[{name:"jsvviewmodelsapi",label:"$.views.viewModels()"}],expanded:!1},{name:"linkedtmpls",label:"Data-linked templates"},{name:"jsvtagcontrols",label:"Custom tag controls",categories:[{name:"tagoptions",label:"Tag control options"},{name:"tagstructure",label:"Tag control structure",expanded:!0},{name:"taglifecycle",label:"Tag control life-cycle"},{name:"tagpatterns",label:"Tag design patterns",categories:[{name:"renderingpatterns",label:"Layout and rendering"},{name:"bindingpatterns",label:"Data binding",expanded:!0},{name:"hierarchypatterns",label:"Tag hierarchy"},{name:"todo",label:"TODO",hidden:!0}],expanded:!1}],expanded:!0},{name:"jsvhelpers-converters",label:"Helpers and converters"},{name:"mvvm-views",label:"MVVM -- Dynamic view hierarchy"}],expanded:!0},{name:"toplink",label:"Top-level data-linking",categories:[{name:"jsv.toplink-true",label:"Declarative: $.link(true, ...)"},{name:"jsv.toplink-expr",label:"Programmatic: $.link(...)"}],expanded:!0},{name:"$view",label:"Views: from UI to data",categories:[{name:"jsv.d.view",label:"$.view()"}],expanded:!0},{name:"link-targets",label:"Targets for data-linking",categories:[{name:"link-formelems",label:"Form elements",categories:[{name:"link-input",label:"textbox / checkbox / radio"},{name:"link-select",label:"select"},{name:"link-textarea",label:"textarea"},{name:"link-button",label:"button"}],expanded:!0},{name:"link-text-html",label:"innerText / innerHTML"},{name:"link-css",label:"CSS attributes"},{name:"link-class",label:"class"},{name:"link-visibility",label:"visibility"},{name:"link-elemattribs",label:"Element attributes/properties"},{name:"link-tags",label:"Tag bindings"},{name:"link-computed",label:"Computed observables"},{name:"link-svg",label:"SVG elements"},{name:"link-contenteditable",label:"contenteditable elements"}],expanded:!0},{name:"jsvsettings",label:"Settings",categories:[{name:"jsvsettings/delimiters",label:"Delimiters"},{name:"jsvsettings/debugmode",label:"Debug mode"},{name:"jsvsettings/trigger",label:"Trigger"},{name:"jsvsettings/allowcode",label:"Allow code"}],expanded:!1},{name:"jsvadvanced",label:"Advanced",categories:[{name:"jsvsettings/advanced",label:"Advanced settings"},{name:"jsvobjects",label:"JsViews objects",categories:[{name:"jsvviewsobject",label:"$.views object",expanded:!0},{name:"jsvtemplateobject",label:"template object"},{name:"jsvviewobject",label:"view object",expanded:!0},{name:"jsvtagobject",label:"tag object"},{name:"jsvctxobject",label:"View context object (ctx)"},{name:"jsvtagctxobject",label:"Tag context object (tagCtx)"},{name:"jsvlinkctxobject",label:"Link context object (linkCtx)"},{name:"eventArgs",label:"eventArgs object"},{name:"jsvglobals",label:"Globals"}],expanded:!0},{name:"jsvunlink",label:"$.unlink()",categories:[],expanded:!0}],expanded:!1}],expanded:!0},{filter:"jsv",name:"jsoapi",label:"JsObservable API - Observing data",heading:"JsObservable API documentation",description:"Detailed API docs on using JsObservable for observing or triggering data changes in a single-page app",categories:[{name:"$observable",label:"Observable objects and arrays"},{name:"propchange",label:"Modify an object observably",categories:[{name:"setprop",label:"$.observable(object).setProperty()"},{name:"removeprop",label:"$.observable(obj).removeProperty()"}],expanded:!0},{name:"arrchange",label:"Modify an array observably",categories:[{name:"insert",label:"$.observable(array).insert()"},{name:"remove",label:"$.observable(array).remove()"},{name:"move",label:"$.observable(array).move()"},{name:"refresh",label:"$.observable(array).refresh()"}],expanded:!0},{name:"observeobjectsarrays",label:"Respond to data changes",categories:[{name:"onpropchange",label:"onPropertyChange"},{name:"onarrchange",label:"onArrayChange"},{name:"observe",label:"$.observe()"},{name:"unobserve",label:"$.unobserve()"},{name:"observeAll",label:"$.observable().observeAll()"},{name:"unobserveAll",label:"$.observable().unobserveAll()"}],expanded:!0},{name:"computed",label:"Computed observables"},{name:"jsoadvanced",label:"Advanced",categories:[{name:"namespaces",label:"Namespaces"}],expanded:!1}],expanded:!0},{name:"samples",label:"Samples",heading:"Samples for JsRender, JsViews or JsObservable",description:"Examples of some of the ways you can use JsRender templates, JsViews tag controls, and more",categories:[{filter:"jsr",name:"samples/jsr",label:"JsRender samples",categories:[{name:"samples/jsr/converters",label:"Converters and encoding"},{name:"samples/jsr/composition",label:"Template composition",categories:[{name:"samples/jsr/composition/tmpl",label:"tmpl property"},{name:"samples/jsr/composition/from-strings",label:"From strings"},{name:"samples/jsr/composition/remote-tmpl",label:"Remote templates"},{name:"samples/jsr/composition/sub-tmpl",label:"Using sub-templates"},{name:"samples/jsr/composition/tmpl-objects",label:"Contextual template objects"}],expanded:!0},{name:"samples/jsr/tags",label:"Custom tags",categories:[{name:"samples/jsr/tags/wrap-content",label:"Wrapping content"},{name:"samples/jsr/tags/extend-for",label:"Extending for"}],expanded:!0},{name:"samples/jsr/helpers",label:"Helpers"},{name:"samples/jsr/paths",label:"Paths"}],expanded:!0},{filter:"jsv",name:"samples/jso",label:"JsObservable samples",hidden:!0},{filter:"jsv",name:"samples/jsv",label:"JsViews samples",categories:[{name:"samples/data-link",label:"Data-linking tags and elements",categories:[{name:"samples/data-link/from-render-to-link",label:"From rendering to linking"},{name:"samples/data-link/for-and-if",label:"Linking {^{for}} and {^{if}}"},{name:"samples/data-link/class",label:"Linking class"},{name:"samples/data-link/toggle",label:"Toggling class with data-link"},{name:"samples/data-link/attributes",label:"Linking attributes"},{name:"samples/data-link/visibility",label:"Linking visibility"},{name:"samples/data-link/hover",label:"Linking visibility and hover"},{name:"samples/data-link/css",label:"Linking CSS attributes"},{name:"samples/data-link/svg",label:"Linking SVG elements"},{name:"samples/data-link/computed",label:"Computed ....!!",hidden:!0}],expanded:!0},{name:"samples/editable",label:"Editable data",categories:[{name:"samples/editable/tags",label:"Data-linked tags"},{name:"samples/editable/elems",label:"Data-linked elements"},{name:"samples/editable/toplevel-for",label:"Top-level elems with {for...}"},{name:"samples/editable/observe",label:"$.observe()"},{name:"samples/editable/compiled",label:"Compiled View Models"},{name:"samples/editable/submit",label:"Submit changes"},{name:"samples/editable/hash",label:"hash/dictionary"}],expanded:!0},{name:"samples/form-elems",label:"Form elements",categories:[{name:"samples/form-els/simple",label:"Form element binding"},{name:"samples/form-els/array-binding",label:"Array binding"},{name:"samples/form-els/converters",label:"2-way binding and converters"},{name:"samples/form-els/visible-binding",label:"Form elements and visibility"},{name:"samples/form-els/edit",label:"Edit tag control",hidden:!0},{name:"samples/form-els/validation",label:"With validation",hidden:!0},{name:"samples/form-els/submit",label:"Submitting the form",hidden:!0}],expanded:!0},{name:"samples/computed",label:"Computed observables",categories:[{name:"samples/computed/fullname",label:"fullName variants"},{name:"samples/computed/shopping-cart",label:"Shopping cart"},{name:"samples/computed/team-manager",label:"Team manager"}],expanded:!1},{name:"samples/tag-controls",label:"Tag controls",categories:[{name:"samples/tag-controls/jqui",label:"jQueryUI widget controls",categories:[{name:"samples/tag-controls/jqui/api",label:"Accessing widget APIs"},{name:"samples/tag-controls/jqui/datepicker",label:"datepicker control",categories:[{name:"samples/tag-controls/jqui/datepicker/simple",label:"Simple datepicker"},{name:"samples/tag-controls/jqui/datepicker/variants",label:"datepicker variants"},{name:"samples/tag-controls/jqui/datepicker/formats",label:"Date formats"},{name:"samples/tag-controls/jqui/datepicker/with-validation",label:"With validation"},{name:"samples/tag-controls/jqui/datepicker/with-validation-wizard",label:"With validation wizard"}],expanded:!1},{name:"samples/tag-controls/jqui/slider",label:"slider control (jQuery UI)",categories:[{name:"samples/tag-controls/jqui/slider/simple",label:"Simple slider"},{name:"samples/tag-controls/jqui/slider/variants",label:"slider variants"},{name:"samples/tag-controls/jqui/slider/with-validation",label:"With validation"},{name:"samples/tag-controls/jqui/slider/color-picker",label:"Color picker"}],expanded:!1},{name:"samples/tag-controls/jqui/spinner",label:"spinner control",categories:[{name:"samples/tag-controls/jqui/spinner/variants",label:"spinner variants",expanded:!0},{name:"samples/tag-controls/jqui/spinner/formats",label:"Formats and cultures"},{name:"samples/tag-controls/jqui/timespinner",label:"timespinner control"}],expanded:!1},{name:"samples/tag-controls/jqui/toolbar",label:"button radio checkbox..."},{name:"samples/tag-controls/jqui/tabs",label:"tabs control (jQuery UI)"},{name:"samples/tag-controls/jqui/menu",label:"menu control"},{name:"samples/tag-controls/jqui/selectmenu",label:"selectmenu control"},{name:"samples/tag-controls/jqui/progressbar",label:"progressbar control"},{name:"samples/tag-controls/jqui/accordion",label:"accordion control"},{name:"samples/tag-controls/jqui/autocomplete",label:"autocomplete control"},{name:"samples/tag-controls/jqui/selectable",label:"selectable control"},{name:"samples/tag-controls/jqui/sortable",label:"sortable control"},{name:"samples/tag-controls/jqui/resizable",label:"resizable control"},{name:"samples/tag-controls/jqui/draggable-droppable",label:"draggable droppable"}],expanded:!0},{name:"samples/tag-controls/tabs",label:"tabs control"},{name:"samples/tag-controls/multiselect",label:"multiselect control"},{name:"samples/tag-controls/tree",label:"tree control",categories:[{name:"samples/tag-controls/tree/visible-binding",label:"tree with 'visible' binding"},{name:"samples/tag-controls/tree/if-binding",label:"tree with if-binding"},{name:"samples/tag-controls/tree/editable",label:"Editable tree"}],expanded:!1},{name:"samples/tag-controls/validate",label:"validate control",categories:[{name:"samples/tag-controls/validate/simple",label:"Simple validate"},{name:"samples/tag-controls/validate/group",label:"Validation group"},{name:"samples/tag-controls/validate/array-binding",label:"Array binding"}],expanded:!1},{name:"samples/tag-controls/simple-textbox",label:"simple textbox control",expanded:!0},{name:"samples/tag-controls/purchases",label:"purchases control"},{name:"samples/tag-controls/slider",label:"slider control"},{name:"samples/tag-controls/areaslider",label:"areaslider control"},{name:"samples/tag-controls/spinblock",label:"spinblock control"},{name:"samples/tag-controls/colorpicker",label:"colorpicker control"},{name:"samples/tag-controls/jsonview",label:"jsonview control"}],expanded:!0}],expanded:!0}],expanded:!0},{name:"download",label:"Download",heading:"Downloading JsViews, JsRender and JsObservable",description:"",categories:[{name:"download",label:"Latest version"},{name:"download/specific",label:"Specific versions",expanded:!0,hidden:!0},{name:"download/pages",label:"Example pages",categories:[{name:"download/pages-jsr-jq",label:"JsRender with jQuery"},{name:"download/pages-jsr",label:"JsRender without jQuery"},{name:"download/pages-jsv",label:"JsViews"}],expanded:!0},{name:"download/jsrplugins",label:"JsRender plugins",expanded:!0},{name:"download/jsvplugins",label:"JsViews plugins",categories:[{name:"download/sample-tagcontrols",label:"Sample tag controls"},{name:"download/jqueryui-tagcontrols",label:"jQuery UI tag controls"}],expanded:!0},{name:"typescript",label:"TypeScript declaration files"}],expanded:!0},{name:"community",label:"JsViews Community",heading:"JsViews and JsRender Community",description:"Viewing the source code, filing bugs or feature requests...",categories:[{name:"github",label:"GitHub",expanded:!0}],expanded:!0}]; //# sourceMappingURL=contents-categories.min.js.map diff --git a/documentation/contents-categories.min.js.map b/documentation/contents-categories.min.js.map index 69080aa7..b44a4eac 100644 --- a/documentation/contents-categories.min.js.map +++ b/documentation/contents-categories.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["contents-categories.js"],"names":["content","$","views","documentation","categories","useStorage","parseJSON","localStorage","getItem","jsrender","loaded","name","label","heading","description","key","class","home","prefix","next","leftsections","_type","title","text","data","nickname","showNickname","markup","sections","typeLabel","sectionTypes","para","template","code","links","jsrJsvJqui","height","header","action","loading","jsviews","html","nocss","jsobservable","expanded","hidden","filter"],"mappings":"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","file":"contents-categories.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.categories = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocCategories\")) ||\r\n[\r\n {\r\n \"jsrender\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsRender\",\r\n \"heading\": \"Best-of-breed templating\",\r\n \"description\": \"Simple and intuitive, powerful and extensible, lightning fast\",\r\n \"key\": \"jsrender\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jsr\",\r\n \"next\": \"jsrplaying\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Here's a first example of the power and simplicity of JsRender templates:\",\r\n \"text\": \"\"\r\n },\r\n {\r\n \"_type\": \"data\",\r\n \"title\": \"Some data:\",\r\n \"data\": [\r\n {\r\n \"name\": \"Robert\",\r\n \"nickname\": \"Bob\",\r\n \"showNickname\": true\r\n },\r\n {\r\n \"name\": \"Susan\",\r\n \"nickname\": \"Sue\",\r\n \"showNickname\": false\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"A template (with a conditional section using an {{if...}} tag):\",\r\n \"markup\": \"
\\n Name: {{:name}}\\n {{if showNickname && nickname}}\\n (Goes by {{:nickname}})\\n {{/if}}\\n
\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And a working demo, you can play with and modify:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:name}}\\n```\\n\\nRender the `name` property of the current data item\\n\\n```jsr\\n{{if showNickname && nickname}}...{{/if}}\\n```\\n\\nAn `{{if}}` tag: Render the block content only if the expression (`showNickname && nickname`) is true...\"\r\n }\r\n ],\r\n \"data\": [\r\n {\r\n \"name\": \"Robert\",\r\n \"nickname\": \"Bob\",\r\n \"showNickname\": true\r\n },\r\n {\r\n \"name\": \"Susan\",\r\n \"nickname\": \"Sue\",\r\n \"showNickname\": false\r\n }\r\n ],\r\n \"markup\": \"
\\n Name: {{:name}}\\n {{if showNickname && nickname}}\\n (Goes by {{:nickname}})\\n {{/if}}\\n
\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"85\",\r\n \"header\": \"\",\r\n \"action\": \"\"\r\n }\r\n ],\r\n \"title\": \"\"\r\n },\r\n \"loading\": \"\"\r\n },\r\n \"jsviews\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsViews\",\r\n \"heading\": \"The next-generation MVVM framework - bringing templates to life\",\r\n \"description\": \"The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates\",\r\n \"key\": \"jsviews\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jsv\",\r\n \"next\": \"jsvplaying\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"The JsViews framework brings declarative data-binding to JsRender templates, supports MVVM and MVP (custom tag controls), and much more...

Here's a small example. We'll start with some data:\",\r\n \"code\": \"...\\n{\\n \\\"name\\\": \\\"Robert\\\",\\n \\\"nickname\\\": \\\"Bob\\\",\\n \\\"showNickname\\\": true\\n}\\n...\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"and a data-bound template:\",\r\n \"markup\": \"
\\n Name: {^{>name}}\\n {^{if showNickname && nickname}}\\n (Goes by )\\n {{/if}}\\n
\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"And within the template we will use two-way binding to allow editing of the underlying data:\",\r\n \"markup\": \"{^{if editable}}\\n
\\n \\n \\n \\n
\\n{{/if}}\\n\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{^{>name}} ... {^{if showNickname && nickname}}...\\n```\\n\\nThese are data-bound tags. When the underlying data changes the data-value within the rendered template automatically updates too.\\n\\nChanging `{{if ...}}` to `{^{if ...}}` makes it data-bound. Now, when the underlying data value or expression changes the whole rendered block content is automatically removed or reinserted.\\n\\n```jsr\\n\\n```\\n\\nYou can use element-based data-linking too. Here, the inner-text of the `` element is data-bound to the `nickname` data value.\\n\\n```jsr\\n\\n```\\n\\nAnd here, the input is automatically two-way data-bound to the `name` property of the underlying data. Change the value in the text box, and the underlying data automatically updates. Any other parts of the template that are data-linked to the same data property will then immediately update too.\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"height\": \"115\",\r\n \"html\": \"
\\n\\n\",\r\n \"code\": \"var data = [\\n {\\n \\\"name\\\": \\\"Robert\\\",\\n \\\"nickname\\\": \\\"Bob\\\",\\n \\\"showNickname\\\": true\\n },\\n {\\n \\\"name\\\": \\\"Susan\\\",\\n \\\"nickname\\\": \\\"Sue\\\",\\n \\\"showNickname\\\": false\\n }\\n];\\n\\nvar template = $.templates(\\\"#theTmpl\\\");\\n\\ntemplate.link(\\\"#result\\\", data);\",\r\n \"nocss\": false,\r\n \"action\": \"append\",\r\n \"header\": \"\"\r\n }\r\n ]\r\n },\r\n \"loading\": \"\"\r\n },\r\n \"jsobservable\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsObservable\",\r\n \"heading\": \"Live observable data in the browser\",\r\n \"description\": \"Code and declarative data-binding working hand-in-hand, adding interactivity and responsiveness to your single-page apps\",\r\n \"key\": \"jsobservable\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jso\",\r\n \"next\": \"getstarted\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The JsObservable library is part of JsViews.\",\r\n \"text\": \"It is used by JsViews to provide the declarative data-binding. And it also allows your code in a JsViews app to trigger data changes, or to 'observe' data-changes programmatically.\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"We'll add some code to a \\\"declarative\\\" JsViews sample. Take some data, and a data-bound template:\",\r\n \"code\": \"var people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{^{for people}}\\n ...\\n \\n ...\\n{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"And add some button click handlers which call JsObservable APIs to make observable changes to the underlying data:\",\r\n \"code\": \"$(\\\"#result\\\")\\n .on(\\\"click\\\", \\\".change\\\", function() {\\n var dataItem = $.view(this).data;\\n $.observable(dataItem).setProperty(\\\"name\\\", ...);\\n })\\n .on(\\\"click\\\", \\\".remove\\\", function() {\\n var index = $.view(this).index;\\n $.observable(people).remove(index);\\n });\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.observable(people).insert({name: ...});\\n\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.observable(object).setProperty(...);\\n```\\n\\n`$.observable(dataItem)` makes `dataItem` *\\\"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.\\n\\n`$.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 people}}` tag. Here the rendered block content of the tag will be incrementally added/removed for each added/removed array item - in response to your change.\\n\\n```js\\n$.observable(array).insert(...);\\n```\\n\\n`$.view(elem)` allows you to get from any DOM element to the *view* object for that part of the rendered content, and hence to the underlying data, index, etc.\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"height\": \"175\",\r\n \"html\": \"
\\n\\n\",\r\n \"code\": \"var template = $.templates(\\\"#theTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n ];\\n\\nvar counter = 1;\\n\\ntemplate.link(\\\"#result\\\", {people: people});\\n\\n$(\\\"#addBtn\\\").on(\\\"click\\\", function() {\\n $.observable(people).insert({name: \\\"name\\\" + counter++});\\n})\\n\\n$(\\\"#result\\\")\\n .on(\\\"click\\\", \\\".change\\\", function() {\\n var dataItem = $.view(this).data;\\n $.observable(dataItem).setProperty(\\\"name\\\", dataItem.name + \\\"*\\\");\\n })\\n .on(\\\"click\\\", \\\".remove\\\", function() {\\n var index = $.view(this).index;\\n $.observable(people).remove(index);\\n });\"\r\n }\r\n ]\r\n },\r\n \"loading\": \"\"\r\n }\r\n },\r\n {\r\n \"name\": \"getstarted\",\r\n \"label\": \"Getting started\",\r\n \"heading\": \"Getting Started\",\r\n \"description\": \"First steps with JsRender, JsViews and JsObservable\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsrplaying\",\r\n \"label\": \"Playing with JsRender\"\r\n },\r\n {\r\n \"name\": \"jsr-quickstart\",\r\n \"label\": \"JsRender Quickstart\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsr-node-quickstart\",\r\n \"label\": \"JsRender Node.js Quickstart\"\r\n },\r\n {\r\n \"name\": \"jsvplaying\",\r\n \"label\": \"Playing with JsViews\"\r\n },\r\n {\r\n \"name\": \"jsv-quickstart\",\r\n \"label\": \"JsViews Quickstart\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"temp\",\r\n \"label\": \"JsViews QS end\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsr\",\r\n \"name\": \"jsrapi\",\r\n \"label\": \"JsRender API - Templated UI\",\r\n \"heading\": \"JsRender API documentation\",\r\n \"description\": \"Detailed API docs on using JsRender templates\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tmplsyntax\",\r\n \"label\": \"Template syntax and structure\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"name\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"name\": \"views\",\r\n \"label\": \"View hierarchy\",\r\n \"categories\": [\r\n {\r\n \"name\": \"getindex\",\r\n \"label\": \"getIndex()\"\r\n },\r\n {\r\n \"name\": \"contextualparams\",\r\n \"label\": \"Contextual parameters\"\r\n },\r\n {\r\n \"name\": \"parentdata\",\r\n \"label\": \"Accessing parent data\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsrtags\",\r\n \"label\": \"Template tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"assigntag\",\r\n \"label\": \"{{: ...}}\"\r\n },\r\n {\r\n \"name\": \"htmltag\",\r\n \"label\": \"{{> ...}}\"\r\n },\r\n {\r\n \"name\": \"includetag\",\r\n \"label\": \"{{include ...}}\"\r\n },\r\n {\r\n \"name\": \"fortag\",\r\n \"label\": \"{{for ...}}\"\r\n },\r\n {\r\n \"name\": \"propstag\",\r\n \"label\": \"{{props ...}}\"\r\n },\r\n {\r\n \"name\": \"iftag\",\r\n \"label\": \"{{if ...}}\"\r\n },\r\n {\r\n \"name\": \"elsetag\",\r\n \"label\": \"{{else ...}}\"\r\n },\r\n {\r\n \"name\": \"allowcodetag\",\r\n \"label\": \"{{* ... }} and {{*: ...}}\"\r\n },\r\n {\r\n \"name\": \"customtagsapi\",\r\n \"label\": \"Custom tags\"\r\n },\r\n {\r\n \"name\": \"commenttag\",\r\n \"label\": \"{{!-- ... --}}\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"rendertmpl\",\r\n \"label\": \"Render a template\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tmplrender\",\r\n \"label\": \"myTmpl.render()\"\r\n },\r\n {\r\n \"name\": \"d.render\",\r\n \"label\": \"$.render.myTmpl()\"\r\n },\r\n {\r\n \"name\": \"db.render\",\r\n \"label\": \"$(\\\"#myTmpl\\\").render()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"apps\",\r\n \"label\": \"Building apps\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsrmodel\",\r\n \"label\": \"Data / View Model\",\r\n \"categories\": [\r\n {\r\n \"name\": \"viewmodelsapi\",\r\n \"label\": \"$.views.viewModels()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"compiletmpl\",\r\n \"label\": \"Templates\",\r\n \"categories\": [\r\n {\r\n \"name\": \"d.templates\",\r\n \"label\": \"$.templates()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"helpers\",\r\n \"label\": \"Helpers\",\r\n \"categories\": [\r\n {\r\n \"name\": \"helpersapi\",\r\n \"label\": \"$.views.helpers()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"tags\",\r\n \"label\": \"Custom tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagsapi\",\r\n \"label\": \"$.views.tags()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"tagsOld\",\r\n \"label\": \"OldCustom tags\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"converters\",\r\n \"label\": \"Converters\",\r\n \"categories\": [\r\n {\r\n \"name\": \"convertersapi\",\r\n \"label\": \"$.views.converters()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"settings\",\r\n \"label\": \"Settings\",\r\n \"hidden\": false,\r\n \"categories\": [\r\n {\r\n \"name\": \"settings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"name\": \"settings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"name\": \"settings/allowcode\",\r\n \"label\": \"Allow code\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"advanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"onerror\",\r\n \"label\": \"Error handling\"\r\n },\r\n {\r\n \"name\": \"settings/advanced\",\r\n \"label\": \"Advanced settings\"\r\n },\r\n {\r\n \"name\": \"nojqueryapi\",\r\n \"label\": \"JsRender without jQuery\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"jsrobjects\",\r\n \"label\": \"JsRender objects\",\r\n \"categories\": [\r\n {\r\n \"name\": \"viewsobject\",\r\n \"label\": \"$.views object\",\r\n \"expanded\": true,\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"templateobject\",\r\n \"label\": \"template object\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"viewobject\",\r\n \"label\": \"view object\"\r\n },\r\n {\r\n \"name\": \"tagobject\",\r\n \"label\": \"tag object\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"viewcontextobject\",\r\n \"label\": \"View context object (ctx)\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"tagcontextobject\",\r\n \"label\": \"Tag context object (tagCtx)\",\r\n \"hidden\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"lifecycle\",\r\n \"label\": \"Life-cycle events\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"jsrnode\",\r\n \"label\": \"JsRender on Node.js\",\r\n \"categories\": [\r\n {\r\n \"name\": \"node/install\",\r\n \"label\": \"Installation and usage\"\r\n },\r\n {\r\n \"name\": \"node/filetmpls\",\r\n \"label\": \"File-based templates\"\r\n },\r\n {\r\n \"name\": \"node/express-hapi\",\r\n \"label\": \"Express and Hapi integration\"\r\n },\r\n {\r\n \"name\": \"node/server-browser\",\r\n \"label\": \"Server/browser shared templates\"\r\n },\r\n {\r\n \"name\": \"node/browserify\",\r\n \"label\": \"Browserify support\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"node/webpack\",\r\n \"label\": \"Webpack support\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"jsvapi\",\r\n \"label\": \"JsViews API - Data-driven UI\",\r\n \"heading\": \"JsViews API documentation\",\r\n \"description\": \"Detailed API docs on using JsViews for dynamic data-driven sites, or MVVM\",\r\n \"categories\": [\r\n {\r\n \"name\": \"linked-template-syntax\",\r\n \"label\": \"Data-linked template syntax\",\r\n \"categories\": [\r\n {\r\n \"name\": \"linked-tag-syntax\",\r\n \"label\": \"Data-linked tags\"\r\n },\r\n {\r\n \"name\": \"linked-elem-syntax\",\r\n \"label\": \"Data-linked elements\"\r\n },\r\n {\r\n \"name\": \"linked-paths\",\r\n \"label\": \"Data-linked paths\"\r\n },\r\n {\r\n \"name\": \"link2way\",\r\n \"label\": \"Two-way binding\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-events\",\r\n \"label\": \"Event bindings\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvviews\",\r\n \"label\": \"View hierarchy\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvgetindex\",\r\n \"label\": \"getIndex()\"\r\n },\r\n {\r\n \"name\": \"jsvcontextualparams\",\r\n \"label\": \"Contextual parameters\"\r\n },\r\n {\r\n \"name\": \"jsvparentdata\",\r\n \"label\": \"Accessing parent data\"\r\n }\r\n ],\r\n \"expanded\": true,\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvtags\",\r\n \"label\": \"Template tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvassigntag\",\r\n \"label\": \"{^{: ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvhtmltag\",\r\n \"label\": \"{^{> ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvincludetag\",\r\n \"label\": \"{^{include ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvfortag\",\r\n \"label\": \"{^{for ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsviftag\",\r\n \"label\": \"{^{if ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvpropstag\",\r\n \"label\": \"{^{props ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvradiogrouptag\",\r\n \"label\": \"{^{radiogroup ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvelsetag\",\r\n \"label\": \"{{else ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvontag\",\r\n \"label\": \"{^{on ...}}\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvcustomtags\",\r\n \"label\": \"Custom tags\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvlinktmpl\",\r\n \"label\": \"Render and link a template\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvtmpllink\",\r\n \"label\": \"myTmpl.link()\"\r\n },\r\n {\r\n \"name\": \"jsv.d.link\",\r\n \"label\": \"$.link.myTmpl()\"\r\n }\r\n ],\r\n \"expanded\": true,\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvapps\",\r\n \"label\": \"Building apps\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvmodel\",\r\n \"label\": \"Data / View Model\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvviewmodelsapi\",\r\n \"label\": \"$.views.viewModels()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"linkedtmpls\",\r\n \"label\": \"Data-linked templates\"\r\n },\r\n {\r\n \"name\": \"jsvtagcontrols\",\r\n \"label\": \"Custom tag controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagoptions\",\r\n \"label\": \"Tag control options\"\r\n },\r\n {\r\n \"name\": \"tagstructure\",\r\n \"label\": \"Tag control structure\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"taglifecycle\",\r\n \"label\": \"Tag control life-cycle\"\r\n },\r\n {\r\n \"name\": \"tagpatterns\",\r\n \"label\": \"Tag design patterns\",\r\n \"categories\": [\r\n {\r\n \"name\": \"renderingpatterns\",\r\n \"label\": \"Layout and rendering\"\r\n },\r\n {\r\n \"name\": \"bindingpatterns\",\r\n \"label\": \"Data binding\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"hierarchypatterns\",\r\n \"label\": \"Tag hierarchy\"\r\n },\r\n {\r\n \"name\": \"todo\",\r\n \"label\": \"TODO\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvhelpers-converters\",\r\n \"label\": \"Helpers and converters\"\r\n },\r\n {\r\n \"name\": \"mvvm-views\",\r\n \"label\": \"MVVM -- Dynamic view hierarchy\",\r\n \"hidden\": false\r\n }\r\n ],\r\n \"expanded\": true,\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"toplink\",\r\n \"label\": \"Top-level data-linking\",\r\n \"hidden\": false,\r\n \"categories\": [\r\n {\r\n \"name\": \"jsv.toplink-true\",\r\n \"label\": \"Declarative: $.link(true, ...)\"\r\n },\r\n {\r\n \"name\": \"jsv.toplink-expr\",\r\n \"label\": \"Programmatic: $.link(...)\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"$view\",\r\n \"label\": \"Views: from UI to data\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsv.d.view\",\r\n \"label\": \"$.view()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"link-targets\",\r\n \"label\": \"Targets for data-linking\",\r\n \"categories\": [\r\n {\r\n \"name\": \"link-formelems\",\r\n \"label\": \"Form elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"link-input\",\r\n \"label\": \"textbox / checkbox / radio\"\r\n },\r\n {\r\n \"name\": \"link-select\",\r\n \"label\": \"select\"\r\n },\r\n {\r\n \"name\": \"link-textarea\",\r\n \"label\": \"textarea\"\r\n },\r\n {\r\n \"name\": \"link-button\",\r\n \"label\": \"button\",\r\n \"hidden\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"link-text-html\",\r\n \"label\": \"innerText / innerHTML\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-css\",\r\n \"label\": \"CSS attributes\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-class\",\r\n \"label\": \"class\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-visibility\",\r\n \"label\": \"visibility\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-elemattribs\",\r\n \"label\": \"Element attributes/properties\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-tags\",\r\n \"label\": \"Tag bindings\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-computed\",\r\n \"label\": \"Computed observables\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-svg\",\r\n \"label\": \"SVG elements\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"link-contenteditable\",\r\n \"label\": \"contenteditable elements\"\r\n }\r\n ],\r\n \"expanded\": true,\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvunlink\",\r\n \"label\": \"unlink()\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsv.d.unlink\",\r\n \"label\": \"$.unlink()\"\r\n },\r\n {\r\n \"name\": \"jsv.db.unlink\",\r\n \"label\": \"$(...).unlink()\"\r\n }\r\n ],\r\n \"expanded\": true,\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"jsvsettings\",\r\n \"label\": \"Settings\",\r\n \"hidden\": false,\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvsettings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"name\": \"jsvsettings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"name\": \"jsvsettings/trigger\",\r\n \"label\": \"Trigger\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvsettings/allowcode\",\r\n \"label\": \"Allow code\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"jsvadvanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvsettings/advanced\",\r\n \"label\": \"Advanced settings\"\r\n },\r\n {\r\n \"name\": \"jsvobjects\",\r\n \"label\": \"JsViews objects\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvviewsobject\",\r\n \"label\": \"$.views object\",\r\n \"expanded\": true,\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvtemplateobject\",\r\n \"label\": \"template object\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvviewobject\",\r\n \"label\": \"view object\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvtagobject\",\r\n \"label\": \"tag object\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"jsvviewcontextobject\",\r\n \"label\": \"View context object (ctx)\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"jsvtagcontextobject\",\r\n \"label\": \"Tag context object (tagCtx)\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"jsvlinkcontextobject\",\r\n \"label\": \"Link context object (linkCtx)\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"eventArgs\",\r\n \"label\": \"eventArgs object\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"other\",\r\n \"label\": \"And computed observable, {{on}}, DataMap. lateRender...\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"jsvlifecycle\",\r\n \"label\": \"Life-cycle events\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"replace-target\",\r\n \"label\": \"Replace placeholder target\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"jsoapi\",\r\n \"label\": \"JsObservable API - Observing data\",\r\n \"heading\": \"JsObservable API documentation\",\r\n \"description\": \"Detailed API docs on using JsObservable for observing or triggering data changes in a single-page app\",\r\n \"categories\": [\r\n {\r\n \"name\": \"$observable\",\r\n \"label\": \"Observable objects and arrays\"\r\n },\r\n {\r\n \"name\": \"propchange\",\r\n \"label\": \"Modify an object observably\",\r\n \"categories\": [\r\n {\r\n \"name\": \"setprop\",\r\n \"label\": \"$.observable(object).setProperty()\"\r\n },\r\n {\r\n \"name\": \"removeprop\",\r\n \"label\": \"$.observable(obj).removeProperty()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"arrchange\",\r\n \"label\": \"Modify an array observably\",\r\n \"categories\": [\r\n {\r\n \"name\": \"insert\",\r\n \"label\": \"$.observable(array).insert()\"\r\n },\r\n {\r\n \"name\": \"remove\",\r\n \"label\": \"$.observable(array).remove()\"\r\n },\r\n {\r\n \"name\": \"move\",\r\n \"label\": \"$.observable(array).move()\"\r\n },\r\n {\r\n \"name\": \"refresh\",\r\n \"label\": \"$.observable(array).refresh()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"observeobjectsarrays\",\r\n \"label\": \"Respond to data changes\",\r\n \"categories\": [\r\n {\r\n \"name\": \"onpropchange\",\r\n \"label\": \"onPropertyChange\"\r\n },\r\n {\r\n \"name\": \"onarrchange\",\r\n \"label\": \"onArrayChange\"\r\n },\r\n {\r\n \"name\": \"observe\",\r\n \"label\": \"$.observe()\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"unobserve\",\r\n \"label\": \"$.unobserve()\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"observeAll\",\r\n \"label\": \"$.observable().observeAll()\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"unobserveAll\",\r\n \"label\": \"$.observable().unobserveAll()\",\r\n \"hidden\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"computed\",\r\n \"label\": \"Computed observables\"\r\n },\r\n {\r\n \"name\": \"jsoadvanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"namespaces\",\r\n \"label\": \"Namespaces\"\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples\",\r\n \"label\": \"Samples\",\r\n \"heading\": \"Samples for JsRender, JsViews or JsObservable\",\r\n \"description\": \"Examples of some of the ways you can use JsRender templates, JsViews tag controls, and more\",\r\n \"categories\": [\r\n {\r\n \"filter\": \"jsr\",\r\n \"name\": \"samples/jsr\",\r\n \"label\": \"JsRender samples\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/converters\",\r\n \"label\": \"Converters and encoding\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition\",\r\n \"label\": \"Template composition\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/composition/tmpl\",\r\n \"label\": \"tmpl parameter\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/from-strings\",\r\n \"label\": \"From strings\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/remote-tmpl\",\r\n \"label\": \"Remote templates\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Using sub-templates\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/tmpl-objects\",\r\n \"label\": \"Contextual template objects\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/jsr/tags\",\r\n \"label\": \"Custom tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/tags/wrap-content\",\r\n \"label\": \"Wrapping content\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/tags/extend-for\",\r\n \"label\": \"Extending for\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/jsr/helpers\",\r\n \"label\": \"Helpers\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/paths\",\r\n \"label\": \"Paths\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"hidden\": true,\r\n \"filter\": \"jsv\",\r\n \"name\": \"samples/jso\",\r\n \"label\": \"JsObservable samples\"\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"samples/jsv\",\r\n \"label\": \"JsViews samples\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/data-link\",\r\n \"label\": \"Data-linking tags and elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/data-link/from-render-to-link\",\r\n \"label\": \"From rendering to linking\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/for-and-if\",\r\n \"label\": \"Linking {^{for}} and {^{if}}\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/class\",\r\n \"label\": \"Linking class\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/toggle\",\r\n \"label\": \"Toggling class with data-link\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/attributes\",\r\n \"label\": \"Linking attributes\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/visibility\",\r\n \"label\": \"Linking visibility\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/hover\",\r\n \"label\": \"Linking visibility and hover\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/css\",\r\n \"label\": \"Linking CSS attributes\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/svg\",\r\n \"label\": \"Linking SVG elements\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/computed\",\r\n \"label\": \"Computed ....!!\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/editable\",\r\n \"label\": \"Editable data\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/editable/tags\",\r\n \"label\": \"Data-linked tags\"\r\n },\r\n {\r\n \"name\": \"samples/editable/elems\",\r\n \"label\": \"Data-linked elements\"\r\n },\r\n {\r\n \"name\": \"samples/editable/toplevel-for\",\r\n \"label\": \"Top-level elems with {for...}\"\r\n },\r\n {\r\n \"name\": \"samples/editable/observe\",\r\n \"label\": \"$.observe()\"\r\n },\r\n {\r\n \"name\": \"samples/editable/compiled\",\r\n \"label\": \"Compiled View Models\"\r\n },\r\n {\r\n \"name\": \"samples/editable/submit\",\r\n \"label\": \"Submit changes\"\r\n },\r\n {\r\n \"name\": \"samples/editable/hash\",\r\n \"label\": \"hash/dictionary\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/form-elems\",\r\n \"label\": \"Form elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/form-els/simple\",\r\n \"label\": \"Form element binding\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/array-binding\",\r\n \"label\": \"Array binding\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/converters\",\r\n \"label\": \"2-way binding and converters\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/visible-binding\",\r\n \"label\": \"Form elements and visibility\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/edit\",\r\n \"label\": \"Edit tag control\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"samples/form-els/validation\",\r\n \"label\": \"With validation\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"samples/form-els/submit\",\r\n \"label\": \"Submitting the form\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/computed\",\r\n \"label\": \"Computed observables\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/computed/fullname\",\r\n \"label\": \"fullName variants\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/computed/shopping-cart\",\r\n \"label\": \"Shopping cart\"\r\n },\r\n {\r\n \"name\": \"samples/computed/team-manager\",\r\n \"label\": \"Team manager\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls\",\r\n \"label\": \"Tag controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui\",\r\n \"label\": \"jQueryUI widget controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/api\",\r\n \"label\": \"Accessing widget APIs\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker\",\r\n \"label\": \"datepicker control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/simple\",\r\n \"label\": \"Simple datepicker\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/variants\",\r\n \"label\": \"datepicker variants\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/formats\",\r\n \"label\": \"Date formats\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/with-validation\",\r\n \"label\": \"With validation\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/with-validation-wizard\",\r\n \"label\": \"With validation wizard\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider\",\r\n \"label\": \"slider control (jQuery UI)\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/simple\",\r\n \"label\": \"Simple slider\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/variants\",\r\n \"label\": \"slider variants\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/with-validation\",\r\n \"label\": \"With validation\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/color-picker\",\r\n \"label\": \"Color picker\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner\",\r\n \"label\": \"spinner control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner/variants\",\r\n \"label\": \"spinner variants\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner/formats\",\r\n \"label\": \"Formats and cultures\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/timespinner\",\r\n \"label\": \"timespinner control\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/toolbar\",\r\n \"label\": \"button radio checkbox...\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/tabs\",\r\n \"label\": \"tabs control (jQuery UI)\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/menu\",\r\n \"label\": \"menu control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/selectmenu\",\r\n \"label\": \"selectmenu control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/progressbar\",\r\n \"label\": \"progressbar control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/accordion\",\r\n \"label\": \"accordion control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/autocomplete\",\r\n \"label\": \"autocomplete control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/selectable\",\r\n \"label\": \"selectable control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/sortable\",\r\n \"label\": \"sortable control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/resizable\",\r\n \"label\": \"resizable control\",\r\n \"hidden\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/draggable-droppable\",\r\n \"label\": \"draggable droppable\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tabs\",\r\n \"label\": \"tabs control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/multiselect\",\r\n \"label\": \"multiselect control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree\",\r\n \"label\": \"tree control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/tree/visible-binding\",\r\n \"label\": \"tree with 'visible' binding\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree/if-binding\",\r\n \"label\": \"tree with if-binding\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree/editable\",\r\n \"label\": \"Editable tree\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate\",\r\n \"label\": \"validate control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/validate/simple\",\r\n \"label\": \"Simple validate\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate/group\",\r\n \"label\": \"Validation group\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate/array-binding\",\r\n \"label\": \"Array binding\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/simple-textbox\",\r\n \"label\": \"simple textbox control\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/purchases\",\r\n \"label\": \"purchases control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/slider\",\r\n \"label\": \"slider control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/areaslider\",\r\n \"label\": \"areaslider control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/spinblock\",\r\n \"label\": \"spinblock control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/colorpicker\",\r\n \"label\": \"colorpicker control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jsonview\",\r\n \"label\": \"jsonview control\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download\",\r\n \"label\": \"Download\",\r\n \"heading\": \"Downloading JsViews, JsRender and JsObservable\",\r\n \"description\": \"\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download\",\r\n \"label\": \"Latest version\"\r\n },\r\n {\r\n \"name\": \"download/specific\",\r\n \"label\": \"Specific versions\",\r\n \"expanded\": true,\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"download/pages\",\r\n \"label\": \"Example pages\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download/pages-jsr-jq\",\r\n \"label\": \"JsRender with jQuery\"\r\n },\r\n {\r\n \"name\": \"download/pages-jsr\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"name\": \"download/pages-jsv\",\r\n \"label\": \"JsViews\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download/jsrplugins\",\r\n \"label\": \"JsRender plugins\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download/jsvplugins\",\r\n \"label\": \"JsViews plugins\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download/sample-tagcontrols\",\r\n \"label\": \"Sample tag controls\"\r\n },\r\n {\r\n \"name\": \"download/jqueryui-tagcontrols\",\r\n \"label\": \"jQuery UI tag controls\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"community\",\r\n \"label\": \"JsViews Community\",\r\n \"heading\": \"JsViews and JsRender Community\",\r\n \"description\": \"Viewing the source code, filing bugs or feature requests...\",\r\n \"categories\": [\r\n {\r\n \"name\": \"github\",\r\n \"label\": \"GitHub\",\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n];"]} \ No newline at end of file +{"version":3,"sources":["contents-categories.js"],"names":["content","$","views","documentation","categories","useStorage","parseJSON","localStorage","getItem","jsrender","loaded","name","label","heading","description","key","class","home","prefix","next","leftsections","_type","title","text","data","nickname","showNickname","markup","sections","typeLabel","sectionTypes","para","template","code","links","jsrJsvJqui","height","header","action","loading","jsviews","html","nocss","jsobservable","expanded","hidden","filter"],"mappings":"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","file":"contents-categories.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.categories = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocCategories\")) ||\r\n[\r\n {\r\n \"jsrender\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsRender\",\r\n \"heading\": \"Best-of-breed templating\",\r\n \"description\": \"Simple and intuitive, powerful and extensible, lightning fast\",\r\n \"key\": \"jsrender\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jsr\",\r\n \"next\": \"jsrplaying\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Here's a first example of the power and simplicity of JsRender templates:\",\r\n \"text\": \"\"\r\n },\r\n {\r\n \"_type\": \"data\",\r\n \"title\": \"Some data:\",\r\n \"data\": [\r\n {\r\n \"name\": \"Robert\",\r\n \"nickname\": \"Bob\",\r\n \"showNickname\": true\r\n },\r\n {\r\n \"name\": \"Susan\",\r\n \"nickname\": \"Sue\",\r\n \"showNickname\": false\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"A template (with a conditional section using an {{if...}} tag):\",\r\n \"markup\": \"
\\n Name: {{:name}}\\n {{if showNickname && nickname}}\\n (Goes by {{:nickname}})\\n {{/if}}\\n
\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And a working demo, you can play with and modify:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:name}}\\n```\\n\\nRender the `name` property of the current data item\\n\\n```jsr\\n{{if showNickname && nickname}}...{{/if}}\\n```\\n\\nAn `{{if}}` tag: Render the block content only if the expression (`showNickname && nickname`) is true...\"\r\n }\r\n ],\r\n \"data\": [\r\n {\r\n \"name\": \"Robert\",\r\n \"nickname\": \"Bob\",\r\n \"showNickname\": true\r\n },\r\n {\r\n \"name\": \"Susan\",\r\n \"nickname\": \"Sue\",\r\n \"showNickname\": false\r\n }\r\n ],\r\n \"markup\": \"
\\n Name: {{:name}}\\n {{if showNickname && nickname}}\\n (Goes by {{:nickname}})\\n {{/if}}\\n
\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"85\",\r\n \"header\": \"\",\r\n \"action\": \"\"\r\n }\r\n ],\r\n \"title\": \"\"\r\n },\r\n \"loading\": \"\"\r\n },\r\n \"jsviews\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsViews\",\r\n \"heading\": \"The next-generation MVVM framework - bringing templates to life\",\r\n \"description\": \"The power of MVVM, the flexibility of JavaScript, the speed and ease of JsRender templates\",\r\n \"key\": \"jsviews\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jsv\",\r\n \"next\": \"jsvplaying\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"The JsViews framework brings declarative data-binding to JsRender templates, supports MVVM and MVP (custom tag controls), and much more...

Here's a small example. We'll start with some data:\",\r\n \"code\": \"...\\n{\\n \\\"name\\\": \\\"Robert\\\",\\n \\\"nickname\\\": \\\"Bob\\\",\\n \\\"showNickname\\\": true\\n}\\n...\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"and a data-bound template:\",\r\n \"markup\": \"
\\n Name: {^{>name}}\\n {^{if showNickname && nickname}}\\n (Goes by )\\n {{/if}}\\n
\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"And within the template we will use two-way binding to allow editing of the underlying data:\",\r\n \"markup\": \"{^{if editable}}\\n
\\n \\n \\n \\n
\\n{{/if}}\\n\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{^{>name}} ... {^{if showNickname && nickname}}...\\n```\\n\\nThese are data-bound tags. When the underlying data changes the data-value within the rendered template automatically updates too.\\n\\nChanging `{{if ...}}` to `{^{if ...}}` makes it data-bound. Now, when the underlying data value or expression changes the whole rendered block content is automatically removed or reinserted.\\n\\n```jsr\\n\\n```\\n\\nYou can use element-based data-linking too. Here, the inner-text of the `` element is data-bound to the `nickname` data value.\\n\\n```jsr\\n\\n```\\n\\nAnd here, the input is automatically two-way data-bound to the `name` property of the underlying data. Change the value in the text box, and the underlying data automatically updates. Any other parts of the template that are data-linked to the same data property will then immediately update too.\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"height\": \"115\",\r\n \"html\": \"
\\n\\n\",\r\n \"code\": \"var data = [\\n {\\n \\\"name\\\": \\\"Robert\\\",\\n \\\"nickname\\\": \\\"Bob\\\",\\n \\\"showNickname\\\": true\\n },\\n {\\n \\\"name\\\": \\\"Susan\\\",\\n \\\"nickname\\\": \\\"Sue\\\",\\n \\\"showNickname\\\": false\\n }\\n];\\n\\nvar template = $.templates(\\\"#theTmpl\\\");\\n\\ntemplate.link(\\\"#result\\\", data);\",\r\n \"nocss\": false,\r\n \"action\": \"append\",\r\n \"header\": \"\"\r\n }\r\n ]\r\n },\r\n \"loading\": \"\"\r\n },\r\n \"jsobservable\": {\r\n \"loaded\": true,\r\n \"name\": \"home\",\r\n \"label\": \"JsObservable\",\r\n \"heading\": \"Live observable data in the browser\",\r\n \"description\": \"Code and declarative data-binding working hand-in-hand, adding interactivity and responsiveness to your single-page apps\",\r\n \"key\": \"jsobservable\",\r\n \"class\": \"home\",\r\n \"home\": {\r\n \"prefix\": \"jso\",\r\n \"next\": \"getstarted\",\r\n \"leftsections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The JsObservable library is part of JsViews.\",\r\n \"text\": \"It is used by JsViews to provide the declarative data-binding. And it also allows your code in a JsViews app to trigger data changes, or to 'observe' data-changes programmatically.\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"We'll add some code to a \\\"declarative\\\" JsViews sample. Take some data, and a data-bound template:\",\r\n \"code\": \"var people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{^{for people}}\\n ...\\n \\n ...\\n{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"And add some button click handlers which call JsObservable APIs to make observable changes to the underlying data:\",\r\n \"code\": \"$(\\\"#result\\\")\\n .on(\\\"click\\\", \\\".change\\\", function() {\\n var dataItem = $.view(this).data;\\n $.observable(dataItem).setProperty(\\\"name\\\", ...);\\n })\\n .on(\\\"click\\\", \\\".remove\\\", function() {\\n var index = $.view(this).index;\\n $.observable(people).remove(index);\\n });\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.observable(people).insert({name: ...});\\n\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.observable(object).setProperty(...);\\n```\\n\\n`$.observable(dataItem)` makes `dataItem` *\\\"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.\\n\\n`$.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 people}}` tag. Here the rendered block content of the tag will be incrementally added/removed for each added/removed array item - in response to your change.\\n\\n```js\\n$.observable(array).insert(...);\\n```\\n\\n`$.view(elem)` allows you to get from any DOM element to the *view* object for that part of the rendered content, and hence to the underlying data, index, etc.\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"height\": \"175\",\r\n \"html\": \"
\\n\\n\",\r\n \"code\": \"var template = $.templates(\\\"#theTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n ];\\n\\nvar counter = 1;\\n\\ntemplate.link(\\\"#result\\\", {people: people});\\n\\n$(\\\"#addBtn\\\").on(\\\"click\\\", function() {\\n $.observable(people).insert({name: \\\"name\\\" + counter++});\\n})\\n\\n$(\\\"#result\\\")\\n .on(\\\"click\\\", \\\".change\\\", function() {\\n var dataItem = $.view(this).data;\\n $.observable(dataItem).setProperty(\\\"name\\\", dataItem.name + \\\"*\\\");\\n })\\n .on(\\\"click\\\", \\\".remove\\\", function() {\\n var index = $.view(this).index;\\n $.observable(people).remove(index);\\n });\"\r\n }\r\n ]\r\n },\r\n \"loading\": \"\"\r\n }\r\n },\r\n {\r\n \"name\": \"getstarted\",\r\n \"label\": \"Getting started\",\r\n \"heading\": \"Getting Started\",\r\n \"description\": \"First steps with JsRender, JsViews and JsObservable\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsrplaying\",\r\n \"label\": \"Playing with JsRender\"\r\n },\r\n {\r\n \"name\": \"jsr-quickstart\",\r\n \"label\": \"JsRender Quickstart\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsr-node-quickstart\",\r\n \"label\": \"JsRender Node.js Quickstart\"\r\n },\r\n {\r\n \"name\": \"jsvplaying\",\r\n \"label\": \"Playing with JsViews\"\r\n },\r\n {\r\n \"name\": \"jsv-quickstart\",\r\n \"label\": \"JsViews Quickstart\"\r\n },\r\n {\r\n \"name\": \"temp\",\r\n \"label\": \"JsViews QS end\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsr\",\r\n \"name\": \"jsrapi\",\r\n \"label\": \"JsRender API - Templated UI\",\r\n \"heading\": \"JsRender API documentation\",\r\n \"description\": \"Detailed API docs on using JsRender templates\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tmplsyntax\",\r\n \"label\": \"Template syntax and structure\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"name\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"name\": \"views\",\r\n \"label\": \"View hierarchy\",\r\n \"categories\": [\r\n {\r\n \"name\": \"getindex\",\r\n \"label\": \"getIndex()\"\r\n },\r\n {\r\n \"name\": \"contextualparams\",\r\n \"label\": \"Contextual parameters\"\r\n },\r\n {\r\n \"name\": \"parentdata\",\r\n \"label\": \"Accessing parent data\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsrtags\",\r\n \"label\": \"Template tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"assigntag\",\r\n \"label\": \"{{: ...}}\"\r\n },\r\n {\r\n \"name\": \"htmltag\",\r\n \"label\": \"{{> ...}}\"\r\n },\r\n {\r\n \"name\": \"includetag\",\r\n \"label\": \"{{include ...}}\"\r\n },\r\n {\r\n \"name\": \"fortag\",\r\n \"label\": \"{{for ...}}\"\r\n },\r\n {\r\n \"name\": \"propstag\",\r\n \"label\": \"{{props ...}}\"\r\n },\r\n {\r\n \"name\": \"iftag\",\r\n \"label\": \"{{if ...}}\"\r\n },\r\n {\r\n \"name\": \"elsetag\",\r\n \"label\": \"{{else ...}}\"\r\n },\r\n {\r\n \"name\": \"allowcodetag\",\r\n \"label\": \"{{* ... }} and {{*: ...}}\"\r\n },\r\n {\r\n \"name\": \"customtagsapi\",\r\n \"label\": \"Custom tags\"\r\n },\r\n {\r\n \"name\": \"commenttag\",\r\n \"label\": \"{{!-- ... --}}\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"rendertmpl\",\r\n \"label\": \"Render a template\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tmplrender\",\r\n \"label\": \"myTmpl.render()\"\r\n },\r\n {\r\n \"name\": \"d.render\",\r\n \"label\": \"$.render.myTmpl()\"\r\n },\r\n {\r\n \"name\": \"db.render\",\r\n \"label\": \"$(\\\"#myTmpl\\\").render()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"apps\",\r\n \"label\": \"Building apps\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsrmodel\",\r\n \"label\": \"Data / View Model\",\r\n \"categories\": [\r\n {\r\n \"name\": \"viewmodelsapi\",\r\n \"label\": \"$.views.viewModels()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"compiletmpl\",\r\n \"label\": \"Templates\",\r\n \"categories\": [\r\n {\r\n \"name\": \"d.templates\",\r\n \"label\": \"$.templates()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"helpers\",\r\n \"label\": \"Helpers\",\r\n \"categories\": [\r\n {\r\n \"name\": \"helpersapi\",\r\n \"label\": \"$.views.helpers()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"tags\",\r\n \"label\": \"Custom tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagsapi\",\r\n \"label\": \"$.views.tags()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"converters\",\r\n \"label\": \"Converters\",\r\n \"categories\": [\r\n {\r\n \"name\": \"convertersapi\",\r\n \"label\": \"$.views.converters()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"settings\",\r\n \"label\": \"Settings\",\r\n \"categories\": [\r\n {\r\n \"name\": \"settings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"name\": \"settings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"name\": \"settings/allowcode\",\r\n \"label\": \"Allow code\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"advanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"onerror\",\r\n \"label\": \"Error handling\"\r\n },\r\n {\r\n \"name\": \"nojqueryapi\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"name\": \"jsrobjects\",\r\n \"label\": \"JsRender objects\",\r\n \"categories\": [\r\n {\r\n \"name\": \"viewsobject\",\r\n \"label\": \"$.views object\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"templateobject\",\r\n \"label\": \"template object\"\r\n },\r\n {\r\n \"name\": \"viewobject\",\r\n \"label\": \"view object\"\r\n },\r\n {\r\n \"name\": \"tagobject\",\r\n \"label\": \"tag object\"\r\n },\r\n {\r\n \"name\": \"ctxobject\",\r\n \"label\": \"View context object (ctx)\"\r\n },\r\n {\r\n \"name\": \"tagctxobject\",\r\n \"label\": \"Tag context object (tagCtx)\"\r\n },\r\n {\r\n \"name\": \"globals\",\r\n \"label\": \"Globals\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"jsrnode\",\r\n \"label\": \"JsRender on Node.js\",\r\n \"categories\": [\r\n {\r\n \"name\": \"node/install\",\r\n \"label\": \"Installation and usage\"\r\n },\r\n {\r\n \"name\": \"node/filetmpls\",\r\n \"label\": \"File-based templates\"\r\n },\r\n {\r\n \"name\": \"node/express-hapi\",\r\n \"label\": \"Express and Hapi integration\"\r\n },\r\n {\r\n \"name\": \"node/server-browser\",\r\n \"label\": \"Server/browser shared templates\"\r\n },\r\n {\r\n \"name\": \"node/browserify\",\r\n \"label\": \"Browserify support\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"node/webpack\",\r\n \"label\": \"Webpack support\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"jsvapi\",\r\n \"label\": \"JsViews API - Data-driven UI\",\r\n \"heading\": \"JsViews API documentation\",\r\n \"description\": \"Detailed API docs on using JsViews for dynamic data-driven sites, or MVVM\",\r\n \"categories\": [\r\n {\r\n \"name\": \"linked-template-syntax\",\r\n \"label\": \"Data-linked template syntax\",\r\n \"categories\": [\r\n {\r\n \"name\": \"linked-tag-syntax\",\r\n \"label\": \"Data-linked tags\"\r\n },\r\n {\r\n \"name\": \"linked-elem-syntax\",\r\n \"label\": \"Data-linked elements\"\r\n },\r\n {\r\n \"name\": \"linked-paths\",\r\n \"label\": \"Data-linked paths\"\r\n },\r\n {\r\n \"name\": \"link2way\",\r\n \"label\": \"Two-way binding\"\r\n },\r\n {\r\n \"name\": \"link-events\",\r\n \"label\": \"Event bindings\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvtags\",\r\n \"label\": \"Template tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvassigntag\",\r\n \"label\": \"{^{: ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvhtmltag\",\r\n \"label\": \"{^{> ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvincludetag\",\r\n \"label\": \"{^{include ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvfortag\",\r\n \"label\": \"{^{for ...}}\"\r\n },\r\n {\r\n \"name\": \"jsviftag\",\r\n \"label\": \"{^{if ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvpropstag\",\r\n \"label\": \"{^{props ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvradiogrouptag\",\r\n \"label\": \"{^{radiogroup ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvelsetag\",\r\n \"label\": \"{{else ...}}\"\r\n },\r\n {\r\n \"name\": \"jsvontag\",\r\n \"label\": \"{^{on ...}}\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvlinktmpl\",\r\n \"label\": \"Render and link a template\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvtmpllink\",\r\n \"label\": \"myTmpl.link()\"\r\n },\r\n {\r\n \"name\": \"jsv.d.link\",\r\n \"label\": \"$.link.myTmpl()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvapps\",\r\n \"label\": \"Building apps\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvmodel\",\r\n \"label\": \"Data / View Model\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvviewmodelsapi\",\r\n \"label\": \"$.views.viewModels()\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"linkedtmpls\",\r\n \"label\": \"Data-linked templates\"\r\n },\r\n {\r\n \"name\": \"jsvtagcontrols\",\r\n \"label\": \"Custom tag controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"tagoptions\",\r\n \"label\": \"Tag control options\"\r\n },\r\n {\r\n \"name\": \"tagstructure\",\r\n \"label\": \"Tag control structure\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"taglifecycle\",\r\n \"label\": \"Tag control life-cycle\"\r\n },\r\n {\r\n \"name\": \"tagpatterns\",\r\n \"label\": \"Tag design patterns\",\r\n \"categories\": [\r\n {\r\n \"name\": \"renderingpatterns\",\r\n \"label\": \"Layout and rendering\"\r\n },\r\n {\r\n \"name\": \"bindingpatterns\",\r\n \"label\": \"Data binding\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"hierarchypatterns\",\r\n \"label\": \"Tag hierarchy\"\r\n },\r\n {\r\n \"name\": \"todo\",\r\n \"label\": \"TODO\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvhelpers-converters\",\r\n \"label\": \"Helpers and converters\"\r\n },\r\n {\r\n \"name\": \"mvvm-views\",\r\n \"label\": \"MVVM -- Dynamic view hierarchy\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"toplink\",\r\n \"label\": \"Top-level data-linking\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsv.toplink-true\",\r\n \"label\": \"Declarative: $.link(true, ...)\"\r\n },\r\n {\r\n \"name\": \"jsv.toplink-expr\",\r\n \"label\": \"Programmatic: $.link(...)\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"$view\",\r\n \"label\": \"Views: from UI to data\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsv.d.view\",\r\n \"label\": \"$.view()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"link-targets\",\r\n \"label\": \"Targets for data-linking\",\r\n \"categories\": [\r\n {\r\n \"name\": \"link-formelems\",\r\n \"label\": \"Form elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"link-input\",\r\n \"label\": \"textbox / checkbox / radio\"\r\n },\r\n {\r\n \"name\": \"link-select\",\r\n \"label\": \"select\"\r\n },\r\n {\r\n \"name\": \"link-textarea\",\r\n \"label\": \"textarea\"\r\n },\r\n {\r\n \"name\": \"link-button\",\r\n \"label\": \"button\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"link-text-html\",\r\n \"label\": \"innerText / innerHTML\"\r\n },\r\n {\r\n \"name\": \"link-css\",\r\n \"label\": \"CSS attributes\"\r\n },\r\n {\r\n \"name\": \"link-class\",\r\n \"label\": \"class\"\r\n },\r\n {\r\n \"name\": \"link-visibility\",\r\n \"label\": \"visibility\"\r\n },\r\n {\r\n \"name\": \"link-elemattribs\",\r\n \"label\": \"Element attributes/properties\"\r\n },\r\n {\r\n \"name\": \"link-tags\",\r\n \"label\": \"Tag bindings\"\r\n },\r\n {\r\n \"name\": \"link-computed\",\r\n \"label\": \"Computed observables\"\r\n },\r\n {\r\n \"name\": \"link-svg\",\r\n \"label\": \"SVG elements\"\r\n },\r\n {\r\n \"name\": \"link-contenteditable\",\r\n \"label\": \"contenteditable elements\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvsettings\",\r\n \"label\": \"Settings\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvsettings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"name\": \"jsvsettings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"name\": \"jsvsettings/trigger\",\r\n \"label\": \"Trigger\"\r\n },\r\n {\r\n \"name\": \"jsvsettings/allowcode\",\r\n \"label\": \"Allow code\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"jsvadvanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvsettings/advanced\",\r\n \"label\": \"Advanced settings\"\r\n },\r\n {\r\n \"name\": \"jsvobjects\",\r\n \"label\": \"JsViews objects\",\r\n \"categories\": [\r\n {\r\n \"name\": \"jsvviewsobject\",\r\n \"label\": \"$.views object\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvtemplateobject\",\r\n \"label\": \"template object\"\r\n },\r\n {\r\n \"name\": \"jsvviewobject\",\r\n \"label\": \"view object\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvtagobject\",\r\n \"label\": \"tag object\"\r\n },\r\n {\r\n \"name\": \"jsvctxobject\",\r\n \"label\": \"View context object (ctx)\"\r\n },\r\n {\r\n \"name\": \"jsvtagctxobject\",\r\n \"label\": \"Tag context object (tagCtx)\"\r\n },\r\n {\r\n \"name\": \"jsvlinkctxobject\",\r\n \"label\": \"Link context object (linkCtx)\"\r\n },\r\n {\r\n \"name\": \"eventArgs\",\r\n \"label\": \"eventArgs object\"\r\n },\r\n {\r\n \"name\": \"jsvglobals\",\r\n \"label\": \"Globals\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"jsvunlink\",\r\n \"label\": \"$.unlink()\",\r\n \"categories\": [],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"jsoapi\",\r\n \"label\": \"JsObservable API - Observing data\",\r\n \"heading\": \"JsObservable API documentation\",\r\n \"description\": \"Detailed API docs on using JsObservable for observing or triggering data changes in a single-page app\",\r\n \"categories\": [\r\n {\r\n \"name\": \"$observable\",\r\n \"label\": \"Observable objects and arrays\"\r\n },\r\n {\r\n \"name\": \"propchange\",\r\n \"label\": \"Modify an object observably\",\r\n \"categories\": [\r\n {\r\n \"name\": \"setprop\",\r\n \"label\": \"$.observable(object).setProperty()\"\r\n },\r\n {\r\n \"name\": \"removeprop\",\r\n \"label\": \"$.observable(obj).removeProperty()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"arrchange\",\r\n \"label\": \"Modify an array observably\",\r\n \"categories\": [\r\n {\r\n \"name\": \"insert\",\r\n \"label\": \"$.observable(array).insert()\"\r\n },\r\n {\r\n \"name\": \"remove\",\r\n \"label\": \"$.observable(array).remove()\"\r\n },\r\n {\r\n \"name\": \"move\",\r\n \"label\": \"$.observable(array).move()\"\r\n },\r\n {\r\n \"name\": \"refresh\",\r\n \"label\": \"$.observable(array).refresh()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"observeobjectsarrays\",\r\n \"label\": \"Respond to data changes\",\r\n \"categories\": [\r\n {\r\n \"name\": \"onpropchange\",\r\n \"label\": \"onPropertyChange\"\r\n },\r\n {\r\n \"name\": \"onarrchange\",\r\n \"label\": \"onArrayChange\"\r\n },\r\n {\r\n \"name\": \"observe\",\r\n \"label\": \"$.observe()\"\r\n },\r\n {\r\n \"name\": \"unobserve\",\r\n \"label\": \"$.unobserve()\"\r\n },\r\n {\r\n \"name\": \"observeAll\",\r\n \"label\": \"$.observable().observeAll()\"\r\n },\r\n {\r\n \"name\": \"unobserveAll\",\r\n \"label\": \"$.observable().unobserveAll()\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"computed\",\r\n \"label\": \"Computed observables\"\r\n },\r\n {\r\n \"name\": \"jsoadvanced\",\r\n \"label\": \"Advanced\",\r\n \"categories\": [\r\n {\r\n \"name\": \"namespaces\",\r\n \"label\": \"Namespaces\"\r\n }\r\n ],\r\n \"expanded\": false\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples\",\r\n \"label\": \"Samples\",\r\n \"heading\": \"Samples for JsRender, JsViews or JsObservable\",\r\n \"description\": \"Examples of some of the ways you can use JsRender templates, JsViews tag controls, and more\",\r\n \"categories\": [\r\n {\r\n \"filter\": \"jsr\",\r\n \"name\": \"samples/jsr\",\r\n \"label\": \"JsRender samples\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/converters\",\r\n \"label\": \"Converters and encoding\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition\",\r\n \"label\": \"Template composition\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/composition/tmpl\",\r\n \"label\": \"tmpl property\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/from-strings\",\r\n \"label\": \"From strings\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/remote-tmpl\",\r\n \"label\": \"Remote templates\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Using sub-templates\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/composition/tmpl-objects\",\r\n \"label\": \"Contextual template objects\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/jsr/tags\",\r\n \"label\": \"Custom tags\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/jsr/tags/wrap-content\",\r\n \"label\": \"Wrapping content\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/tags/extend-for\",\r\n \"label\": \"Extending for\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/jsr/helpers\",\r\n \"label\": \"Helpers\"\r\n },\r\n {\r\n \"name\": \"samples/jsr/paths\",\r\n \"label\": \"Paths\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"samples/jso\",\r\n \"label\": \"JsObservable samples\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"filter\": \"jsv\",\r\n \"name\": \"samples/jsv\",\r\n \"label\": \"JsViews samples\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/data-link\",\r\n \"label\": \"Data-linking tags and elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/data-link/from-render-to-link\",\r\n \"label\": \"From rendering to linking\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/for-and-if\",\r\n \"label\": \"Linking {^{for}} and {^{if}}\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/class\",\r\n \"label\": \"Linking class\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/toggle\",\r\n \"label\": \"Toggling class with data-link\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/attributes\",\r\n \"label\": \"Linking attributes\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/visibility\",\r\n \"label\": \"Linking visibility\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/hover\",\r\n \"label\": \"Linking visibility and hover\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/css\",\r\n \"label\": \"Linking CSS attributes\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/svg\",\r\n \"label\": \"Linking SVG elements\"\r\n },\r\n {\r\n \"name\": \"samples/data-link/computed\",\r\n \"label\": \"Computed ....!!\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/editable\",\r\n \"label\": \"Editable data\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/editable/tags\",\r\n \"label\": \"Data-linked tags\"\r\n },\r\n {\r\n \"name\": \"samples/editable/elems\",\r\n \"label\": \"Data-linked elements\"\r\n },\r\n {\r\n \"name\": \"samples/editable/toplevel-for\",\r\n \"label\": \"Top-level elems with {for...}\"\r\n },\r\n {\r\n \"name\": \"samples/editable/observe\",\r\n \"label\": \"$.observe()\"\r\n },\r\n {\r\n \"name\": \"samples/editable/compiled\",\r\n \"label\": \"Compiled View Models\"\r\n },\r\n {\r\n \"name\": \"samples/editable/submit\",\r\n \"label\": \"Submit changes\"\r\n },\r\n {\r\n \"name\": \"samples/editable/hash\",\r\n \"label\": \"hash/dictionary\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/form-elems\",\r\n \"label\": \"Form elements\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/form-els/simple\",\r\n \"label\": \"Form element binding\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/array-binding\",\r\n \"label\": \"Array binding\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/converters\",\r\n \"label\": \"2-way binding and converters\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/visible-binding\",\r\n \"label\": \"Form elements and visibility\"\r\n },\r\n {\r\n \"name\": \"samples/form-els/edit\",\r\n \"label\": \"Edit tag control\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"samples/form-els/validation\",\r\n \"label\": \"With validation\",\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"samples/form-els/submit\",\r\n \"label\": \"Submitting the form\",\r\n \"hidden\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/computed\",\r\n \"label\": \"Computed observables\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/computed/fullname\",\r\n \"label\": \"fullName variants\"\r\n },\r\n {\r\n \"name\": \"samples/computed/shopping-cart\",\r\n \"label\": \"Shopping cart\"\r\n },\r\n {\r\n \"name\": \"samples/computed/team-manager\",\r\n \"label\": \"Team manager\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls\",\r\n \"label\": \"Tag controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui\",\r\n \"label\": \"jQueryUI widget controls\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/api\",\r\n \"label\": \"Accessing widget APIs\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker\",\r\n \"label\": \"datepicker control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/simple\",\r\n \"label\": \"Simple datepicker\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/variants\",\r\n \"label\": \"datepicker variants\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/formats\",\r\n \"label\": \"Date formats\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/with-validation\",\r\n \"label\": \"With validation\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/datepicker/with-validation-wizard\",\r\n \"label\": \"With validation wizard\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider\",\r\n \"label\": \"slider control (jQuery UI)\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/simple\",\r\n \"label\": \"Simple slider\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/variants\",\r\n \"label\": \"slider variants\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/with-validation\",\r\n \"label\": \"With validation\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/slider/color-picker\",\r\n \"label\": \"Color picker\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner\",\r\n \"label\": \"spinner control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner/variants\",\r\n \"label\": \"spinner variants\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/spinner/formats\",\r\n \"label\": \"Formats and cultures\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/timespinner\",\r\n \"label\": \"timespinner control\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/toolbar\",\r\n \"label\": \"button radio checkbox...\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/tabs\",\r\n \"label\": \"tabs control (jQuery UI)\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/menu\",\r\n \"label\": \"menu control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/selectmenu\",\r\n \"label\": \"selectmenu control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/progressbar\",\r\n \"label\": \"progressbar control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/accordion\",\r\n \"label\": \"accordion control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/autocomplete\",\r\n \"label\": \"autocomplete control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/selectable\",\r\n \"label\": \"selectable control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/sortable\",\r\n \"label\": \"sortable control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/resizable\",\r\n \"label\": \"resizable control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jqui/draggable-droppable\",\r\n \"label\": \"draggable droppable\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tabs\",\r\n \"label\": \"tabs control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/multiselect\",\r\n \"label\": \"multiselect control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree\",\r\n \"label\": \"tree control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/tree/visible-binding\",\r\n \"label\": \"tree with 'visible' binding\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree/if-binding\",\r\n \"label\": \"tree with if-binding\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/tree/editable\",\r\n \"label\": \"Editable tree\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate\",\r\n \"label\": \"validate control\",\r\n \"categories\": [\r\n {\r\n \"name\": \"samples/tag-controls/validate/simple\",\r\n \"label\": \"Simple validate\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate/group\",\r\n \"label\": \"Validation group\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/validate/array-binding\",\r\n \"label\": \"Array binding\"\r\n }\r\n ],\r\n \"expanded\": false\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/simple-textbox\",\r\n \"label\": \"simple textbox control\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/purchases\",\r\n \"label\": \"purchases control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/slider\",\r\n \"label\": \"slider control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/areaslider\",\r\n \"label\": \"areaslider control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/spinblock\",\r\n \"label\": \"spinblock control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/colorpicker\",\r\n \"label\": \"colorpicker control\"\r\n },\r\n {\r\n \"name\": \"samples/tag-controls/jsonview\",\r\n \"label\": \"jsonview control\"\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download\",\r\n \"label\": \"Download\",\r\n \"heading\": \"Downloading JsViews, JsRender and JsObservable\",\r\n \"description\": \"\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download\",\r\n \"label\": \"Latest version\"\r\n },\r\n {\r\n \"name\": \"download/specific\",\r\n \"label\": \"Specific versions\",\r\n \"expanded\": true,\r\n \"hidden\": true\r\n },\r\n {\r\n \"name\": \"download/pages\",\r\n \"label\": \"Example pages\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download/pages-jsr-jq\",\r\n \"label\": \"JsRender with jQuery\"\r\n },\r\n {\r\n \"name\": \"download/pages-jsr\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"name\": \"download/pages-jsv\",\r\n \"label\": \"JsViews\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download/jsrplugins\",\r\n \"label\": \"JsRender plugins\",\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"download/jsvplugins\",\r\n \"label\": \"JsViews plugins\",\r\n \"categories\": [\r\n {\r\n \"name\": \"download/sample-tagcontrols\",\r\n \"label\": \"Sample tag controls\"\r\n },\r\n {\r\n \"name\": \"download/jqueryui-tagcontrols\",\r\n \"label\": \"jQuery UI tag controls\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"typescript\",\r\n \"label\": \"TypeScript declaration files\"\r\n }\r\n ],\r\n \"expanded\": true\r\n },\r\n {\r\n \"name\": \"community\",\r\n \"label\": \"JsViews Community\",\r\n \"heading\": \"JsViews and JsRender Community\",\r\n \"description\": \"Viewing the source code, filing bugs or feature requests...\",\r\n \"categories\": [\r\n {\r\n \"name\": \"github\",\r\n \"label\": \"GitHub\",\r\n \"expanded\": true\r\n }\r\n ],\r\n \"expanded\": true\r\n }\r\n];"]} \ No newline at end of file diff --git a/documentation/contents-download.js b/documentation/contents-download.js index 5760ce29..2dec6d35 100644 --- a/documentation/contents-download.js +++ b/documentation/contents-download.js @@ -9,12 +9,19 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "", - "text": "
JsRender (jsrender.js) – rendering templates in the browser
\n\n***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jsrender.js\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\n\n\n*JsRender is also available:*\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\n\n*Example HTML pages:*\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\n- [Page loading JsRender without jQuery](#download/pages-jsr)\n\n*See:*\n[JsRender Quickstart](#jsr-quickstart)\n\n" + "text": "The latest version of both *JsRender* and *JsViews* is ***v1.0.0***" }, { "_type": "para", - "title": "", - "text": "
JsViews (jsviews.js) – templates with data-binding
\n\n***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jsviews.js\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\n\n*JsViews is also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews](#download/pages-jsv)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)\n\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)" + "title": "JsRender (jsviews.js) – rendering templates in the browser", + "text": "***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jsrender.js\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\n\n\n*JsRender is also available:*\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\n\n*Example HTML pages:*\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\n- [Page loading JsRender without jQuery](#download/pages-jsr)\n\n*See:*\n[JsRender Quickstart](#jsr-quickstart)\n\n", + "anchor": "jsrender" + }, + { + "_type": "para", + "title": "JsViews (jsviews.js) – templates with data-binding", + "text": "***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jsviews.js\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\n\n*JsViews is also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews](#download/pages-jsv)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)\n\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)", + "anchor": "jsviews" }, { "_type": "para", @@ -24,17 +31,20 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "JsRender for Node.js – rendering templates on the server", - "text": "A specific Node.js version of JsRender can be installed from npm, using:\n\n```js\n$ npm install jsrender\n```\n\nand then loaded in script using:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call regular JsRender APIs, such as:\n\n```js\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\n\nvar html = tmpl.render({name: \"Jim\"}); // Render\n```\n\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\n\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart)." + "text": "A specific Node.js version of JsRender can be installed from npm, using:\n\n```js\n$ npm install jsrender\n```\n\nand then loaded in script using:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call regular JsRender APIs, such as:\n\n```js\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\n\nvar html = tmpl.render({name: \"Jim\"}); // Render\n```\n\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\n\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart).", + "anchor": "nodejs" }, { "_type": "para", "title": "Loading JsViews as separate files", - "text": "Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\n\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\n\n***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\n\n*jquery.observable.js and jquery.views.js are also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)" + "text": "Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\n\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\n\n***Latest version*** *(To download, right-click and select \"Save as...\" from the menu):*\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\n\n*jquery.observable.js and jquery.views.js are also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)", + "anchor": "separate" }, { "_type": "para", "title": "CDN delivery", - "text": "JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\n\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)" + "text": "JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\n\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)", + "anchor": "cdn" } ] }, @@ -67,7 +77,7 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "", - "text": "The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \n\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\n\n*(To download, right-click and select “Save as…” from the menu.)*\n\n- **{^{tabs/}}**\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\n- **{^{tree/}}**\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\n- **{^{textbox/}}**\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\n- **{^{validate/}}** and **{^{validation/}}** \n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\n
Used in the\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\n [validate simple](#samples/tag-controls/validate/simple)\n and the [validate tag control](#samples/tag-controls/validate) samples\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\n- **{^{slider/}}**\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\n- **{^{areaslider/}}**\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\n- **{^{spinblock/}}**\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\n- **{^{colorpicker/}}**\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\n- **{^{jsonview/}}**\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\n\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\n\n```jsr\n...\n\n...\n\n\n\n...\n```" + "text": "The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \n\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\n\n*(To download, right-click and select “Save as…” from the menu.)*\n\n- **{^{tabs/}}**\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\n- **{^{tree/}}**\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\n- **{^{textbox/}}**\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\n- **{^{validate/}}** and **{^{validation/}}** \n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\n
Used in the\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\n [validate simple](#samples/tag-controls/validate/simple)\n and the [validate tag control](#samples/tag-controls/validate) samples\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\n- **{^{slider/}}**\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\n- **{^{areaslider/}}**\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\n- **{^{spinblock/}}**\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\n- **{^{colorpicker/}}**\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\n- **{^{jsonview/}}**\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\n\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\n\n```jsr\n...\n\n...\n\n\n\n...\n```" } ] }, @@ -104,13 +114,13 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "Example HTML page, using latest version of JsRender from www.jsviews.com", - "text": "```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", + "text": "```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", "anchor": "" }, { "_type": "para", "title": "Alternatives: replace the JsRender <script> tag above by one of the following:", - "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```" + "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```" } ] }, @@ -122,13 +132,13 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "Example HTML page, using latest version of JsRender from www.jsviews.com", - "text": "```jsr\n\n\n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", + "text": "```jsr\n\n\n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", "anchor": "" }, { "_type": "para", "title": "Alternatives: replace the JsRender <script> tag above by one of the following:", - "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```" + "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```" } ] }, @@ -140,13 +150,13 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "Example HTML page, loading latest version of JsViews from www.jsviews.com", - "text": "```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", + "text": "```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", "anchor": "" }, { "_type": "para", "title": "Alternatives: replace the JsViews <script> tag above by one of the following:", - "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n```" + "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n```" }, { "_type": "para", @@ -156,13 +166,13 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "Example HTML page, loading JsViews as separate files", - "text": "```jsr\n\n\n\n \n \n\n \n \n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", + "text": "```jsr\n\n\n\n \n \n\n \n \n \n \n\n\n \n
\n\n \n \n\n \n\n\n```", "anchor": "separate" }, { "_type": "para", "title": "Alternatives: replace the three JsViews <script> tags above by one of the following:", - "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n\n\n```" + "text": "*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n\n\n```" } ] }, @@ -189,7 +199,7 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "", - "text": "To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\n\n```jsr\n...\n\n\n...\n\n\n...\n```\n\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\n\n```jsr\n\n```\n\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\n" + "text": "To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\n\n```jsr\n...\n\n\n...\n\n\n...\n```\n\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\n\n```jsr\n\n```\n\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\n" } ] }, @@ -206,7 +216,7 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "", - "text": "```jsr\n...\n\n\n...\n```" + "text": "```jsr\n...\n\n\n...\n```" } ] }, @@ -223,7 +233,7 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie { "_type": "para", "title": "", - "text": "```jsr\n...\n\n\n...\n```" + "text": "```jsr\n...\n\n\n...\n```" }, { "_type": "links", @@ -241,5 +251,16 @@ content.download = content.useStorage && $.parseJSON(localStorage.getItem("JsVie ] } ] + }, + "typescript": { + "title": "Typescript declaration files", + "path": "", + "sections": [ + { + "_type": "para", + "title": "", + "text": "JsRender and JsViews have TypeScript declaration files available:\n\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsrender/index.d.ts) for jsrender\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsviews/index.d.ts) for jsviews\n\nBoth will be published to [DefinitelyTyped](https://definitelytyped.org).\n\nNote that the JsViews declaration file depends on the JsRender declaration file (and both depend on the jQuery TypeScript declaration file). They include appropriate triple slash type references such as `/// ` " + } + ] } }; \ No newline at end of file diff --git a/documentation/contents-download.min.js b/documentation/contents-download.min.js index 9224f068..b614a1d4 100644 --- a/documentation/contents-download.min.js +++ b/documentation/contents-download.min.js @@ -1,3 +1,3 @@ -var content=$.views.documentation.content;content.download=content.useStorage&&$.parseJSON(localStorage.getItem("JsViewsDocTopics/download"))||{download:{title:"JsRender and JsViews Downloads",path:"",sections:[{_type:"para",title:"",text:'
JsRender (jsrender.js) – rendering templates in the browser
\n\n***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jsrender.js\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\n\n\n*JsRender is also available:*\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\n\n*Example HTML pages:*\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\n- [Page loading JsRender without jQuery](#download/pages-jsr)\n\n*See:*\n[JsRender Quickstart](#jsr-quickstart)\n\n'},{_type:"para",title:"",text:'
JsViews (jsviews.js) – templates with data-binding
\n\n***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jsviews.js\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\n\n*JsViews is also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews](#download/pages-jsv)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)\n\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)'},{_type:"para",title:"",text:'
Additional scenarios:
\n'},{_type:"para",title:"JsRender for Node.js – rendering templates on the server",text:"A specific Node.js version of JsRender can be installed from npm, using:\n\n```js\n$ npm install jsrender\n```\n\nand then loaded in script using:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call regular JsRender APIs, such as:\n\n```js\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\n\nvar html = tmpl.render({name: \"Jim\"}); // Render\n```\n\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\n\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart)."},{_type:"para",title:"Loading JsViews as separate files",text:'Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\n\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\n\n***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\n\n*jquery.observable.js and jquery.views.js are also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)'},{_type:"para",title:"CDN delivery",text:"JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\n\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)"}]},"download/specific":{title:"JsRender, JsViews and JsObservable Downloads",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"download",label:"Latest versions"}]},{_type:"para",title:"",text:'

Specific named versions:

\n\n(These links will continue to point to the specific version, even after subsequent new releases).\n\nTo download these files, right-click and select "Save as..." from the menu.\n\n
JsRender beta
\n\nStatus: JsRender is currently beta. V1.0 is planned to be available right after JsViews official beta release is complete.\n\nUncompressed (for development): jsrender-v1.0.0-beta.js.
Compressed (for production): jsrender-v1.0.0-beta.min.js. (Source map available here).\n\n
JsViews pre beta
\n\nStatus: JsViews is currently a beta candidate. It will be officially labelled "beta" as soon as reasonably complete documentation for the JsViews and JsObservable APIs has been made available on this site. (Coming soon...)\n\nSingle file version (includes JsRender, JsObservable and JsViews)\n\nUncompressed (for development): jsviews-v1.0.0-alpha.js.
Compressed (for production): jsviews-v1.0.0-alpha.min.js. (Source map available here).\n\nSeparate files (to be used with jsrender.js)\n\nUncompressed (for development): jquery.views-v1.0.0-alpha.js.
Compressed (for production): jquery.views-v1.0.0-alpha.min.js. (Source map available here).\n\nUncompressed (for development): jquery.observable-v1.0.0-alpha.js.
Compressed (for production): jquery.observable-v1.0.0-alpha.min.js. (Source map available here).'}]},"download/sample-tagcontrols":{title:"Sample tag controls – plugin libraries",path:"",sections:[{_type:"para",title:"",text:'The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \n\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\n\n*(To download, right-click and select “Save as…” from the menu.)*\n\n- **{^{tabs/}}**\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\n- **{^{tree/}}**\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\n- **{^{textbox/}}**\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\n- **{^{validate/}}** and **{^{validation/}}** \n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\n
Used in the\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\n [validate simple](#samples/tag-controls/validate/simple)\n and the [validate tag control](#samples/tag-controls/validate) samples\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\n- **{^{slider/}}**\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\n- **{^{areaslider/}}**\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\n- **{^{spinblock/}}**\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\n- **{^{colorpicker/}}**\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\n- **{^{jsonview/}}**\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\n\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\n\n```jsr\n...\n\n...\n\n\n\n...\n```'}]},"download/pages":{title:"Example HTML pages – loading JsRender or JsViews ",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"download/pages-jsr-jq",label:"JsRender with jQuery"},{hash:"download/pages-jsr",label:"JsRender without jQuery"},{hash:"download/pages-jsv",label:"JsViews"}]}]},"download/pages-jsr-jq":{filter:"jsr",title:"Loading JsRender with jQuery",path:"",sections:[{_type:"para",title:"Example HTML page, using latest version of JsRender from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsRender <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```'}]},"download/pages-jsr":{filter:"jsr",title:"Loading JsRender without jQuery",path:"",sections:[{_type:"para",title:"Example HTML page, using latest version of JsRender from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsRender <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```'}]},"download/pages-jsv":{filter:"jsv",title:"Loading JsViews",path:"",sections:[{_type:"para",title:"Example HTML page, loading latest version of JsViews from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsViews <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n```'},{_type:"para",title:"",text:'
JsViews – separate files
\n\nUsually JsViews as a single file (*jsviews.js*), as in the example HTML page above.\n\nHowever it can be loaded as three separate files: *jsrender.js* (templated rendering), *jquery.observable.js* (observable data) and *jquery.views.js* (data-binding) -- as follows:\n'},{_type:"para",title:"Example HTML page, loading JsViews as separate files",text:'```jsr\n\n\n\n \n \n\n \n \n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:"separate"},{_type:"para",title:"Alternatives: replace the three JsViews <script> tags above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n\n\n```'}]},"download/jqueryui-tagcontrols":{filter:"jsv",title:"jQuery UI tag controls library",path:"",sections:[{_type:"para",title:"",text:"The *jQuery UI tag controls library: __jsviews-jqueryui-widgets.js__* is a set of tag controls based on jQuery UI widgets."},{_type:"para",title:"Download:",text:'*Uncompressed (for development):* jsviews-jqueryui-widgets.js
\n*Compressed (for production):* jsviews-jqueryui-widgets.min.js. (Source map available here)\n\n*(To download, right-click and select “Save as…” from the menu.)*'},{_type:"para",title:"Tag controls:",text:"The library provides the following tag controls (each integrating the corresponding jQuery UI widget):
\n\n- *__{{autocomplete/}}__* -- based on [jQuery UI autocomplete](https://jqueryui.com/autocomplete/)\n([api](https://api.jqueryui.com/autocomplete/))\n - used in the [autocomplete](#samples/tag-controls/jqui/autocomplete) sample\n- *__{{accordion/}}__* -- based on [jQuery UI accordion](https://jqueryui.com/accordion/)\n([api](https://api.jqueryui.com/accordion/))\n - used in the [accordion](#samples/tag-controls/jqui/accordion) samples\n- *__{{button/}}__* -- based on [jQuery UI button](https://jqueryui.com/button/)\n([api](https://api.jqueryui.com/button/))\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{checkbox/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\n([api](https://api.jqueryui.com/checkboxradio/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [Accessing widget APIs](#samples/tag-controls/jqui/api@widgetapi) samples\n- *__{{radio/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\n([api](https://api.jqueryui.com/checkboxradio/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\n- *__{{controlgroup/}}__* -- based on [jQuery UI controlgroup](https://jqueryui.com/controlgroup/)\n([api](https://api.jqueryui.com/controlgroup/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\n- *__{{buttonset}}__* -- *deprecated and available only if using jQuery UI 1.11.4*\n- *__{{datepicker/}}__* -- based on [jQuery UI datepicker](https://jqueryui.com/datepicker/)\n([api](https://api.jqueryui.com/datepicker/))\n - used in the [simple datepicker](#samples/tag-controls/jqui/datepicker/simple),\n[datepicker variants](#samples/tag-controls/jqui/datepicker/variants),\n[datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation)\nand [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard) samples\n- *__{{draggable/}}__* -- based on [jQuery UI draggable](https://jqueryui.com/draggable/)\n([api](https://api.jqueryui.com/draggable/))\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\n- *__{{droppable/}}__* -- based on [jQuery UI droppable](https://jqueryui.com/droppable/)\n([api](https://api.jqueryui.com/droppable/))\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\n- *__{{menu/}}__* -- based on [jQuery UI menu](https://jqueryui.com/menu/)\n([api](https://api.jqueryui.com/menu/))\n - used in the [menu](#samples/tag-controls/jqui/menu) samples\n- *__{{progressbar/}}__* -- based on [jQuery UI progressbar](https://jqueryui.com/progressbar/)\n([api](https://api.jqueryui.com/progressbar/))\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{resizable/}}__* -- based on [jQuery UI resizable](https://jqueryui.com/resizable/)\n([api](https://api.jqueryui.com/resizable/))\n - used in the [resizable](#samples/tag-controls/jqui/resizable) samples\n- *__{{selectable/}}__* -- based on [jQuery UI selectable](https://jqueryui.com/selectable/)\n([api](https://api.jqueryui.com/selectable/))\n - used in the [selectable](#samples/tag-controls/jqui/selectable) samples\n- *__{{selectmenu/}}__* -- based on [jQuery UI selectmenu](https://jqueryui.com/selectmenu/)\n([api](https://api.jqueryui.com/selectmenu/))\n - used in the [selectmenu](#samples/tag-controls/jqui/selectmenu) samples\n- *__{{slider/}}__* -- based on [jQueryUI slider](https://jqueryui.com/slider/)\n([api](https://api.jqueryui.com/slider/))\n - used in the [simple slider](#samples/tag-controls/jqui/slider/simple),\n[slider variants](#samples/tag-controls/jqui/slider/variants),\n[slider with validation](#samples/tag-controls/jqui/slider/with-validation),\n[sliders as color picker](#samples/tag-controls/jqui/slider/color-picker),\n[Toolbar](#samples/tag-controls/jqui/toolbar),\n[resizable](#samples/tag-controls/jqui/resizable),\n[draggable - droppable](#samples/tag-controls/jqui/draggable-droppable),\n[spinner](#samples/tag-controls/jqui/spinner) and\n[progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{sortable/}}__* -- based on [jQuery UI sortable](https://jqueryui.com/sortable/)\n([api](https://api.jqueryui.com/sortable/))\n - used in the [sortable](#samples/tag-controls/jqui/sortable) samples\n- *__{{spinner/}}__* -- based on [jQuery UI spinner](https://jqueryui.com/spinner/)\n([api](https://api.jqueryui.com/spinner/))\n - used in the [spinner](#samples/tag-controls/jqui/spinner)\nand [resizable](#samples/tag-controls/jqui/resizable) samples\n- *__{{timespinner/}}__* -- also based on [jQuery UI spinner](https://jqueryui.com/spinner/)\n([api](https://api.jqueryui.com/spinner/))\n - used in the [timespinner](#samples/tag-controls/jqui/timespinner) samples\n- *__{{tabs/}}__* -- based on [jQuery UI tabs](https://jqueryui.com/tabs/)\n([api](https://api.jqueryui.com/tabs/))\n - used in the [tabs](#samples/tag-controls/jqui/tabs) samples"},{_type:"para",title:"",text:'To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\n\n```jsr\n...\n\n\n...\n\n\n...\n```\n\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\n\n```jsr\n\n```\n\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\n' -}]},"download/jsrplugins":{filter:"jsr",title:"JsRender plugins",path:"",sections:[{_type:"para",title:"",text:"*JsRender* can be extended by including external libraries of custom tags, converters, helpers etc. -- such as the *jsonview.js* library:"},{_type:"para",title:"",text:'```jsr\n...\n\n\n...\n```'}]},"download/jsvplugins":{filter:"jsv",title:"JsViews plugins and tag controls",path:"",sections:[{_type:"para",title:"",text:"*JsViews* can be extended by including external libraries of custom tag controls, converters, helpers, etc. -- such as the *[jQuery UI tag controls](#download/jqueryui-tagcontrols)* library (*jsviews-jqueryui-widgets.js*):"},{_type:"para",title:"",text:'```jsr\n...\n\n\n...\n```'},{_type:"links",title:"",links:[],topics:[{hash:"download/sample-tagcontrols",label:"Sample tag controls"},{hash:"download/jqueryui-tagcontrols",label:"jQuery UI tag controls"}]}]}}; +var content=$.views.documentation.content;content.download=content.useStorage&&$.parseJSON(localStorage.getItem("JsViewsDocTopics/download"))||{download:{title:"JsRender and JsViews Downloads",path:"",sections:[{_type:"para",title:"",text:"The latest version of both *JsRender* and *JsViews* is ***v1.0.0***"},{_type:"para",title:"JsRender (jsviews.js) – rendering templates in the browser",text:'***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jsrender.js\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\n\n\n*JsRender is also available:*\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\n\n*Example HTML pages:*\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\n- [Page loading JsRender without jQuery](#download/pages-jsr)\n\n*See:*\n[JsRender Quickstart](#jsr-quickstart)\n\n',anchor:"jsrender"},{_type:"para",title:"JsViews (jsviews.js) – templates with data-binding",text:'***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jsviews.js\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\n\n*JsViews is also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews](#download/pages-jsv)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)\n\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)',anchor:"jsviews"},{_type:"para",title:"",text:'
Additional scenarios:
\n'},{_type:"para",title:"JsRender for Node.js – rendering templates on the server",text:"A specific Node.js version of JsRender can be installed from npm, using:\n\n```js\n$ npm install jsrender\n```\n\nand then loaded in script using:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call regular JsRender APIs, such as:\n\n```js\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\n\nvar html = tmpl.render({name: \"Jim\"}); // Render\n```\n\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\n\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart).",anchor:"nodejs"},{_type:"para",title:"Loading JsViews as separate files",text:'Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\n\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\n\n***Latest version*** *(To download, right-click and select "Save as..." from the menu):*\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\n\n*jquery.observable.js and jquery.views.js are also available:*\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\n\n*Example HTML page:*\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\n\n*See:* [JsViews Quickstart](#jsv-quickstart)',anchor:"separate"},{_type:"para",title:"CDN delivery",text:"JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\n\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)",anchor:"cdn"}]},"download/specific":{title:"JsRender, JsViews and JsObservable Downloads",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"download",label:"Latest versions"}]},{_type:"para",title:"",text:'

Specific named versions:

\n\n(These links will continue to point to the specific version, even after subsequent new releases).\n\nTo download these files, right-click and select "Save as..." from the menu.\n\n
JsRender beta
\n\nStatus: JsRender is currently beta. V1.0 is planned to be available right after JsViews official beta release is complete.\n\nUncompressed (for development): jsrender-v1.0.0-beta.js.
Compressed (for production): jsrender-v1.0.0-beta.min.js. (Source map available here).\n\n
JsViews pre beta
\n\nStatus: JsViews is currently a beta candidate. It will be officially labelled "beta" as soon as reasonably complete documentation for the JsViews and JsObservable APIs has been made available on this site. (Coming soon...)\n\nSingle file version (includes JsRender, JsObservable and JsViews)\n\nUncompressed (for development): jsviews-v1.0.0-alpha.js.
Compressed (for production): jsviews-v1.0.0-alpha.min.js. (Source map available here).\n\nSeparate files (to be used with jsrender.js)\n\nUncompressed (for development): jquery.views-v1.0.0-alpha.js.
Compressed (for production): jquery.views-v1.0.0-alpha.min.js. (Source map available here).\n\nUncompressed (for development): jquery.observable-v1.0.0-alpha.js.
Compressed (for production): jquery.observable-v1.0.0-alpha.min.js. (Source map available here).'}]},"download/sample-tagcontrols":{title:"Sample tag controls – plugin libraries",path:"",sections:[{_type:"para",title:"",text:'The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \n\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\n\n*(To download, right-click and select “Save as…” from the menu.)*\n\n- **{^{tabs/}}**\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\n- **{^{tree/}}**\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\n- **{^{textbox/}}**\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\n- **{^{validate/}}** and **{^{validation/}}** \n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\n
Used in the\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\n [validate simple](#samples/tag-controls/validate/simple)\n and the [validate tag control](#samples/tag-controls/validate) samples\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\n- **{^{slider/}}**\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\n- **{^{areaslider/}}**\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\n- **{^{spinblock/}}**\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\n- **{^{colorpicker/}}**\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\n- **{^{jsonview/}}**\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\n\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\n\n```jsr\n...\n\n...\n\n\n\n...\n```'}]},"download/pages":{title:"Example HTML pages – loading JsRender or JsViews ",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"download/pages-jsr-jq",label:"JsRender with jQuery"},{hash:"download/pages-jsr",label:"JsRender without jQuery"},{hash:"download/pages-jsv",label:"JsViews"}]}]},"download/pages-jsr-jq":{filter:"jsr",title:"Loading JsRender with jQuery",path:"",sections:[{_type:"para",title:"Example HTML page, using latest version of JsRender from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsRender <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```'}]},"download/pages-jsr":{filter:"jsr",title:"Loading JsRender without jQuery",path:"",sections:[{_type:"para",title:"Example HTML page, using latest version of JsRender from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsRender <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\n\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\n\n```jsr\n\n```'}]},"download/pages-jsv":{filter:"jsv",title:"Loading JsViews",path:"",sections:[{_type:"para",title:"Example HTML page, loading latest version of JsViews from www.jsviews.com",text:'```jsr\n\n\n\n \n \n\n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:""},{_type:"para",title:"Alternatives: replace the JsViews <script> tag above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n```'},{_type:"para",title:"",text:'
JsViews – separate files
\n\nUsually JsViews as a single file (*jsviews.js*), as in the example HTML page above.\n\nHowever it can be loaded as three separate files: *jsrender.js* (templated rendering), *jquery.observable.js* (observable data) and *jquery.views.js* (data-binding) -- as follows:\n'},{_type:"para",title:"Example HTML page, loading JsViews as separate files",text:'```jsr\n\n\n\n \n \n\n \n \n \n \n\n\n \n
\n\n \n \n\n \n\n\n```',anchor:"separate"},{_type:"para",title:"Alternatives: replace the three JsViews <script> tags above by one of the following:",text:'*Using latest version, minified, from www.jsviews.com:*\n\n```jsr\n\n\n\n```\n\n*Using specific version from CDN:*\n\n```jsr\n\n\n\n```\n\n*Using specific version, minified, from CDN:*\n\n```jsr\n\n\n\n```\n\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\n\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\n\n```jsr\n\n\n\n```'}]},"download/jqueryui-tagcontrols":{filter:"jsv",title:"jQuery UI tag controls library",path:"",sections:[{_type:"para",title:"",text:"The *jQuery UI tag controls library: __jsviews-jqueryui-widgets.js__* is a set of tag controls based on jQuery UI widgets."},{_type:"para",title:"Download:",text:'*Uncompressed (for development):* jsviews-jqueryui-widgets.js
\n*Compressed (for production):* jsviews-jqueryui-widgets.min.js. (Source map available here)\n\n*(To download, right-click and select “Save as…” from the menu.)*'},{_type:"para",title:"Tag controls:",text:"The library provides the following tag controls (each integrating the corresponding jQuery UI widget):
\n\n- *__{{autocomplete/}}__* -- based on [jQuery UI autocomplete](https://jqueryui.com/autocomplete/)\n([api](https://api.jqueryui.com/autocomplete/))\n - used in the [autocomplete](#samples/tag-controls/jqui/autocomplete) sample\n- *__{{accordion/}}__* -- based on [jQuery UI accordion](https://jqueryui.com/accordion/)\n([api](https://api.jqueryui.com/accordion/))\n - used in the [accordion](#samples/tag-controls/jqui/accordion) samples\n- *__{{button/}}__* -- based on [jQuery UI button](https://jqueryui.com/button/)\n([api](https://api.jqueryui.com/button/))\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{checkbox/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\n([api](https://api.jqueryui.com/checkboxradio/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [Accessing widget APIs](#samples/tag-controls/jqui/api@widgetapi) samples\n- *__{{radio/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\n([api](https://api.jqueryui.com/checkboxradio/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\n- *__{{controlgroup/}}__* -- based on [jQuery UI controlgroup](https://jqueryui.com/controlgroup/)\n([api](https://api.jqueryui.com/controlgroup/))\n(requires jQuery UI version 1.12.1 or later)\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\n- *__{{buttonset}}__* -- *deprecated and available only if using jQuery UI 1.11.4*\n- *__{{datepicker/}}__* -- based on [jQuery UI datepicker](https://jqueryui.com/datepicker/)\n([api](https://api.jqueryui.com/datepicker/))\n - used in the [simple datepicker](#samples/tag-controls/jqui/datepicker/simple),\n[datepicker variants](#samples/tag-controls/jqui/datepicker/variants),\n[datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation)\nand [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard) samples\n- *__{{draggable/}}__* -- based on [jQuery UI draggable](https://jqueryui.com/draggable/)\n([api](https://api.jqueryui.com/draggable/))\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\n- *__{{droppable/}}__* -- based on [jQuery UI droppable](https://jqueryui.com/droppable/)\n([api](https://api.jqueryui.com/droppable/))\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\n- *__{{menu/}}__* -- based on [jQuery UI menu](https://jqueryui.com/menu/)\n([api](https://api.jqueryui.com/menu/))\n - used in the [menu](#samples/tag-controls/jqui/menu) samples\n- *__{{progressbar/}}__* -- based on [jQuery UI progressbar](https://jqueryui.com/progressbar/)\n([api](https://api.jqueryui.com/progressbar/))\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{resizable/}}__* -- based on [jQuery UI resizable](https://jqueryui.com/resizable/)\n([api](https://api.jqueryui.com/resizable/))\n - used in the [resizable](#samples/tag-controls/jqui/resizable) samples\n- *__{{selectable/}}__* -- based on [jQuery UI selectable](https://jqueryui.com/selectable/)\n([api](https://api.jqueryui.com/selectable/))\n - used in the [selectable](#samples/tag-controls/jqui/selectable) samples\n- *__{{selectmenu/}}__* -- based on [jQuery UI selectmenu](https://jqueryui.com/selectmenu/)\n([api](https://api.jqueryui.com/selectmenu/))\n - used in the [selectmenu](#samples/tag-controls/jqui/selectmenu) samples\n- *__{{slider/}}__* -- based on [jQueryUI slider](https://jqueryui.com/slider/)\n([api](https://api.jqueryui.com/slider/))\n - used in the [simple slider](#samples/tag-controls/jqui/slider/simple),\n[slider variants](#samples/tag-controls/jqui/slider/variants),\n[slider with validation](#samples/tag-controls/jqui/slider/with-validation),\n[sliders as color picker](#samples/tag-controls/jqui/slider/color-picker),\n[Toolbar](#samples/tag-controls/jqui/toolbar),\n[resizable](#samples/tag-controls/jqui/resizable),\n[draggable - droppable](#samples/tag-controls/jqui/draggable-droppable),\n[spinner](#samples/tag-controls/jqui/spinner) and\n[progressbar](#samples/tag-controls/jqui/progressbar) samples\n- *__{{sortable/}}__* -- based on [jQuery UI sortable](https://jqueryui.com/sortable/)\n([api](https://api.jqueryui.com/sortable/))\n - used in the [sortable](#samples/tag-controls/jqui/sortable) samples\n- *__{{spinner/}}__* -- based on [jQuery UI spinner](https://jqueryui.com/spinner/)\n([api](https://api.jqueryui.com/spinner/))\n - used in the [spinner](#samples/tag-controls/jqui/spinner)\nand [resizable](#samples/tag-controls/jqui/resizable) samples\n- *__{{timespinner/}}__* -- also based on [jQuery UI spinner](https://jqueryui.com/spinner/)\n([api](https://api.jqueryui.com/spinner/))\n - used in the [timespinner](#samples/tag-controls/jqui/timespinner) samples\n- *__{{tabs/}}__* -- based on [jQuery UI tabs](https://jqueryui.com/tabs/)\n([api](https://api.jqueryui.com/tabs/))\n - used in the [tabs](#samples/tag-controls/jqui/tabs) samples"},{_type:"para",title:"",text:'To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\n\n```jsr\n...\n\n\n...\n\n\n...\n```\n\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\n\n```jsr\n\n```\n\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\n' +}]},"download/jsrplugins":{filter:"jsr",title:"JsRender plugins",path:"",sections:[{_type:"para",title:"",text:"*JsRender* can be extended by including external libraries of custom tags, converters, helpers etc. -- such as the *jsonview.js* library:"},{_type:"para",title:"",text:'```jsr\n...\n\n\n...\n```'}]},"download/jsvplugins":{filter:"jsv",title:"JsViews plugins and tag controls",path:"",sections:[{_type:"para",title:"",text:"*JsViews* can be extended by including external libraries of custom tag controls, converters, helpers, etc. -- such as the *[jQuery UI tag controls](#download/jqueryui-tagcontrols)* library (*jsviews-jqueryui-widgets.js*):"},{_type:"para",title:"",text:'```jsr\n...\n\n\n...\n```'},{_type:"links",title:"",links:[],topics:[{hash:"download/sample-tagcontrols",label:"Sample tag controls"},{hash:"download/jqueryui-tagcontrols",label:"jQuery UI tag controls"}]}]},typescript:{title:"Typescript declaration files",path:"",sections:[{_type:"para",title:"",text:'JsRender and JsViews have TypeScript declaration files available:\n\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsrender/index.d.ts) for jsrender\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsviews/index.d.ts) for jsviews\n\nBoth will be published to [DefinitelyTyped](https://definitelytyped.org).\n\nNote that the JsViews declaration file depends on the JsRender declaration file (and both depend on the jQuery TypeScript declaration file). They include appropriate triple slash type references such as `/// ` '}]}}; //# sourceMappingURL=contents-download.min.js.map diff --git a/documentation/contents-download.min.js.map b/documentation/contents-download.min.js.map index acd7b5fb..d6cc2e14 100644 --- a/documentation/contents-download.min.js.map +++ b/documentation/contents-download.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["contents-download.js"],"names":["content","$","views","documentation","download","useStorage","parseJSON","localStorage","getItem","title","path","sections","_type","text","download/specific","links","topics","hash","label","download/sample-tagcontrols","download/pages","download/pages-jsr-jq","filter","anchor","download/pages-jsr","download/pages-jsv","download/jqueryui-tagcontrols","download/jsrplugins","download/jsvplugins"],"mappings":"AAAA,GAAIA,SAAUC,EAAEC,MAAMC,cAAcH,OAEpCA,SAAQI,SAAWJ,QAAQK,YAAcJ,EAAEK,UAAUC,aAAaC,QAAQ,gCAExEJ,UACEK,MAAS,iCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,s7BAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,g8BAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,qDAGRD,MAAS,OACTH,MAAS,iEACTI,KAAQ,+1BAGRD,MAAS,OACTH,MAAS,oCACTI,KAAQ,unDAGRD,MAAS,OACTH,MAAS,eACTI,KAAQ,wOAIdC,qBACEL,MAAS,+CACTC,KAAQ,GACRC,WAEIC,MAAS,QACTH,MAAS,GACTM,SACAC,SAEIC,KAAQ,WACRC,MAAS,sBAKbN,MAAS,OACTH,MAAS,GACTI,KAAQ,62EAIdM,+BACEV,MAAS,+CACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,urPAIdO,kBACEX,MAAS,0DACTC,KAAQ,GACRC,WAEIC,MAAS,QACTH,MAAS,GACTM,SACAC,SAEIC,KAAQ,wBACRC,MAAS,yBAGTD,KAAQ,qBACRC,MAAS,4BAGTD,KAAQ,qBACRC,MAAS,eAMnBG,yBACEC,OAAU,MACVb,MAAS,+BACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,2EACTI,KAAQ,kzBACRU,OAAU,KAGVX,MAAS,OACTH,MAAS,uFACTI,KAAQ,yxBAIdW,sBACEF,OAAU,MACVb,MAAS,kCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,2EACTI,KAAQ,2iCACRU,OAAU,KAGVX,MAAS,OACTH,MAAS,uFACTI,KAAQ,yxBAIdY,sBACEH,OAAU,MACVb,MAAS,kBACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,4EACTI,KAAQ,6yBACRU,OAAU,KAGVX,MAAS,OACTH,MAAS,sFACTI,KAAQ,2wBAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,4UAGRD,MAAS,OACTH,MAAS,uDACTI,KAAQ,49BACRU,OAAU,aAGVX,MAAS,OACTH,MAAS,6FACTI,KAAQ,86CAIda,iCACEJ,OAAU,MACVb,MAAS,iCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,+HAGRD,MAAS,OACTH,MAAS,YACTI,KAAQ,khBAGRD,MAAS,OACTH,MAAS,gBACTI,KAAQ,4wKAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ;IAIdc,uBACEL,OAAU,MACVb,MAAS,mBACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,8IAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,+KAIde,uBACEN,OAAU,MACVb,MAAS,mCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,mOAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,6LAGRD,MAAS,QACTH,MAAS,GACTM,SACAC,SAEIC,KAAQ,8BACRC,MAAS,wBAGTD,KAAQ,gCACRC,MAAS","file":"contents-download.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.download = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocTopics/download\")) ||\r\n{\r\n \"download\": {\r\n \"title\": \"JsRender and JsViews Downloads\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
JsRender (jsrender.js) – rendering templates in the browser
\\n\\n***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jsrender.js\\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\\n\\n\\n*JsRender is also available:*\\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\\n\\n*Example HTML pages:*\\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\\n- [Page loading JsRender without jQuery](#download/pages-jsr)\\n\\n*See:*\\n[JsRender Quickstart](#jsr-quickstart)\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
JsViews (jsviews.js) – templates with data-binding
\\n\\n***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jsviews.js\\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\\n\\n*JsViews is also available:*\\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\\n\\n*Example HTML page:*\\n- [Page loading JsViews](#download/pages-jsv)\\n\\n*See:* [JsViews Quickstart](#jsv-quickstart)\\n\\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
Additional scenarios:
\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender for Node.js – rendering templates on the server\",\r\n \"text\": \"A specific Node.js version of JsRender can be installed from npm, using:\\n\\n```js\\n$ npm install jsrender\\n```\\n\\nand then loaded in script using:\\n\\n```js\\nvar jsrender = require('jsrender');\\n```\\n\\nNow call regular JsRender APIs, such as:\\n\\n```js\\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\\n\\nvar html = tmpl.render({name: \\\"Jim\\\"}); // Render\\n```\\n\\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\\n\\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Loading JsViews as separate files\",\r\n \"text\": \"Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\\n\\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\\n\\n***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\\n\\n*jquery.observable.js and jquery.views.js are also available:*\\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\\n\\n*Example HTML page:*\\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\\n\\n*See:* [JsViews Quickstart](#jsv-quickstart)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"CDN delivery\",\r\n \"text\": \"JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\\n\\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\"\r\n }\r\n ]\r\n },\r\n \"download/specific\": {\r\n \"title\": \"JsRender, JsViews and JsObservable Downloads\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download\",\r\n \"label\": \"Latest versions\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"

Specific named versions:

\\n\\n(These links will continue to point to the specific version, even after subsequent new releases).\\n\\nTo download these files, right-click and select \\\"Save as...\\\" from the menu.\\n\\n
JsRender beta
\\n\\nStatus: JsRender is currently beta. V1.0 is planned to be available right after JsViews official beta release is complete.\\n\\nUncompressed (for development): jsrender-v1.0.0-beta.js.
Compressed (for production): jsrender-v1.0.0-beta.min.js. (Source map available here).\\n\\n
JsViews pre beta
\\n\\nStatus: JsViews is currently a beta candidate. It will be officially labelled \\\"beta\\\" as soon as reasonably complete documentation for the JsViews and JsObservable APIs has been made available on this site. (Coming soon...)\\n\\nSingle file version (includes JsRender, JsObservable and JsViews)\\n\\nUncompressed (for development): jsviews-v1.0.0-alpha.js.
Compressed (for production): jsviews-v1.0.0-alpha.min.js. (Source map available here).\\n\\nSeparate files (to be used with jsrender.js)\\n\\nUncompressed (for development): jquery.views-v1.0.0-alpha.js.
Compressed (for production): jquery.views-v1.0.0-alpha.min.js. (Source map available here).\\n\\nUncompressed (for development): jquery.observable-v1.0.0-alpha.js.
Compressed (for production): jquery.observable-v1.0.0-alpha.min.js. (Source map available here).\"\r\n }\r\n ]\r\n },\r\n \"download/sample-tagcontrols\": {\r\n \"title\": \"Sample tag controls – plugin libraries\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \\n\\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\\n\\n*(To download, right-click and select “Save as…” from the menu.)*\\n\\n- **{^{tabs/}}**\\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\\n- **{^{tree/}}**\\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\\n- **{^{textbox/}}**\\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\\n- **{^{validate/}}** and **{^{validation/}}** \\n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\\n
Used in the\\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\\n [validate simple](#samples/tag-controls/validate/simple)\\n and the [validate tag control](#samples/tag-controls/validate) samples\\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\\n- **{^{slider/}}**\\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\\n- **{^{areaslider/}}**\\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\\n- **{^{spinblock/}}**\\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\\n- **{^{colorpicker/}}**\\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\\n- **{^{jsonview/}}**\\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\\n\\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\\n\\n```jsr\\n...\\n\\n...\\n\\n\\n\\n...\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages\": {\r\n \"title\": \"Example HTML pages – loading JsRender or JsViews \",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download/pages-jsr-jq\",\r\n \"label\": \"JsRender with jQuery\"\r\n },\r\n {\r\n \"hash\": \"download/pages-jsr\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"hash\": \"download/pages-jsv\",\r\n \"label\": \"JsViews\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"download/pages-jsr-jq\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"Loading JsRender with jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, using latest version of JsRender from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsRender <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\\n\\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages-jsr\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"Loading JsRender without jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, using latest version of JsRender from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsRender <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\\n\\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages-jsv\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"Loading JsViews\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, loading latest version of JsViews from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsViews <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\\n\\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
JsViews – separate files
\\n\\nUsually JsViews as a single file (*jsviews.js*), as in the example HTML page above.\\n\\nHowever it can be loaded as three separate files: *jsrender.js* (templated rendering), *jquery.observable.js* (observable data) and *jquery.views.js* (data-binding) -- as follows:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, loading JsViews as separate files\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"separate\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the three JsViews <script> tags above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\\n\\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\\n\\n```jsr\\n\\n\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/jqueryui-tagcontrols\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"jQuery UI tag controls library\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The *jQuery UI tag controls library: __jsviews-jqueryui-widgets.js__* is a set of tag controls based on jQuery UI widgets.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Download:\",\r\n \"text\": \"*Uncompressed (for development):* jsviews-jqueryui-widgets.js
\\n*Compressed (for production):* jsviews-jqueryui-widgets.min.js. (Source map available here)\\n\\n*(To download, right-click and select “Save as…” from the menu.)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag controls:\",\r\n \"text\": \"The library provides the following tag controls (each integrating the corresponding jQuery UI widget):
\\n\\n- *__{{autocomplete/}}__* -- based on [jQuery UI autocomplete](https://jqueryui.com/autocomplete/)\\n([api](https://api.jqueryui.com/autocomplete/))\\n - used in the [autocomplete](#samples/tag-controls/jqui/autocomplete) sample\\n- *__{{accordion/}}__* -- based on [jQuery UI accordion](https://jqueryui.com/accordion/)\\n([api](https://api.jqueryui.com/accordion/))\\n - used in the [accordion](#samples/tag-controls/jqui/accordion) samples\\n- *__{{button/}}__* -- based on [jQuery UI button](https://jqueryui.com/button/)\\n([api](https://api.jqueryui.com/button/))\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{checkbox/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\\n([api](https://api.jqueryui.com/checkboxradio/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [Accessing widget APIs](#samples/tag-controls/jqui/api@widgetapi) samples\\n- *__{{radio/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\\n([api](https://api.jqueryui.com/checkboxradio/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\\n- *__{{controlgroup/}}__* -- based on [jQuery UI controlgroup](https://jqueryui.com/controlgroup/)\\n([api](https://api.jqueryui.com/controlgroup/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\\n- *__{{buttonset}}__* -- *deprecated and available only if using jQuery UI 1.11.4*\\n- *__{{datepicker/}}__* -- based on [jQuery UI datepicker](https://jqueryui.com/datepicker/)\\n([api](https://api.jqueryui.com/datepicker/))\\n - used in the [simple datepicker](#samples/tag-controls/jqui/datepicker/simple),\\n[datepicker variants](#samples/tag-controls/jqui/datepicker/variants),\\n[datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation)\\nand [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard) samples\\n- *__{{draggable/}}__* -- based on [jQuery UI draggable](https://jqueryui.com/draggable/)\\n([api](https://api.jqueryui.com/draggable/))\\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\\n- *__{{droppable/}}__* -- based on [jQuery UI droppable](https://jqueryui.com/droppable/)\\n([api](https://api.jqueryui.com/droppable/))\\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\\n- *__{{menu/}}__* -- based on [jQuery UI menu](https://jqueryui.com/menu/)\\n([api](https://api.jqueryui.com/menu/))\\n - used in the [menu](#samples/tag-controls/jqui/menu) samples\\n- *__{{progressbar/}}__* -- based on [jQuery UI progressbar](https://jqueryui.com/progressbar/)\\n([api](https://api.jqueryui.com/progressbar/))\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{resizable/}}__* -- based on [jQuery UI resizable](https://jqueryui.com/resizable/)\\n([api](https://api.jqueryui.com/resizable/))\\n - used in the [resizable](#samples/tag-controls/jqui/resizable) samples\\n- *__{{selectable/}}__* -- based on [jQuery UI selectable](https://jqueryui.com/selectable/)\\n([api](https://api.jqueryui.com/selectable/))\\n - used in the [selectable](#samples/tag-controls/jqui/selectable) samples\\n- *__{{selectmenu/}}__* -- based on [jQuery UI selectmenu](https://jqueryui.com/selectmenu/)\\n([api](https://api.jqueryui.com/selectmenu/))\\n - used in the [selectmenu](#samples/tag-controls/jqui/selectmenu) samples\\n- *__{{slider/}}__* -- based on [jQueryUI slider](https://jqueryui.com/slider/)\\n([api](https://api.jqueryui.com/slider/))\\n - used in the [simple slider](#samples/tag-controls/jqui/slider/simple),\\n[slider variants](#samples/tag-controls/jqui/slider/variants),\\n[slider with validation](#samples/tag-controls/jqui/slider/with-validation),\\n[sliders as color picker](#samples/tag-controls/jqui/slider/color-picker),\\n[Toolbar](#samples/tag-controls/jqui/toolbar),\\n[resizable](#samples/tag-controls/jqui/resizable),\\n[draggable - droppable](#samples/tag-controls/jqui/draggable-droppable),\\n[spinner](#samples/tag-controls/jqui/spinner) and\\n[progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{sortable/}}__* -- based on [jQuery UI sortable](https://jqueryui.com/sortable/)\\n([api](https://api.jqueryui.com/sortable/))\\n - used in the [sortable](#samples/tag-controls/jqui/sortable) samples\\n- *__{{spinner/}}__* -- based on [jQuery UI spinner](https://jqueryui.com/spinner/)\\n([api](https://api.jqueryui.com/spinner/))\\n - used in the [spinner](#samples/tag-controls/jqui/spinner)\\nand [resizable](#samples/tag-controls/jqui/resizable) samples\\n- *__{{timespinner/}}__* -- also based on [jQuery UI spinner](https://jqueryui.com/spinner/)\\n([api](https://api.jqueryui.com/spinner/))\\n - used in the [timespinner](#samples/tag-controls/jqui/timespinner) samples\\n- *__{{tabs/}}__* -- based on [jQuery UI tabs](https://jqueryui.com/tabs/)\\n([api](https://api.jqueryui.com/tabs/))\\n - used in the [tabs](#samples/tag-controls/jqui/tabs) samples\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\\n\\n```jsr\\n...\\n\\n\\n...\\n\\n\\n...\\n```\\n\\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\\n\\n```jsr\\n\\n```\\n\\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\\n\"\r\n }\r\n ]\r\n },\r\n \"download/jsrplugins\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"JsRender plugins\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsRender* can be extended by including external libraries of custom tags, converters, helpers etc. -- such as the *jsonview.js* library:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n\\n\\n...\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/jsvplugins\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"JsViews plugins and tag controls\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsViews* can be extended by including external libraries of custom tag controls, converters, helpers, etc. -- such as the *[jQuery UI tag controls](#download/jqueryui-tagcontrols)* library (*jsviews-jqueryui-widgets.js*):\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n\\n\\n...\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download/sample-tagcontrols\",\r\n \"label\": \"Sample tag controls\"\r\n },\r\n {\r\n \"hash\": \"download/jqueryui-tagcontrols\",\r\n \"label\": \"jQuery UI tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n};"]} \ No newline at end of file +{"version":3,"sources":["contents-download.js"],"names":["content","$","views","documentation","download","useStorage","parseJSON","localStorage","getItem","title","path","sections","_type","text","anchor","download/specific","links","topics","hash","label","download/sample-tagcontrols","download/pages","download/pages-jsr-jq","filter","download/pages-jsr","download/pages-jsv","download/jqueryui-tagcontrols","download/jsrplugins","download/jsvplugins","typescript"],"mappings":"AAAA,GAAIA,SAAUC,EAAEC,MAAMC,cAAcH,OAEpCA,SAAQI,SAAWJ,QAAQK,YAAcJ,EAAEK,UAAUC,aAAaC,QAAQ,gCAExEJ,UACEK,MAAS,iCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,wEAGRD,MAAS,OACTH,MAAS,mFACTI,KAAQ,y0BACRC,OAAU,aAGVF,MAAS,OACTH,MAAS,2EACTI,KAAQ,41BACRC,OAAU,YAGVF,MAAS,OACTH,MAAS,GACTI,KAAQ,qDAGRD,MAAS,OACTH,MAAS,iEACTI,KAAQ,61BACRC,OAAU,WAGVF,MAAS,OACTH,MAAS,oCACTI,KAAQ,qnDACRC,OAAU,aAGVF,MAAS,OACTH,MAAS,eACTI,KAAQ,qOACRC,OAAU,SAIhBC,qBACEN,MAAS,+CACTC,KAAQ,GACRC,WAEIC,MAAS,QACTH,MAAS,GACTO,SACAC,SAEIC,KAAQ,WACRC,MAAS,sBAKbP,MAAS,OACTH,MAAS,GACTI,KAAQ,62EAIdO,+BACEX,MAAS,+CACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,+sPAIdQ,kBACEZ,MAAS,0DACTC,KAAQ,GACRC,WAEIC,MAAS,QACTH,MAAS,GACTO,SACAC,SAEIC,KAAQ,wBACRC,MAAS,yBAGTD,KAAQ,qBACRC,MAAS,4BAGTD,KAAQ,qBACRC,MAAS,eAMnBG,yBACEC,OAAU,MACVd,MAAS,+BACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,2EACTI,KAAQ,8zBACRC,OAAU,KAGVF,MAAS,OACTH,MAAS,uFACTI,KAAQ,yyBAIdW,sBACED,OAAU,MACVd,MAAS,kCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,2EACTI,KAAQ,ijCACRC,OAAU,KAGVF,MAAS,OACTH,MAAS,uFACTI,KAAQ,yyBAIdY,sBACEF,OAAU,MACVd,MAAS,kBACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,4EACTI,KAAQ,yzBACRC,OAAU,KAGVF,MAAS,OACTH,MAAS,sFACTI,KAAQ,2xBAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,4UAGRD,MAAS,OACTH,MAAS,uDACTI,KAAQ,o/BACRC,OAAU,aAGVF,MAAS,OACTH,MAAS,6FACTI,KAAQ,89CAIda,iCACEH,OAAU,MACVd,MAAS,iCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,+HAGRD,MAAS,OACTH,MAAS,YACTI,KAAQ,khBAGRD,MAAS,OACTH,MAAS,gBACTI,KAAQ,4wKAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ;IAIdc,uBACEJ,OAAU,MACVd,MAAS,mBACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,8IAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,2LAIde,uBACEL,OAAU,MACVd,MAAS,mCACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ,mOAGRD,MAAS,OACTH,MAAS,GACTI,KAAQ,yMAGRD,MAAS,QACTH,MAAS,GACTO,SACAC,SAEIC,KAAQ,8BACRC,MAAS,wBAGTD,KAAQ,gCACRC,MAAS,8BAMnBU,YACEpB,MAAS,+BACTC,KAAQ,GACRC,WAEIC,MAAS,OACTH,MAAS,GACTI,KAAQ","file":"contents-download.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.download = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocTopics/download\")) ||\r\n{\r\n \"download\": {\r\n \"title\": \"JsRender and JsViews Downloads\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The latest version of both *JsRender* and *JsViews* is ***v1.0.0***\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender (jsviews.js) – rendering templates in the browser\",\r\n \"text\": \"***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jsrender.js\\n- *Compressed (for production):* jsrender.min.js. (Source map available here)\\n\\n\\n*JsRender is also available:*\\n- on CDN at [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\\n- using [Bower](http://bower.io/search/?q=jsrender) to install on the file system: `$ bower install jsrender`\\n\\n*Example HTML pages:*\\n- [Page loading JsRender with jQuery](#download/pages-jsr-jq)\\n- [Page loading JsRender without jQuery](#download/pages-jsr)\\n\\n*See:*\\n[JsRender Quickstart](#jsr-quickstart)\\n\\n\",\r\n \"anchor\": \"jsrender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsViews (jsviews.js) – templates with data-binding\",\r\n \"text\": \"***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jsviews.js\\n- *Compressed (for production):* jsviews.min.js. (Source map available here)\\n\\n*JsViews is also available:*\\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\\n\\n*Example HTML page:*\\n- [Page loading JsViews](#download/pages-jsv)\\n\\n*See:* [JsViews Quickstart](#jsv-quickstart)\\n\\n(Note that *jsviews.js* includes all of *jsrender.js* code -- so *jsrender.js* does not need to be loaded first.)\",\r\n \"anchor\": \"jsviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
Additional scenarios:
\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender for Node.js – rendering templates on the server\",\r\n \"text\": \"A specific Node.js version of JsRender can be installed from npm, using:\\n\\n```js\\n$ npm install jsrender\\n```\\n\\nand then loaded in script using:\\n\\n```js\\nvar jsrender = require('jsrender');\\n```\\n\\nNow call regular JsRender APIs, such as:\\n\\n```js\\nvar tmpl = jsrender.templates('Name: {{:name}}
'); // Compile template from string\\n\\nvar html = tmpl.render({name: \\\"Jim\\\"}); // Render\\n```\\n\\nThis Node.js version of JsRender provides the complete set of JsRender APIs and features, together with integration with view-engines such as Express and Hapi, APIs for loading templates from the file system, and integration with Browserify for bundling server-side templates into client scripts for the browser.\\n\\n*See:* [JsRender Node.js Quickstart](#jsr-node-quickstart).\",\r\n \"anchor\": \"nodejs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Loading JsViews as separate files\",\r\n \"text\": \"Instead of loading JsViews as a single file (*jsviews.js*), it can be loaded as three separate files: *jsrender.js* (providing templated rendering), *jquery.observable.js* (for observable data) and *jquery.views.js* (data-binding).\\n\\nThis can be useful in some scenarios. For example, if JsRender has already been loaded (by other components, for example) then full JsViews functionality may be added by loading only the additional *jquery.observable.js* and *jquery.views.js* files (rather than the complete composite file, *jsviews.js*).\\n\\n***Latest version*** *(To download, right-click and select \\\"Save as...\\\" from the menu):*\\n- *Uncompressed (for development):* jquery.observable.js and jquery.views.js\\n- *Compressed (for production):* jquery.observable.min.js and jquery.views.min.js. (Source maps available here and here)\\n\\n*jquery.observable.js and jquery.views.js are also available:*\\n- on CDN at [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\\n- using [Bower](http://bower.io/search/?q=jsviews) to install on the file system: `$ bower install jsviews`\\n\\n*Example HTML page:*\\n- [Page loading JsViews as separate files](#download/pages-jsv@separate)\\n\\n*See:* [JsViews Quickstart](#jsv-quickstart)\",\r\n \"anchor\": \"separate\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"CDN delivery\",\r\n \"text\": \"JsRender and JsViews are available on the ***[cdnjs](https://cdnjs.com)*** CDN at:\\n\\n- [cdnjs.com/libraries/jsrender](https://cdnjs.com/libraries/jsrender)\\n- [cdnjs.com/libraries/jsviews](https://cdnjs.com/libraries/jsviews)\",\r\n \"anchor\": \"cdn\"\r\n }\r\n ]\r\n },\r\n \"download/specific\": {\r\n \"title\": \"JsRender, JsViews and JsObservable Downloads\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download\",\r\n \"label\": \"Latest versions\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"

Specific named versions:

\\n\\n(These links will continue to point to the specific version, even after subsequent new releases).\\n\\nTo download these files, right-click and select \\\"Save as...\\\" from the menu.\\n\\n
JsRender beta
\\n\\nStatus: JsRender is currently beta. V1.0 is planned to be available right after JsViews official beta release is complete.\\n\\nUncompressed (for development): jsrender-v1.0.0-beta.js.
Compressed (for production): jsrender-v1.0.0-beta.min.js. (Source map available here).\\n\\n
JsViews pre beta
\\n\\nStatus: JsViews is currently a beta candidate. It will be officially labelled \\\"beta\\\" as soon as reasonably complete documentation for the JsViews and JsObservable APIs has been made available on this site. (Coming soon...)\\n\\nSingle file version (includes JsRender, JsObservable and JsViews)\\n\\nUncompressed (for development): jsviews-v1.0.0-alpha.js.
Compressed (for production): jsviews-v1.0.0-alpha.min.js. (Source map available here).\\n\\nSeparate files (to be used with jsrender.js)\\n\\nUncompressed (for development): jquery.views-v1.0.0-alpha.js.
Compressed (for production): jquery.views-v1.0.0-alpha.min.js. (Source map available here).\\n\\nUncompressed (for development): jquery.observable-v1.0.0-alpha.js.
Compressed (for production): jquery.observable-v1.0.0-alpha.min.js. (Source map available here).\"\r\n }\r\n ]\r\n },\r\n \"download/sample-tagcontrols\": {\r\n \"title\": \"Sample tag controls – plugin libraries\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following tag controls, used in some of the samples, can be a starting point for your own custom tag controls. Some are very rudimentary, others are more advanced and complete. \\n\\n**Note:** If you use these controls in your own applications, it is recommended to download the files, or copy the code, rather than loading directly from this location, since the implementations (and associated APIs) may change over time as new versions of the samples are introduced.\\n\\n*(To download, right-click and select “Save as…” from the menu.)*\\n\\n- **{^{tabs/}}**\\n - *Download:* [tabs.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.js)\\n(*Compressed:* [tabs.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.min.js.map)*)\\n
Used in the [tabs](#samples/tag-controls/tabs) sample. (See also discussion [here](#bindingpatterns@tabsctxprm))\\n
Alternative versions:
[tabs2.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.js)\\n(*Compressed:* [tabs2.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs2.min.js.map)*) and:
[tabs3.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.js)\\n(*Compressed:* [tabs3.min.js](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs3.min.js.map)*)\\n - (*CSS:* [tabs.css](https://www.jsviews.com/download/sample-tag-controls/tabs/tabs.css))\\n- **{^{tree/}}**\\n - *Download:* [tree-if.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.js)\\n(*Compressed:* [tree-if.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-if.min.js.map)*)\\n
Used in the [tree (if-binding)](#samples/tag-controls/tree/if-binding) sample\\n - *Download:* [tree-visible.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.js)\\n(*Compressed:* [tree-visible.min.js](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/treeview/tree-visible.min.js.map)*)\\n
Used in the [tree (visible-binding)](#samples/tag-controls/tree/visible-binding) sample\\n - (*CSS:* [tree.css](https://www.jsviews.com/download/sample-tag-controls/treeview/tree.css))\\n- **{^{textbox/}}**\\n - *Download:* [simple-textbox.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.js)\\n(*Compressed:* [simple-textbox.min.js](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/textbox/simple-textbox.min.js.map)*)\\n
Used in the [simple textbox](#samples/tag-controls/simple-textbox) sample\\n- **{^{validate/}}** and **{^{validation/}}** \\n - *Download:* [validate.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.js)\\n(*Compressed:* [validate.min.js](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/validate/validate.min.js.map)*)\\n
Used in the\\n [datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation),\\n [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard),\\n [slider with validation](#samples/tag-controls/jqui/slider/with-validation),
\\n [validate simple](#samples/tag-controls/validate/simple)\\n and the [validate tag control](#samples/tag-controls/validate) samples\\n - (*CSS:* [validate.css](https://www.jsviews.com/download/sample-tag-controls/validate/validate.css))\\n- **{^{slider/}}**\\n - *Download:* [slider.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.js)\\n(*Compressed:* [slider.min.js](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/slider/slider.min.js.map)*)\\n
Used in the [slider](#samples/tag-controls/slider) JsViews sample\\n- **{^{areaslider/}}**\\n - *Download:* [areaslider.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.js)\\n(*Compressed:* [areaslider.min.js](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/areaslider/areaslider.min.js.map)*)\\n
Used in the [areaslider](#samples/tag-controls/areaslider) JsViews sample\\n- **{^{spinblock/}}**\\n - *Download:* [spinblock.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.js)\\n(*Compressed:* [spinblock.min.js](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/spinblock/spinblock.min.js.map)*)\\n
Used in the [spinblock](#samples/tag-controls/spinblock) JsViews sample\\n- **{^{colorpicker/}}**\\n - *Download:* [colorpicker.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.js)\\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\\n - *Download:* [colorpicker-multiformat.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.js)\\n(*Compressed:* [colorpicker-multiformat.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker@multiformat) JsViews sample\\n - *Download:* [colorpicker-multiformat2.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.js)\\n(*Compressed:* [colorpicker.min.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker-multiformat2.min.js.map)*)\\n
Used in the [colorpicker](#samples/tag-controls/colorpicker) JsViews sample\\n - (*CSS:* [colorpicker.css](https://www.jsviews.com/download/sample-tag-controls/colorpicker/colorpicker.css) *TinyColor:* [tinycolor.js](https://www.jsviews.com/download/sample-tag-controls/colorpicker/tinycolor.js))\\n- **{^{jsonview/}}**\\n - *Download:* [jsonview.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js)\\n(*Compressed:* [jsonview.min.js](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js). *Source map [here](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.min.js.map)*)\\n
Used in the [jsonview](#samples/tag-controls/jsonview) JsViews sample\\n - (*CSS:* [jsonview.css](https://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css))\\n\\nTo use the above tag controls simply include the corresponding libraries for your chosen tags, after loading *JsViews*:\\n\\n```jsr\\n...\\n\\n...\\n\\n\\n\\n...\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages\": {\r\n \"title\": \"Example HTML pages – loading JsRender or JsViews \",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download/pages-jsr-jq\",\r\n \"label\": \"JsRender with jQuery\"\r\n },\r\n {\r\n \"hash\": \"download/pages-jsr\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"hash\": \"download/pages-jsv\",\r\n \"label\": \"JsViews\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"download/pages-jsr-jq\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"Loading JsRender with jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, using latest version of JsRender from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsRender <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\\n\\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages-jsr\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"Loading JsRender without jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, using latest version of JsRender from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsRender <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsrender) *install:*\\n\\n-- Install JsRender on local file system, using `$ bower install jsrender`
-- then load `jsrender.js` or `jsrender.min.js` from the `bower_components/jsrender/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/pages-jsv\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"Loading JsViews\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, loading latest version of JsViews from www.jsviews.com\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the JsViews <script> tag above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\\n\\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load `jsviews.js` or `jsviews.min.js` from the `bower_components/jsviews/` folder, as in:\\n\\n```jsr\\n\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
JsViews – separate files
\\n\\nUsually JsViews as a single file (*jsviews.js*), as in the example HTML page above.\\n\\nHowever it can be loaded as three separate files: *jsrender.js* (templated rendering), *jquery.observable.js* (observable data) and *jquery.views.js* (data-binding) -- as follows:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example HTML page, loading JsViews as separate files\",\r\n \"text\": \"```jsr\\n\\n\\n\\n \\n \\n\\n \\n \\n \\n \\n\\n\\n \\n
\\n\\n \\n \\n\\n \\n\\n\\n```\",\r\n \"anchor\": \"separate\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternatives: replace the three JsViews <script> tags above by one of the following:\",\r\n \"text\": \"*Using latest version, minified, from www.jsviews.com:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Using specific version from CDN:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Using specific version, minified, from CDN:*\\n\\n```jsr\\n\\n\\n\\n```\\n\\n*Loading from the file system after* [Bower](http://bower.io/search/?q=jsviews) *install:*\\n\\n-- Install JsViews on local file system, using `$ bower install jsviews`
-- then load the correspondins `.js` or `.min.js` files from the `bower_components/jsviews/` folder, as in:\\n\\n```jsr\\n\\n\\n\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/jqueryui-tagcontrols\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"jQuery UI tag controls library\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The *jQuery UI tag controls library: __jsviews-jqueryui-widgets.js__* is a set of tag controls based on jQuery UI widgets.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Download:\",\r\n \"text\": \"*Uncompressed (for development):* jsviews-jqueryui-widgets.js
\\n*Compressed (for production):* jsviews-jqueryui-widgets.min.js. (Source map available here)\\n\\n*(To download, right-click and select “Save as…” from the menu.)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag controls:\",\r\n \"text\": \"The library provides the following tag controls (each integrating the corresponding jQuery UI widget):
\\n\\n- *__{{autocomplete/}}__* -- based on [jQuery UI autocomplete](https://jqueryui.com/autocomplete/)\\n([api](https://api.jqueryui.com/autocomplete/))\\n - used in the [autocomplete](#samples/tag-controls/jqui/autocomplete) sample\\n- *__{{accordion/}}__* -- based on [jQuery UI accordion](https://jqueryui.com/accordion/)\\n([api](https://api.jqueryui.com/accordion/))\\n - used in the [accordion](#samples/tag-controls/jqui/accordion) samples\\n- *__{{button/}}__* -- based on [jQuery UI button](https://jqueryui.com/button/)\\n([api](https://api.jqueryui.com/button/))\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{checkbox/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\\n([api](https://api.jqueryui.com/checkboxradio/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [Accessing widget APIs](#samples/tag-controls/jqui/api@widgetapi) samples\\n- *__{{radio/}}__* -- based on [jQuery UI checkboxradio](https://jqueryui.com/checkboxradio/)\\n([api](https://api.jqueryui.com/checkboxradio/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\\n- *__{{controlgroup/}}__* -- based on [jQuery UI controlgroup](https://jqueryui.com/controlgroup/)\\n([api](https://api.jqueryui.com/controlgroup/))\\n(requires jQuery UI version 1.12.1 or later)\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar) sample\\n- *__{{buttonset}}__* -- *deprecated and available only if using jQuery UI 1.11.4*\\n- *__{{datepicker/}}__* -- based on [jQuery UI datepicker](https://jqueryui.com/datepicker/)\\n([api](https://api.jqueryui.com/datepicker/))\\n - used in the [simple datepicker](#samples/tag-controls/jqui/datepicker/simple),\\n[datepicker variants](#samples/tag-controls/jqui/datepicker/variants),\\n[datepicker with validation](#samples/tag-controls/jqui/datepicker/with-validation)\\nand [datepicker with validation wizard](#samples/tag-controls/jqui/datepicker/with-validation-wizard) samples\\n- *__{{draggable/}}__* -- based on [jQuery UI draggable](https://jqueryui.com/draggable/)\\n([api](https://api.jqueryui.com/draggable/))\\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\\n- *__{{droppable/}}__* -- based on [jQuery UI droppable](https://jqueryui.com/droppable/)\\n([api](https://api.jqueryui.com/droppable/))\\n - used in the [draggable - droppable](#samples/tag-controls/jqui/draggable-droppable) samples\\n- *__{{menu/}}__* -- based on [jQuery UI menu](https://jqueryui.com/menu/)\\n([api](https://api.jqueryui.com/menu/))\\n - used in the [menu](#samples/tag-controls/jqui/menu) samples\\n- *__{{progressbar/}}__* -- based on [jQuery UI progressbar](https://jqueryui.com/progressbar/)\\n([api](https://api.jqueryui.com/progressbar/))\\n - used in the [Toolbar](#samples/tag-controls/jqui/toolbar)\\nand [progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{resizable/}}__* -- based on [jQuery UI resizable](https://jqueryui.com/resizable/)\\n([api](https://api.jqueryui.com/resizable/))\\n - used in the [resizable](#samples/tag-controls/jqui/resizable) samples\\n- *__{{selectable/}}__* -- based on [jQuery UI selectable](https://jqueryui.com/selectable/)\\n([api](https://api.jqueryui.com/selectable/))\\n - used in the [selectable](#samples/tag-controls/jqui/selectable) samples\\n- *__{{selectmenu/}}__* -- based on [jQuery UI selectmenu](https://jqueryui.com/selectmenu/)\\n([api](https://api.jqueryui.com/selectmenu/))\\n - used in the [selectmenu](#samples/tag-controls/jqui/selectmenu) samples\\n- *__{{slider/}}__* -- based on [jQueryUI slider](https://jqueryui.com/slider/)\\n([api](https://api.jqueryui.com/slider/))\\n - used in the [simple slider](#samples/tag-controls/jqui/slider/simple),\\n[slider variants](#samples/tag-controls/jqui/slider/variants),\\n[slider with validation](#samples/tag-controls/jqui/slider/with-validation),\\n[sliders as color picker](#samples/tag-controls/jqui/slider/color-picker),\\n[Toolbar](#samples/tag-controls/jqui/toolbar),\\n[resizable](#samples/tag-controls/jqui/resizable),\\n[draggable - droppable](#samples/tag-controls/jqui/draggable-droppable),\\n[spinner](#samples/tag-controls/jqui/spinner) and\\n[progressbar](#samples/tag-controls/jqui/progressbar) samples\\n- *__{{sortable/}}__* -- based on [jQuery UI sortable](https://jqueryui.com/sortable/)\\n([api](https://api.jqueryui.com/sortable/))\\n - used in the [sortable](#samples/tag-controls/jqui/sortable) samples\\n- *__{{spinner/}}__* -- based on [jQuery UI spinner](https://jqueryui.com/spinner/)\\n([api](https://api.jqueryui.com/spinner/))\\n - used in the [spinner](#samples/tag-controls/jqui/spinner)\\nand [resizable](#samples/tag-controls/jqui/resizable) samples\\n- *__{{timespinner/}}__* -- also based on [jQuery UI spinner](https://jqueryui.com/spinner/)\\n([api](https://api.jqueryui.com/spinner/))\\n - used in the [timespinner](#samples/tag-controls/jqui/timespinner) samples\\n- *__{{tabs/}}__* -- based on [jQuery UI tabs](https://jqueryui.com/tabs/)\\n([api](https://api.jqueryui.com/tabs/))\\n - used in the [tabs](#samples/tag-controls/jqui/tabs) samples\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"To use the above tag controls simply include the library after loading *jQuery UI* (recommended version *1.12.1* or later) and *JsViews*:\\n\\n```jsr\\n...\\n\\n\\n...\\n\\n\\n...\\n```\\n\\nIn addition, include an appropriate jQuery UI css class library, such as the default theme:\\n\\n```jsr\\n\\n```\\n\\nSee [jQuery UI widget controls samples](#samples/tag-controls/jqui).\\n\"\r\n }\r\n ]\r\n },\r\n \"download/jsrplugins\": {\r\n \"filter\": \"jsr\",\r\n \"title\": \"JsRender plugins\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsRender* can be extended by including external libraries of custom tags, converters, helpers etc. -- such as the *jsonview.js* library:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n\\n\\n...\\n```\"\r\n }\r\n ]\r\n },\r\n \"download/jsvplugins\": {\r\n \"filter\": \"jsv\",\r\n \"title\": \"JsViews plugins and tag controls\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsViews* can be extended by including external libraries of custom tag controls, converters, helpers, etc. -- such as the *[jQuery UI tag controls](#download/jqueryui-tagcontrols)* library (*jsviews-jqueryui-widgets.js*):\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n\\n\\n...\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"download/sample-tagcontrols\",\r\n \"label\": \"Sample tag controls\"\r\n },\r\n {\r\n \"hash\": \"download/jqueryui-tagcontrols\",\r\n \"label\": \"jQuery UI tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"typescript\": {\r\n \"title\": \"Typescript declaration files\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender and JsViews have TypeScript declaration files available:\\n\\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsrender/index.d.ts) for jsrender\\n- [*index.d.ts*](https://www.jsviews.com/download/typescript/jsviews/index.d.ts) for jsviews\\n\\nBoth will be published to [DefinitelyTyped](https://definitelytyped.org).\\n\\nNote that the JsViews declaration file depends on the JsRender declaration file (and both depend on the jQuery TypeScript declaration file). They include appropriate triple slash type references such as `/// ` \"\r\n }\r\n ]\r\n }\r\n};"]} \ No newline at end of file diff --git a/documentation/contents-getstarted.js b/documentation/contents-getstarted.js index cf83c2ac..0758e95c 100644 --- a/documentation/contents-getstarted.js +++ b/documentation/contents-getstarted.js @@ -441,12 +441,12 @@ content.getstarted = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "_type": "para", "title": "Using JsRender with jQuery", - "text": "When jQuery is present, JsRender loads as a jQuery plugin and adds `$.views`, `$.templates` and `$.render` to the jQuery namespace object, `$` (or `window.jQuery`).\n\n*Example HTML page:* [JsRender with jQuery](#download/pages-jsr-jq)\n" + "text": "When jQuery is present, JsRender loads as a jQuery plugin and adds `$.views`, `$.templates` and `$.render` to the jQuery global namespace object, `$` (or `jQuery`).\n\n*Example HTML page:* [JsRender with jQuery](#download/pages-jsr-jq)\n" }, { "_type": "para", "title": "JsRender without jQuery", - "text": "When jQuery is not present, JsRender provides its own `jsrender` namespace object, exposed as `window.jsrender`\n\nThe `jsrender` namespace provides the same methods/APIs as with jQuery, so if jQuery is not present you can still use all the API examples, by simply writing:\n\n```js\nvar $ = window.jsrender;\n\n// Now use code as in samples/examples, with $.views... $.templates... $.render...\n```\n\n*Example HTML page:* [JsRender without jQuery](#download/pages-jsr)\n\n
\n## JsRender usage" + "text": "When jQuery is not present, JsRender provides its own `jsrender` global namespace object, `jsrender` (or `window.jsrender`)\n\nThe `jsrender` namespace provides the same methods/APIs as with jQuery, so if jQuery is not present you can still use all the API examples, by simply writing:\n\n```js\nvar $ = jsrender;\n\n// Now use code as in samples/examples, with $.views... $.templates... $.render...\n```\n\n*Example HTML page:* [JsRender without jQuery](#download/pages-jsr)\n\n**Learn more:** *[JsRender without jQuery](#nojqueryapi)*\n\n
\n## JsRender usage" }, { "_type": "para", @@ -471,7 +471,7 @@ content.getstarted = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "_type": "para", "title": "Template tag syntax", - "text": "- All tags other than [`{{: ...}}`](#assigntag) [`{{> ...}}`](#htmltag) [`{{* ...}}`](#allowcodetag) [`{{!-- --}}`](#commenttag) behave as block tags

\n- Block tags can have content, unless they use the self-closing syntax:\n - Block tag -- with content: `{{sometag ...}} content {{/sometag}}`\n - Self-closing tag -- no content (empty): `{{sometag .../}}`

\n- A particular case where self-closing syntax is used is when a block tag uses the named parameter `tmpl=...` to reference an external template – which then replaces what would have been the block content:\n - Self-closing block tag referencing an external template: `{{sometag ... tmpl=.../}}`
(This lets you do [template composition](#tagsyntax@composition). See [example](#samples/jsr/composition/tmpl).)

\n- Tags can take both unnamed arguments and named parameters:\n - `{{sometag argument1 param1=...}} content {{/sometag}}`\n - an example of a named parameter is the `tmpl=...` parameter mentioned above\n - arguments and named parameters can be assigned values from simple data-paths such as `address.street` or from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\n\n[Learn more...](#tagsyntax)\n\n
Built-in tags
" + "text": "- All tags other than [`{{: ...}}`](#assigntag) [`{{> ...}}`](#htmltag) [`{{* ...}}`](#allowcodetag) [`{{!-- --}}`](#commenttag) behave as block tags

\n- Block tags can have content, unless they use the self-closing syntax:\n - Block tag -- with content: `{{sometag ...}} content {{/sometag}}`\n - Self-closing tag -- no content (empty): `{{sometag .../}}`

\n- A particular case where self-closing syntax is used is when a block tag uses the named property `tmpl=...` to reference an external template – which then replaces what would have been the block content:\n - Self-closing block tag referencing an external template: `{{sometag ... tmpl=.../}}`
(This lets you do [template composition](#tagsyntax@composition). See [example](#samples/jsr/composition/tmpl).)

\n- Tags can take both unnamed arguments and named properties:\n - `{{sometag argument1 param1=...}} content {{/sometag}}`\n - an example of a named property is the `tmpl=...` property mentioned above\n - arguments and named properties can be assigned values from simple data-paths such as `address.street` or from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\n\n[Learn more...](#tagsyntax)\n\n
Built-in tags
" }, { "_type": "para", @@ -540,7 +540,7 @@ content.getstarted = content.useStorage && $.parseJSON(localStorage.getItem("JsV { "_type": "para", "title": "Logic and expressions", - "text": "JsRender supports rich expressions and logic, but at the same time encapsulates templates to prevent random access to globals. If you want to provide access to global variables within a template, you have to pass them in as data or as helpers.\n\nYou can assign rich expressions to any template arguments or parameters, as in:\n\n`{{:person.nickname ? \"Nickname: \" + person.nickname : \"(has no nickname)\"}}`\n\nor\n\n```jsr\n{{if ~limits.maxVal > (product.price*100 - discount)/rate}}\n ...\n{{else ~limits.minVal < product.price}}\n ... \n{{else}}\n ... \n{{/if}}\n```", + "text": "JsRender supports rich expressions and logic, but at the same time encapsulates templates to prevent random access to globals. If you want to provide access to global variables within a template, you have to pass them in as data or as helpers.\n\nYou can assign rich expressions to any template arguments or properties, as in:\n\n`{{:person.nickname ? \"Nickname: \" + person.nickname : \"(has no nickname)\"}}`\n\nor\n\n```jsr\n{{if ~limits.maxVal > (product.price*100 - discount)/rate}}\n ...\n{{else ~limits.minVal < product.price}}\n ... \n{{else}}\n ... \n{{/if}}\n```", "anchor": "logic" }, { diff --git a/documentation/contents-getstarted.min.js b/documentation/contents-getstarted.min.js index 83bee63b..c7df2e74 100644 --- a/documentation/contents-getstarted.min.js +++ b/documentation/contents-getstarted.min.js @@ -1,3 +1,3 @@ -var content=$.views.documentation.content;content.getstarted=content.useStorage&&$.parseJSON(localStorage.getItem("JsViewsDocTopics/getstarted"))||{getstarted:{title:"Getting started",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"jsrplaying",label:"Playing with JsRender"},{hash:"jsr-quickstart",label:"JsRender Quickstart"},{hash:"jsr-node-quickstart",label:"JsRender Node.js Quickstart"},{hash:"jsvplaying",label:"Playing with JsViews"},{hash:"jsv-quickstart",label:"JsViews Quickstart"}]},{_type:"links",title:"Other links:",links:[],topics:[{_type:"topic",hash:"jsrapi",label:"JsRender API - Templated UI"},{_type:"topic",hash:"jsvapi",label:"JsViews API - Data-driven UI"},{_type:"topic",hash:"jsoapi",label:"JsObservable API - Observing data"},{_type:"topic",hash:"samples",label:"Samples"}]}]},jsrplaying:{filter:"jsr",path:"",title:"Playing with JsRender",sections:[{_type:"para",title:"",text:"(***See also:*** [JsRender Quickstart](#jsr-quickstart))"},{_type:"para",title:"JsRender templates",text:"JsRender templates are probably the most powerful and at the same time the most intuitive of template engines out there.\n\nTo get started, let's just create a template, and run it against some data. The way you do that in code is like this:"},{_type:"template",title:"Here's a template:",markup:" {{:name}}"},{_type:"code",title:"Here's some code:",code:'var person = {\n name: "Adriana"\n};\n\nvar html = myTemplate.render(person);'},{_type:"para",title:"And here it is as a working sample:",text:"Let's go straight to a sample showing how that template renders against the data. Like all the samples in this documentation, it is a working sample that you can experiment with. \n",anchor:""},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'You can hit Try it, modify the template or the data, then hit Run Code to see the effect immediately in the running sample above.\n\nFor example, replace the data with the following:\n\n```json\n[\n {\n "name": "Adriana"\n },\n {\n "name": "Robert"\n }\n]\n```\n\nOr try replacing the template with the following:\n\n```jsr\n\n \n \n
Name{{:name}}
\n```'}],title:"A first template:",markup:" {{:name}}",data:{name:"Adriana"},height:"60",onlyJsRender:!0,anchor:""},{_type:"para",title:"",text:"OK -- a few interesting things there. For example, if you tried changing the data, and provided an array instead of an object, you will have seen that the template rendered once for each item in the array.\n\nBut before we look at more details on the template rendering, let's look at how you get a compiled template object for your markup (the `myTemplate` object in the code example above) so you can call the render method.\n\nThe next working example shows you that."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'Take a look at the Code, Full Code or Try It tabs.\n\nIn the html you see that we put our markup in a script block with `type="text/x-jsrender"`...\n\n```jsr\n\n```\n\n... and then in the code we call the `$.templates()` method with a jQuery selector for that script block, to get the compiled template.\n\n```js\nvar myTemplate = $.templates("#personTmpl");\n```\n\nAfter that we run the code we have already seen to render the template against our data, and get the HTML output as a string. (We pass the data -- this time we used an array -- to the `render()` method of our compiled template.)\n\n\n```js\nvar html = myTemplate.render(people);\n```\n\nFinally we simply insert that output into the HTML DOM using the jQuery `html()` method.\n\nAgain, you can play with the sample in the Try it tab, by changing the data, or the markup, or the code.\n\nFor example if you change the template to produce a ``, you will want to insert the output into the `tbody` of a `table`, by adding a `` target container -- as in the following:\n\n```jsr\n
\n\n\n```'}],html:'
\n\n',code:'var myTemplate = $.templates("#personTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];\n\nvar html = myTemplate.render(people);\n\n$("#peopleList").html(html);',title:"Complete code for template rendering:",onlyJsRender:!0,height:"80"},{_type:"para",title:"What else is in templates?",text:"JsRender template have a very rich feature-set, yet a small number of predefined tags. The links at the bottom of this topic give details on some of the features.\n\n But let's try one more sample, where this time, instead of passing our `people` array to the `template.render()` method, we will pass an object (our `app` object) which will have a `people` property. Now in the template we will use a `{{for}}` tag to iterate over the `people`. \n\nAlso we'll use an `{{if}}` tag to test whether the `person` has a `nickname` field, and if so we will render out the nickname too..."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:"The `{{for people}}...{{/for}}` block tag, in the template, looks at the current data item (the `app` that we passed in) and navigates a data-path that you provide as parameter -- in this case `people`.\n\nJsRender supports different kinds of paths, as well as expressions of various kinds. The data-path can be something like `address.street`, with 'dot' separators, but in this case it is simply the `people` property of the `app` object.\n\nNow, because `people` is an array, JsRender will render the content of the `{{for}}...{{/for}}` block once for each item in the array.\n\nWithin the block the current item is now the `person`(item in the `people` array), and there we have an `{{if nickname}}...{{/if}}` block tag, which takes an expression as parameter.\n\nIn this case the expression is another data-path, `nickname`. So it renders the content of the `{{if}}...{{/if}}` block if the `nickname` is not `undefined` (or is not `null`, or the empty string).\n\nYou can experiment by replacing the `{{if nickname}}` expression. For example, try giving Adriana the nickname Adriana! Then try replacing `{{if nickname}}` with:\n\n```jsr\n{{if nickname && nickname !== name}} \n```"}],html:'
\n\n',code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert",\n nickname: "Bob"\n }\n ];\n\n app = {\n people: people\n };\n\nvar html = myTemplate.render(app);\n\n$("#peopleList").html(html);\n',onlyJsRender:!0,title:"Some template tags...",height:"110"},{_type:"para",title:"Next:",text:"[JsRender Quickstart](#jsr-quickstart)"},{_type:"links",title:"Links:",links:[],topics:[{_type:"topic",hash:"jsrtags",label:"Built-in template tags"},{_type:"topic",hash:"jsrapi",label:"JsRender API"},{_type:"topic",hash:"samples/jsr",label:"JsRender samples"}]}]},jsvplaying:{filter:"jsv",title:"Playing with JsViews",path:"",sections:[{_type:"para",title:"",text:"(***See also:*** *[JsViews Quickstart](#jsv-quickstart)*)"},{_type:"para",title:"JsViews: A platform for data-bound single-page apps",text:'JsViews provides dynamic data-bound views, built on top of JsRender templates. It "brings JsRender templates to life". So let\'s start with the JsRender template we ended up with in the *[Playing with JsRender](#jsrplaying)* topic:'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'If you look at the code you will see it is almost identical to the previous JsRender sample. One difference though: the two lines for rendering the template as a string and then inserting it into the DOM:\n\n```js\nvar html = myTemplate.render(app);\n\n$("#peopleList").html(html);\n```\n\n...have been replaced by a single line:\n\n```js\nmyTemplate.link("#peopleList", app);\n```\n\nThat line of code actually does three things:\n\n- First it renders the template against the data (second parameter)\n- Next, it inserts the resulting HTML under the container element (first parameter)\n- Finally, it *data-binds the HTML* against the data'}],url:"",html:'
\n\n\n',code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar app = {\n people: people\n };\n\nmyTemplate.link("#peopleList", app);',height:"110",title:"Using the template.link() method"},{_type:"para",title:"Data-linking",text:'In JsViews we refer to *data-linking*. It means data-binding, but refers to the particular approach used in JsViews, which is based on *observable objects and arrays*.\n\nIf you take an object and assign a new value to one of its properties (fields), there is no corresponding event that can allow other code to know you modified the object. Similarly, mutating an array will not provide any events or notifications to other code.\n\nThat\'s where *JsObservable* comes in. It provides ways of changing objects and arrays, *observably*.\n\nThe next sample shows what happens when the template renders against an array, and then that array is modified \'observably\' (*observable collection change*).\n\n```js\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name"});\n});\n```'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:"Click on the Add button, and a new row gets added to the array. The template rendering automatically updates to show the new row.\n\nIt uses the code:\n\n```js\n$.observable(people).insert({name: \"name\"});\n```\n\nBut notice that the template is different from previously. It has that extra carat sign: `{^{for ...}}`. Try removing the `^` and then clicking the Add button. -- Nothing happens.\n\nAny regular JsRender tag `{{sometag ...}}` -- whether built-in or custom -- can be data-linked by adding the `^`: `{^{sometag ...}}`. That tag has become 'dynamic' and will re-render itself whenever it needs to, if the underlying data changes ('observably').\n\nRemove the `^`, and the tag is 'dead'..."}],html:'
\n\n',code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar app = {\n people: people\n };\n\nmyTemplate.link("#peopleList", app);\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name"});\n});',height:"206",title:"Data-linked tags and observable arrays and objects "},{_type:"para",title:"",text:"What about changing an object? Let's modify the `name` on a `person` object (*observable property change*):"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:"Here is the code when you click Change:\n\n```js\nfunction() {\n var dataItem = $.view(this).data;\n\n $.observable(dataItem).setProperty(\"name\", dataItem.name + counter++);\n}\n```\n\nThe code for `setProperty` should make sense, given what we have already seen. You call `$.observable(myObject)` to get an 'observable form of your object' which will provide you with appropriate methods you can call: `setProperty(...)` if it was an object, and `insert`, `remove`, `refresh` and `move`, if it was an array. \n\nBut in our case, the first problem is to know which `person` object should be modified by this particular button. The `this` pointer in the click-handler is the element, and our code:\n\n```js\nvar dataItem = $.view(this).data;\n```\n\n-- let's us get the `view` (an 'instance' of a rendered template, or template tag block) and hence to the data item (in this case the `person`) we want to modify.\n\nAs in the previous sample, we have 'brought a tag to life' by writing:\n\n```jsr\n{^{:name}}\n```\n\nChange it back to:\n\n```jsr\n{{:name}}\n```\n\nand you will see that the name no longer updates when you click on the Change button."}],html:'
\n\n',height:"206",code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar app = {\n people: people\n };\n\nvar counter = 1;\n\nmyTemplate.link("#peopleList", app);\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name"});\n});\n\n$("#peopleList").on("click", ".changeBtn", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", dataItem.name + counter++);\n});\n',title:"Observable change: setProperty",anchor:"setprop"},{_type:"para",title:"Data-linked tags...",text:"So far we have used data-linked template tags for data-linking, as in:\n\n```jsr\n{^{:name}}\n```\n\nBut the fact that the data-linked tag is wrapped by an HTML element means that if we want we can replace it by an 'element-based' syntax:"},{_type:"template",title:"...or element-based data-linking",markup:''},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'So this version of the sample uses:\n\n```jsr\n\n```\n\nTry changing it back to the data-linked tag syntax, with `{^{`. You will see that the sample works just the same...'}],html:'
\n\n',code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar app = {\n people: people\n };\n\nvar counter = 1;\n\nmyTemplate.link("#peopleList", app);\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name"});\n});\n\n$("#peopleList").on("click", ".changeBtn", function() {\n var dataItem = $.view(this).data;\n $.observable(dataItem).setProperty("name", dataItem.name + counter++);\n});\n',height:"206",title:'Element-based linking: "data-link"'},{_type:"para",title:"",text:"But what about *two-way* data-binding?"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'This is where the element-based data-linking comes into its own. The textbox uses declarative binding:\n\n```jsr\n\n\n \n\n```\n\nThe `` and the `` are both data-linked. The underlying data gets modified when you change the name in the textbox -- and updates the ``, without you needing to write any propertyChange code at all.'}],title:"Two-way data-binding",html:'
\n\n',code:'var myTemplate = $.templates("#peopleTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n ];\n\nvar app = {\n people: people\n };\n\nvar counter = 1;\n\nmyTemplate.link("#peopleList", app);\n\n$("#addBtn").on("click", function() {\n $.observable(people).insert({name: "name"});\n});\n',height:"206",anchor:"twoway"},{_type:"para",title:"A more complete sample:",text:"This was just a glimpse of some of the richness of JsViews data-linking. The next sample lets you see a more fully-fledged example, which you can experiment with.\n\nFor more details on JsViews features and APIs see the *Links* section below."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'This sample includes binding to `\n```\n\nAnd also to each `
block, {{* } }} into the template code:\n\n```jsr\n {{* } }}\n```\n\n'}],jsrJsvJqui:"jsr",height:"110",code:'var data = {\n title: "My list",\n list: [2, 10.3, 77, -44, -5.5]\n };\n\nvar tmpl = $.templates({\n markup: "#myTemplate",\n allowCode: true\n });\n \nvar html = tmpl.render(data);\n\n$("#result").html(html);',html:'\n\n
',title:"allowCode for template",anchor:"tmpl"}]},customtagsapi:{title:"Custom tags",path:"",sections:[{_type:"para",title:"Defining custom tags",text:"JsRender deliberately has only a small number of built-in tags -- each of which is very flexible and useful. This is intended to reduce the 'learning curve'. And at the same time JsRender makes it very easy to create your own custom tags:"},{_type:"links",title:"See:",links:[],topics:[{_type:"topic",hash:"tags",label:"Using custom tags"},{_type:"topic",hash:"tagsapi",label:"Registering custom tags: $.view.tags()"},{_type:"topic",hash:"samples/jsr/tags",label:"Samples: JsRender custom tags"}]}]},rendertmpl:{title:"Render a template",path:"",sections:[{_type:"para",title:"",text:'A template is rendered by calling the `render()` method.\n\nThe `render(data, helpersOrContext)` method takes as parameters the data (used as the \'data context\' during the rendering), and optionally additional metadata or contextual helpers. It returns a string -- which is the rendered template -- typically HTML markup with data values or computed values inserted at appropriate points in the string.\n\nThere are three ways of calling the `render()` method:\n- If you have a reference to the template object -- `myTmpl`, call [myTmpl.render(...)](#tmplrender)\n- If you have registered the template by name -- `"myTmpl"`, call [$.render.myTmpl(...)](#d.render)\n- If the template is declared in a script block, with selector `"#myTmpl"`, you can also call [$("#myTmpl").render(...)](#db.render)'},{_type:"links",title:"See:",links:[],topics:[{hash:"tmplrender",label:"myTmpl.render()"},{hash:"d.render",label:"$.render.myTmpl()"},{hash:"db.render",label:'$("#myTmpl").render()'}]}]},tmplrender:{title:"Render a template against data objects or arrays",path:"",sections:[{_type:"para",title:"myTmpl.render()",text:"If `myTmpl` is the compiled template object for your template, you can render it using the `myTmpl.render()` method -- which takes a data object or array (as well as an optional helpersOrContext object), and returns the rendered template as a string.\n\nThere is also a shortcut version of the `render()` method: you can call the template object itself as a function: `var html = myTmpl(data)` -- which is equivalent to `var html = myTmpl.render(data)`.\n\nTo get a template object from a template string, a template declared in a script block, or a previously registered *named template*, see [`$.templates()`](#d.templates)."},{_type:"api",typeLabel:"API:",title:"template.render(data)",name:"render",object:"template",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."}],sections:[],example:"var html = myTmpl.render(myData);",description:"Render template against data"}],description:"Render a template against data, and return a string.",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Passing an object to the `render()` method.\n\n*--- The template is rendered once, with the object as data context:*"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"code",title:"",code:'var myTmpl = $.templates("#personTmpl");\n\nvar html = myTmpl.render(person);'}],html:'
\n\n',code:'var myTmpl = $.templates("#personTmpl");\n\nvar person = {\n name: "Adriana"\n };\n\nvar html = myTmpl.render(person);\n\n$("#person").html(html);',title:"template.render(object):",jsrJsvJqui:"jsr",height:"50"},{_type:"para",title:"",text:"Passing an array to the `render()` method.\n\n*--- The template is rendered once for each item in the array:*"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"code",title:"",code:"var html = myTmpl.render(people);"}],html:'
\n\n',code:'var myTmpl = $.templates("#personTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];\n\nvar html = myTmpl.render(people);\n\n$("#peopleList").html(html);',title:"template.render(array):",jsrJsvJqui:"jsr",height:"74"},{_type:"para",title:"",text:"Passing helpers to the `render()` method."},{_type:"api",typeLabel:"API:",title:"template.render(data, helpersOrContext)",name:"render",object:"template",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"}],sections:[],example:"var html = myTmpl.render(myData, myHelpers);",description:"Render template against data, and pass in helpers"}],description:"Render a template against data, along with helper objects or context, and return a string",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:"helpers"},{_type:"para",title:"",text:"You can pass in any JavaScript type (object, string, number, function...) as helpers on the `helpersOrContext` object, and use them as metadata, or as helper functions for formatting etc.\n\nNote: By passing in helpers in this way, you are making them specific to this render call. Alternatively, you can declare helpers globally, -- and you can also declare helpers that are private to a specific template. See *[Registering helpers: `$.views.helpers()`](#helpers)* for details...\n\nWithin the template, helpers (whether global, or passed in to the `render()` method) are accessed by *helper paths*: `~keyName`. \n\nFor example you might pass in an object with some utility functions:\n\n```js\nvar myHelpers = {\n util: {\n split: function(val, part) {...},\n ...\n },\n ...\n};\n\nvar html = myTmpl.render(myData, myHelpers);\n```\n\n-- and access them in the template using a *helper path* such as:\n\n```jsr\n{{:~util.split(fullName, 0)}}\n```\n\nSee *[Registering helpers](#helpers)*." -},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nfunction toUpper(val) {...}\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = myTmpl.render(person, myHelpers);\n```\n\n```jsr\n\n {{:~format(name)}}\n\n```\n\nClick Try it and change the color to "green"...'}],html:'
\n\n',code:'function toUpper(val) { return val.toUpperCase(); }\n\nvar myTmpl = $.templates("#personTemplate");\n\nvar person = {\n name: "Adriana"\n };\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = myTmpl.render(person, myHelpers);\n\n$("#person").html(html);',title:"template.render(object, myHelpers):",height:"52",jsrJsvJqui:"jsr"},{_type:"para",title:"Passing an array to render(), but without iteration.",text:"When rendering an array, an additional optional boolean parameter, `true`, can be passed to the `render()` method, in order to prevent iteration.\n"},{_type:"api",typeLabel:"API:",title:"template.render(data, helpersOrContext, noIteration)",name:"render",object:"template",method:!0,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],args:[],sections:[],example:"var html = myTmpl.render(data, helpers, true);",description:"Render template against data, pass in helpers, and specify iteration behavior"}],description:"Render a template against data, along with helpers/context (and determine iteration behavior with array data). Return a string. ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:"noiteration"},{_type:"para",title:"",text:"By passing in `true` as the third *'noIteration'* parameter (or as second parameter if no `helpersOrContext` are passed), the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\n\nWithin the template, `{{for}}` (or equivalently `{{for #data}}`) can be used to iterate over the array, as in the following example:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"Code:\n\n```js\nvar html = myTmpl.render(people, true);\n```\n\nTemplate:\n\n```jsr\n\n \n \n {{for}}\n \n {{/for}}\n \n
\n {{:#data.length}} people\n
\n {{:name}}\n
\n```"}],jsrJsvJqui:"jsr",height:"110",html:'
\n\n',code:'var myTmpl = $.templates("#personTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];\n\nvar html = myTmpl.render(people, true);\n\n$("#peopleList").html(html);',title:"template.render(array, helpers, noIteration):"},{_type:"para",title:"Alternative compact syntax for render() call",text:"The compiled template is in fact *itself a function*, equivalent to its own `render()` method. \n\nThis means that any `render()` call can be replaced by an equivalent (but more compact) syntax, as shown in the following example:\n\n```js\nvar html = myTmpl(people, helpers, true);"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},"d.render":{title:"Render a named template without needing the template object",path:"",sections:[{_type:"para",title:"$.render.myTmpl()",text:'If a template has been [registered](#d.templates) as a named template:\n\n```js\n$.templates("myTmpl", "#personTmpl");\n```\n\nor\n\n```js\n$.templates("myTmpl", "some markup string");\n```\n\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates).\n\nJust call `$.render.myTmpl(...)`, or `$.render["myTmpl"](...)`\n\n(**Note:** there is also an alternative syntax for rendering a named template: `$.templates.myTmpl(...);`)\n'},{_type:"api",typeLabel:"API:",title:"$.render.myTmpl(data, helpersOrContext, noIteration)",name:"myTmpl",object:"$.render",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],sections:[],example:"var html = $.render.myTmpl(data, helpers, true);",description:"Render template against data. Optionally pass in helpers and specify iteration behavior."}],description:"Render a template against data. Return a string.
(Optionally provide helpers/context, and specify iteration behavior). ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", "#personTemplate");\n\nvar html = $.render.personTmpl(person);'}],html:'
\n\n',code:'function toUpper(val) { return val.toUpperCase(); }\n\n$.templates("personTmpl", "#personTemplate");\n\nvar person = {\n name: "Adriana"\n };\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = $.render.personTmpl(person, myHelpers);\n\n$("#person").html(html);',title:"$.render.personTmpl(...):",height:"50",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},"db.render":{title:"jQuery instance method to render a template declared in a script block",path:"",sections:[{_type:"para",title:'$("#myTmpl").render()',text:'If a template has been [registered](#d.templates) using a script block:\n\n```jsr\n\n```\n\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates), and without registering a named template.\n\nJust call `$("#myTmpl").render(...)`'},{_type:"api",typeLabel:"API:",title:"$(tmplSelector).render(data, helpersOrContext, noIteration)",name:"render",object:"$(tmplSelector)",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],sections:[],example:'var html = $("#myTmpl").render(myData, myHelpers, true);',description:"Render template against data. Optionally pass in helpers and specify iteration behavior."}],description:"Render a template against data. Return a string.
(Optionally provide helpers/context, and specify iteration behavior). ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\nvar html = $("#personTemplate").render(person);\n```'}],html:'
\n\n',code:'var person = {\n name: "Adriana"\n };\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',title:'$("#personTemplate").render(...):',height:"50",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},compiletmpl:{title:"Using templates",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering templates](#d.templates): The `$.views.templates()` API*.)"},{_type:"para",title:"Defining templates",text:"To define a template you need to provide the markup for the template. JsRender will convert (compile) the markup into a JavaScript function -- the 'render' function for your template. In fact for convenience, JsRender creates a *template object* which has a [`template.render()`](#rendertmpl) method which is the compiled function.\n\nThere are two ways to create a template:\n\n- Pass the markup string to the [`$.templates()`](#d.templates) method\n- Declare the template in a script block with `type=\"text/x-jsrender\"` (or at least a type other than the default `text/javascript`), then pass the jQuery selector for the script block to the [`$.templates()`](#d.templates) method\n\nIn either case, the `$.templates()` method will compile a template object, and optionally register it by name.\n\nHere is an example of the first approach:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'We pass our markup string to the [`$.templates()`](#d.templates) method:\n\n```jsr\nvar myTmpl = $.templates(" {{:name}} ");\n```\n\nthen call the [`render()`](#rendertmpl) method on the returned template object:\n\n```js\nvar html = myTmpl.render(people);\n```'}],height:"40",jsrJsvJqui:"jsr",html:'
',code:'var myTmpl = $.templates(" {{:name}} ");\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];\n\nvar html = myTmpl.render(people);\n\n$("#peopleList").html(html);',title:"Registering a template from a template markup string:"},{_type:"para",title:"",text:"And here is an example of the second:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'This time we put our markup in a script block with `type="text/x-jsrender"`\n\n```jsr\n\n```\n\nand then in the code we call the [`$.templates()`](#d.templates) method with a jQuery selector for that script block: \n\n```jsr\nvar myTmpl = $.templates(" {{:name}} ");\n```\n\nThen as before we call the [`render()`](#rendertmpl) method on the returned template object:\n\n```js\nvar html = myTmpl.render(people);\n```'}],html:'
\n\n',code:'var myTmpl = $.templates("#personTemplate");\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];\n\nvar html =myTmpl.render(people);\n\n$("#peopleList").html(html);',title:"Registering a template declared in script block:",jsrJsvJqui:"jsr",height:"40"},{_type:"para",title:"",text:"The first approach above has the advantage of keeping your template declaration independent of the HTML markup that you are loading into the browser. Indeed you may want to provide the template markup strings for your templates in different application-specific ways, such as loading the string from the server (using a script file or text or html file), creating 'computed' template markup strings on the fly, etc.\n"},{_type:"para",title:"Example of fetching the markup string from the server",text:'Here is a simple example of fetching the markup string from the server. We load a `.../person.js` file from the server which registers a named `"person"` template.'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'We load the *person.js* script from the server, which registers a named `"person"` template:\n\n```js\n$.templates("person", " {{:name}} ");\n```\n\nAs soon as the script is loaded, we call the [`render(...)`](#d.render) method for the registered template:\n\n```js\n$.getScript(".../person.js", function() {\n var html = $.render.person(people);\n $("#peopleList").html(html);\n });\n```\n\n*Note:* For a more sophisticated example of lazy loading of scripts for registering templates, see the [remote templates](#samples/jsr/composition/remote-tmpl) sample.'}],markup:"\n",data:{},code:'$.getScript("//www.jsviews.com/samples/resources/templates/person.js", function() {\n var html = $.render.person(people);\n $("#peopleList").html(html);\n });\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];',html:'
',jsrJsvJqui:"jsr",height:"40",title:"Fetching a script file from the server, which registers a named template from a string",codetabs:[{_type:"codetab",name:"",url:"samples/resources/templates/person.js",label:"person.js"}]},{_type:"para",title:"",text:"And here is a variant of the same sample, where we fetch a text file containing the template markup:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'The markup string is fetched in an AJAX request (the *person.txt* file).\n\n```jsr\n {{:name}}\n```\n\nAs soon as the request returns, we use the markup string to compile the `personTemplate` object. This time we will not register it as a *named template*, but instead directly call the [`render(...)`](#tmplrender) method of the returned `personTemplate` object:\n\n```js\n$.get("...person.txt", function(value) {\n personTemplate = $.templates(value);\n var html = personTemplate.render(people);\n $("#peopleList").html(html);\n});\n```'}],html:'
\n',code:'var personTemplate;\n\n$.get("resources/templates/person.txt", function(value) {\n personTemplate = $.templates(value);\n var html = personTemplate.render(people);\n $("#peopleList").html(html);\n});\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];',title:"Registering a named template using markup fetched from the server in a text file",jsrJsvJqui:"jsr",height:"40",codetabs:[{_type:"codetab",name:"",url:"samples/resources/templates/person.txt",label:"person.txt"}]},{_type:"para",title:"",text:"And here is the second approach:"},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering templates](#d.templates): The `$.views.templates()` API"},{_type:"links",title:"See also:",links:[],topics:[{hash:"rendertmpl",label:"Render a template"},{_type:"topic",hash:"samples/jsr/composition/sub-tmpl",label:"Sample: sub-templates"}]}]},"d.templates":{title:"Registering templates: $.templates()",path:"",sections:[{_type:"para",title:"",text:"`$.templates()` is used to register or compile templates. See *[Using templates](#compiletmpl)* for an overview, and simple examples.\n\nThis topic provides more details."},{_type:"para",title:"Simple scenarios",text:"`$.templates(...)` is powerful and flexible. You can use it for many scenarios, including the following:\n- Compile a template from a string\n- Get a template object for a template declared in a script block\n- Register a template (from either a string or a script block declaration) as a *named template*\n- Get a template object for a previously registered *named template*\n- On Node.js: Get a template object for a template declared as a file on the file-system (see *[File-based templates on Node.js](#node/filetmpls)*).",anchor:"$.templates"},{_type:"api",typeLabel:"API:",title:"$.templates(...)",name:"templates",object:"$",method:!0,tag:!1,returns:"Compiled template object",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"markupOrSelector",type:"string",optional:!1,description:"A markup string or a selector for a template declaration script block"}],sections:[],example:"var myTemplate = $.templates(myMarkupString);",description:"Compile a template from a string or selector, and return the template object"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered template"},{_type:"param",name:"markupOrSelector",type:"string",optional:!1,description:"A markup string or a selector for a template declaration script block"}],args:[],sections:[],example:'$.templates("myTemplateName", myMarkupString);',description:"Register a named template from a string or selector"}],description:"Create one or more compiled templates – optionally registered as named templates",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:""},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"code",title:"",code:'var myTmpl = $.templates(" {{:name}}");\n\nvar html = myTmpl.render(person);\n'}],html:'
\n',code:'var myTmpl = $.templates(" {{:name}}");\n\nvar person = {name: "Robert"};\n\nvar html = myTmpl.render(person);\n\n$("#peopleList").html(html);',title:"Compile a template from a string",jsrJsvJqui:"jsr",height:"40",anchor:"tmpl-string"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\nvar myTmpl = $.templates("#personTemplate");\n\nvar html = myTmpl.render(person);\n```'}],title:"Get template object for script block template",html:'
\n\n',code:'var myTmpl = $.templates("#personTemplate");\n\nvar person = {name: "Robert"};\n\nvar html = myTmpl.render(person);\n\n$("#peopleList").html(html);',height:"40",jsrJsvJqui:"jsr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", " {{:name}}");\n\nvar html = $.render.personTmpl(person);\n'}],code:'$.templates("personTmpl", " {{:name}}");\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',html:'
',height:"40",title:"Register named template from a string",anchor:"namedfromstring",jsrJsvJqui:"jsr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", "#personTemplate");\n\nvar html = $.render.personTmpl(person);\n'}],code:'$.templates("personTmpl", "#personTemplate");\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',html:'
\n\n',title:"Register named template from script block",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Register multiple templates in one call",text:"You can register multiple named templates in one call to `$.templates()` as follows:"},{_type:"api",typeLabel:"API:",title:"$.templates(namedTemplates)",name:"",object:"",method:!1,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"namedTemplates",type:"object",optional:!1,description:"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)"}],args:[],sections:[],example:'$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: "<label>Name:</label>"\n});',description:"Register multiple named templates"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\n$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: ""\n});\n\nvar html = $.render.personTmpl(person);\n```'}],html:'
\n\n',code:'$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: ""\n});\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',title:"Registering multiple templates",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Get a template object for a named template",text:'You can get the template object for a previously registered *named template* as follows:\n\n```js\nvar myTemplate = $.templates.myTemplateName; // or $.templates["myTemplateName"]\n```'},{_type:"para",title:"Unregister a named template",text:'To unregister a previously registered named template, pass `null` to `$.templates()`:\n\n```js\n$.templates("myTemplateName", null);\n// Named template "myTemplateName" is no longer registered\n```'},{_type:"para",title:"Advanced scenarios: Associating private resources with templates",text:'$.templates() can also be used for the following more advanced scenarios:\n\n- Compile a template, (or multiple templates) along with specified resources to be available only within that template\n- Compile one or more templates to be added to the set of private resources of another (already compiled) template\n\nYou can use `$.templates()` to compile or register not only a template, but in addition some helpers, converters, custom tags or nested sub-templates, to be made available to the new template as private resources.\n\nNote that as an alternative you can register resources (helpers, converters, custom tags or templates) globally, using `$.views.helpers()`, `$.views.converters()`, `$.views.tags()`, or `$.templates()` -- rather than making them private to the template that needs to reference them.'},{_type:"api",typeLabel:"API:",title:"$.templates(...) — associating resources",name:"templates",object:"$",method:!0,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"templateOptions",type:"object",optional:!1,description:"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)"}],args:[],sections:[],example:'var myTmpl = $.templates({\n markup: "...",\n helpers: {...},\n tags: {...}\n ...\n});',description:"Compile a template, along with specified resources to be available only within this template"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered template"},{_type:"param",name:"templateOptions",type:"object",optional:!1,description:"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)"}],args:[],sections:[],example:'$.templates("myTmpl", {\n markup: "...",\n helpers: {...},\n tags: {...}\n ...\n});',description:"Register a named template, along with specified resources available only within that template"},{_type:"signature",title:"",params:[{_type:"param",name:"namedTemplates",type:"object",optional:!1,description:"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these template(s) are being added as private resources"}],args:[],sections:[],example:"$.templates(namedTemplates, parentTemplate);",description:"Register named templates as private resources for a 'parent template'"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:"resources"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'A converter and a helper are registered as private resources for the `personTmpl` named template.\n\n```js\n$.templates("personTmpl", {\n markup: "#personTemplate",\n converters: {\n upper: function(val) {return val.toUpperCase();}\n },\n helpers: {\n append: function(a, b) {return a + b;}\n }\n});\n```\n\nThey are accessed within the `personTmpl`\n\n```jsr\n\n```'}],html:'
\n\n',code:'// Register a template along with a converter and a helper that it will use.\n// These resources are private to the template, rather than being registered\n// globally using $.views.converters or $.views.helpers\n$.templates("personTmpl", {\n markup: "#personTemplate",\n converters: {\n upper: function(val) {return val.toUpperCase();}\n },\n helpers: {\n append: function(a, b) {return a + b;}\n }\n});\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',title:"Register a named template along with specified resources",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Adding templates as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.templates(...)`. In that way the template you are registering becomes a 'private template resource' for the `parentTemplate`.\n\nHere is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("labelTmpl", "", personTmpl);\n'}],code:'var personTmpl = $.templates("#personTemplate");\n\n$.templates("labelTmpl", "", personTmpl);\n\nvar person = {name: "Robert"};\n\nvar html = personTmpl.render(person);\n\n$("#peopleList").html(html);',html:'
\n\n',title:'Add a "labelTmpl" template resource as a \'sub template\' – a private resource for an existing "personTemplate"',height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Debug a template by including a debugger; statement",text:'As a technique for debugging compiled templates, you can temporarily set the template option `debug: true`:\n\n```js\n$.templates({\n myTmpl: {\n markup: "...",\n debug: true // This option will add a debugger; statement to the compiled template\n }\n});\n```\n\nThe result will be to include a `debugger;` statement at the beginning of the compiled template, which will behave as a breakpoint when debugging, and will facilitate understanding, or stepping through, the compiled template.\n'},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"compiletmpl",label:"Using templates"},{_type:"topic",hash:"samples/jsr/composition/sub-tmpl",label:"Sample: sub-templates"},{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},jsrregister:{title:"Register helpers, converters, tags...",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"converters",label:"$.views.converters()"},{hash:"tags",label:"$.views.tags()"},{hash:"helpers",label:"$.views.helpers()"}]}]},tags:{title:"Using custom tags",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering tags](#tagsapi): The `$.views.tags()` API*.)"},{_type:"para",title:"What is a custom tag?",text:"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\n\nA tag renders itself as part of the template output. You determine how it renders, generally by specifying either a function as *render()* method or a template, when you declare your custom tag.\n\nThe *render()* method, or the *template*, can access both unnamed arguments (*args*) and named parameters (*props*) and , [as in](#tagsyntax@tagparams):\n\n```jsr\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\n```\n\nIn fact it can also access the current data item -- or even the whole hierarchy of views and data...\n\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. "},{_type:"para",title:"Registering a custom tag",text:'To register a custom tag, you call [`$.views.tags(...)`](#tagsapi):\n```js\n$.views.tags("mytag", tagOptions)\n```\n\nYou provide a `tagOptions` object, whose properties will typically include a `render: tagRenderFn` (function to be used as *render()* method) and/or a `template: tagTemplate` (template to be rendered -- markup string, selector string or template object).\n\nFor the simple case where the *only* option you need to specify is a *render()* method, you can provide the function directly:\n\n```js\n$.views.tags("mytag", tagRenderFn);\n```\n\nOr if you *only* want to provide a template markup string, to show how it renders, you can again provide it directly:\n\n```js\n$.views.tags("mytag", tagTemplate);\n```\n\nHere is an example of a simple custom tag using just a function:'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Render method for the tag\nfunction renderBoldP(value) {\n return "

" + value + "

";\n}\n\n$.views.tags("boldp", renderBoldP); // Provide just a render method\n```\n\nAlternatively we could have written:\n\n```js\n$.views.tags("boldp", {\n render: renderBoldP); // Provide just a render method\n});\n```\n' -},{_type:"template",title:"Using the tag",markup:"This is the title:{{boldp title /}}"}],title:"A custom tag using just a render() method",html:'
\n\n',code:'// Render method for the tag\nfunction renderBoldP(value) {\n return "

" + value + "

";\n}\n\n$.views.tags("boldp", renderBoldP); // Provide just a render method\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"70",jsrJsvJqui:"jsr",anchor:"render-sample"},{_type:"para",title:"",text:"And here is the equivalent sample using just a template:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Template markup string for the tag\nvar tagTemplate = "

{{:}}

";\n\n$.views.tags("boldp", tagTemplate); // Provide just a template markup string\n```\n\nAlternatively we could have written:\n\n```js\n$.views.tags("boldp", {\n template: tagTemplate; // Provide just a template markup string\n});\n```'},{_type:"template",title:"Using the tag",markup:"This is the title:{{boldp title /}}"}],code:'// Template markup string for the tag\nvar tagTemplate = "

{{:}}

";\n\n$.views.tags("boldp", tagTemplate); // Provide just a template markup string\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',html:'
\n\n',title:"A custom tag using just a template",height:"70",jsrJsvJqui:"jsr",anchor:"template-sample"},{_type:"para",title:"Accessing unnamed arguments, named parameters, data, etc. within the render() method",text:'The `this` pointer within the tag *render()* method is the instance of the tag, and can be used to access parameters, data, view hierarchy, and more. Most of the useful context is provided via `this.tagCtx`. (See [tagCtx object](#tagcontextobject).)\n\nIn particular, unnamed arguments can be accessed via `tagCtx.args`, and named parameters via `tagCtx.props`.\n\nHere is tag with two arguments and one named parameter:\n\n```jsr\n{{sometag title name mode="edit"}}\n```\n\nFrom within the *render()* method of `sometag`, you can access `title` and `name` as `this.tagCtx.args[0]` and `this.tagCtx.args[1]`. And you can access mode as `this.tagCtx.props.mode`.\n\nIn addition to being accessible as `tagCtx.args`, unnamed arguments are also passed directly as arguments to the *render()* method (if your tag is using one):\n\n```js\nfunction sometagRenderMethod(title, name) {\n // Here, this.tagCtx.args[1] and the name argument are the same thing\n}\n```\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Render method for the tag\nfunction sometagRenderMethod(title, name) {\n var parentData = this.tagCtx.view.data;\n\n return\n "title: " ... title ... // Get argument passed to render method\n + "parentData.title: " ... this.tagCtx.view.data.title ... // Get title from parent context\n\n + "args[1]: " ... this.tagCtx.args[1] ... // Get argument from args[]\n + "mode: " ... this.tagCtx.props.mode; // Get named parameter from props\n}\n```'}],jsrJsvJqui:"jsr",html:'
\n\n',code:'// Render method for the tag\nfunction sometagRenderMethod(title, name) {\n var parentData = this.tagCtx.view.data;\n\n return "title: " + title + "
" // Get argument passed to render method\n + "parentData.title: " + this.tagCtx.view.data.title + "
" // Get title from parent context\n + "args[1]: " + this.tagCtx.args[1] + "
" // Get argument from args[]\n + "mode: " + this.tagCtx.props.mode; + ""// Get named parameter from props\n}\n\n$.views.tags("sometag", sometagRenderMethod); // Provide just a render method\n\nvar team = {\n title: "theTitle",\n name: "theName"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",title:"Accessing context within the render() method",action:"append",header:"",anchor:"context-sample"},{_type:"para",title:"Accessing arguments, named parameters, data, etc. from the tag template",text:"Within the template, the tag instance can be accessed as `~tag`, and so unnamed arguments and named parameters are obtained using `~tagCtx.args[...]` and `~tagCtx.props...`"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Template markup for the tag\nvar sometagTemplate =\n "title: {{:}}" // The data context within the tag is the first argument, title\n + "title (#data): {{:#data}}" // Equivalent unabbreviated syntax for current data\n + "parentData.title: {{:~tagCtx.view.data.title}}" // Get title from parent context\n\n + "args[1]: {{:~tagCtx.args[1]}}" // Get argument from args[]\n + "mode: {{:~tagCtx.props.mode}}"; // Get named parameter from props";\n```'}],html:'
\n\n',code:'// Template markup for the tag\nvar sometagTemplate =\n "title: {{:}}
" // The data context within the tag is the first argument, title\n + "title (#data): {{:#data}}
" // Equivalent unabbreviated syntax for current data\n + "parentData.title: {{:~tagCtx.view.data.title}}

" // Get title from parent context\n + "args[1]: {{:~tagCtx.args[1]}}
" // Get argument from args[]\n + "mode: {{:~tagCtx.props.mode}}"; // Get named parameter from props\n\n$.views.tags("sometag", sometagTemplate ); // Provide just a template markup string\n\nvar team = {\n title: "theTitle",\n name: "theName"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"124",header:"",action:"append",title:"Accessing context from the tag template",anchor:"tmplcontext-sample"},{_type:"para",title:"Accessing and rendering wrapped block content, in a custom tag",text:"A common requirement is to define a custom tag to be used as a block tag, which renders itself by wrapping the rendered block content with other markup.\n\nFor example, a `boldp` tag which wraps its content as: `

...

`:\n\n```jsr\n{{boldp}}\n This is inside our block content:
\n {{:title}}\n{{/boldp}}\n```\n\n**_Block content, using a render() method_**:\n\nIn a *render()* method, the block content can be included in the rendered output using:\n\n```js\n... this.tagCtx.render() ...\n```\n\n(For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See [template as fallback sample](#tags@tmpl-fallback) below) \n",anchor:"wrapping"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Tag render method:*\n\n```js\nfunction renderBoldP(val) {\n //To render the block content, we call this.tagCtx.render()\n return "

" + this.tagCtx.render() + "

";\n}\n```\n\n*Using the tag:*\n\n```jsr\nThis is outside our block content: ...\n{{boldp}}\n This is inside our block content: ...\n {{:title}}\n{{/boldp}}\n```'}],title:"Rendering block content from a custom tag render() method",html:'
\n\n',code:'function renderBoldP(val) {\n return "

" + this.tagCtx.render() + "

";\n}\n\n$.views.tags("boldp", renderBoldP); // User renderBoldP() as render method\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",jsrJsvJqui:"jsr",anchor:"renderblock-sample"},{_type:"para",title:"",text:"When using `tagCtx.render()` without arguments, the data context within the block content is the same as the data context outside our custom tag. However by passing an argument to `tagCtx.render(myData)` the inner data context can be moved to the chosen data. \n\nThe following sample shows a custom `{{runningTotal}}` tag which renders an array of `lineItems` (with a column for each property), and provides a running total of one of the columns.\n\nIt uses a *render()* method to access tag arguments and named parameters, and iterate over the `lineItems` array. It renders a row for each `lineItem`, using the code:\n\n```js\nret += this.tagCtx.render(lineItem, {total: totalVal});\n```\n\nHere, the row is rendered using the block content as template -- with the `lineItem` passed in as data context. The running total `totalVal` is provided as contextual helper: `~total`."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'You call the custom `{{runningTotal}}` tag like this:\n\n```jsr\n{{runningTotal lineItems totalColumn="quantity"}}\n ...{{:quantity}}\n ...{{:~total}}\n{{/runningTotal}}\n```\n\nAnd the *render()* method code accesses context (`this.tagCtx`) to get at the arguments and named parameters... :\n\n```js\n$.views.tags("runningTotal", function renderLineItems(array) {\n ...\n totalVal = 0; // Initialize ~total to 0 before rendering\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\n for (var i = 0; i < array.length; i++) {\n lineItem = array[i];\n totalVal += lineItem[totalCol]; // Compute running total\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content as\n // template. Pass lineItem as data and totalVal as helper: ~total\n }\n ...\n```'}],html:'
\n\n',code:'function renderLineItems(array) {\n var lineItem,\n ret = "",\n totalVal = 0, // Initialize ~total to 0 before rendering\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\n for (var i = 0; i < array.length; i++) { // Iterate over array and render a row for each lineItem \n lineItem = array[i];\n totalVal += lineItem[totalCol]; // Compute running total\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content\n // as template, and passing lineItem as current data and totalVal as helper: ~total\n }\n return ret;\n}\n\n$.views.tags("runningTotal", renderLineItems); // Use renderLineItems() as render method\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ]\n};\nvar html = $("#myTmpl").render(data);\n\n$("#lineItems").html(html);',jsrJsvJqui:"jsr",height:"152",title:"A {{runningTotal}} custom tag, using a render() method ",anchor:"runningtotal-sample",header:"",action:"append"},{_type:"para",title:"",text:"**_Block content, using a template_**:\n\nTo render block content declaratively within a custom tag template, use:\n\n```jsr\n{{include tmpl=#content/}}\n```\n\nor equivalently:\n\n```jsr\n{{include tmpl=~tagCtx.content/}}\n```\n\nHere is a modified [`{{boldp}}`](#tags@renderblock-sample) sample using a custom template instead of a *render()* method."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'To render block content, we use `{{include tmpl=#content/}}`\n\n```js\ntemplate: "

{{include tmpl=#content/}}

"\n```\n\n(The syntax `#content` is an example of a `view path` -- equivalent to `#view.content`.)\n\nThe `content` property on the `view` object is a compiled template for the block content, which is also available as the `content` property on the `tagCtx`.'}],html:'
\n\n',code:'$.views.tags("boldp", {\n template: "

{{include tmpl=#content/}}

"\n});\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",title:"Rendering block content from a custom tag template",jsrJsvJqui:"jsr",anchor:"tmplblock-sample"},{_type:"para",title:"",text:"Here, the default data context within the block content is the same as the data context outside our custom tag (as was the case in the [previous](#tags@renderblock-sample) `{{boldp}}` sample). However by providing an argument to the `{{include...}}`, as in `{{include myData tmpl=#content/}}`, the inner data context can be moved to the chosen data.\n\n(Note: To be precise, the default data in the two samples is different. When using `tagCtx.render()` the outer context is *outside our `{{boldp}}` tag*. Whereas when using `{{include}}`, it is *outside the `{{include}}` and within the `{{boldp}}` template*. If we provide an argument to the tag: '{{mytag someArgument}}...' then in custom tag template approach the passed-in argument value will be used as default data context.)\n"},{_type:"para",title:"",text:"For further details and examples of custom tags which wrap content, see [*Rendering wrapped block content*](#tagsapi@wrapping)"},{_type:"para",title:"Custom tags using both a render() method and a template",text:'If there is both a *template* and a *render()* method, then the *template* will only be used if the *render()* method returns *undefined*.\n\nLet\'s take our `{{runningTotal}}` example using a *render()* method, but provide a *template* which will be used as "fallback" rendering for the tag in the case when there are no items to render in the chosen range. We will also provide support for limiting the range of line items by setting `start=... end=...`:',anchor:"tmpl-fallback"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'First, in the *render()* method, we will change the original code to test whether the item exists in the array, before rendering the block content.\n\nSecondly, we will make sure that when there is an item we do render the block content and not the template. So we call `this.tagCtx.content.render(...)`, rather than `this.tagCtx.render(...)`.\n\nThat\'s because `this.tagCtx.render(...)` will actually look to see if there is template associated with the tag, (either a template on the tag definition, or a `tmpl` property on the tag) -- in which case it will render that template and not the block content... \n\n```js\nfor (var i=start; iNo line items"\n```'}],code:'$.views.tags("runningTotal", {\n render: function(array) {\n var lineItem,\n ret = "",\n totalVal = 0, // Initialize ~total to 0 before rendering\n props = this.tagCtx.props,\n totalCol = props.totalColumn; // The column/property to use for running total\n start = props.start,\n end = props.end;\n for (var i=start; iNo line items" // Template for fallback if no line items\n});\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ],\n lineItems2: []\n};\n\nvar html = $("#myTmpl").render(data, {\n category: function(item, index, items) {\n return item.category === this.props.category;\n }\n});\n\n$("#purchases").html(html);',html:'
\n\n',height:"244",jsrJsvJqui:"jsr",title:'A {{runningTotal}} custom tag, with render() method and a template as "fallback"',anchor:"renderplustmpl-sample",header:"",action:"append",url:""},{_type:"para",title:"",text:"In the above sample our feature for limiting the range of items by setting `start=... end=...` is basically identical to the corresponding feature available natively on the [`{{for}}`](#fortag@sortfilterrange) tag:\n\n```jsr\n{{for start=... end=...}}\n```\n\nIn fact we can add this feature to our `{{runningTotal}}` tag for free (along with providing sorting, filtering etc.) by making `{{runningTotal}}` derive from `{{for}}`, as `baseTag`. This will also simplify our code considerably. See [*Specifying tag inheritance*](#tagsapi@basetag) for details and an [updated](#tagsapi@derivedfor) `{{runningTotal}}` sample."},{_type:"para",title:"Custom tags and 'tag controls'",text:"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern."},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering tags](#tagsapi): The `$.views.tags()` API"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"samples/jsr/tags",label:"Samples: JsRender custom tags"},{_type:"topic",hash:"samples/tag-controls",label:"Samples: JsViews tag controls"},{_type:"topic",hash:"jsvtagcontrols",label:"JsViews tag controls"}]}]},jsrobjects:{title:"JsRender objects",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"viewsobject",label:"$.views object"},{hash:"templateobject",label:"template object"},{hash:"viewobject",label:"view object"},{hash:"tagobject",label:"tag object"},{hash:"viewcontextobject",label:"view context object"},{hash:"tagcontextobject",label:"tag context object"}]}]},viewsobject:{title:"The $.views object",path:"",sections:[{_type:"para",title:"",text:"The `$.views` object provides access to APIs for creating templates, tags, helpers etc.

\n\n\n- `$.views.templates(...)` -- available also as `$.templates(...)`\n
Used for defining templates -- see: [Registering templates](#d.templates)\n- `$.views.tags(...)`\n
Used for defining custom tags -- see: [Registering custom tags](#tagsapi)\n- `$.views.converters(...)`\n
Used for defining converters -- see: [Registering converters](#convertersapi)\n- `$.views.helpers(...)`\n
Used for defining helpers -- see: [Registering helpers](#helpersapi)\n- `$.views.viewModels(...)`\n
Used for defining View Models -- see: [Compiled View Models](#viewmodelsapi)\n\nIt also provides access to:

\n- `$.views.settings`\n
Used for modifying JsViews settings and options -- see: [Settings](#jsvsettings)\n- `$.views.map(...)`\n
Used for defining custom maps (advanced) \n- `$.views.jsviews`\n
Provides the version number of the currently loaded JsViews or JsRender library\n\n"}]},settingsobject:{title:"$.views.settings object",path:"",sections:[]},subobject:{title:"$.views.sub object",path:"",sections:[]},templateobject:{title:"The template object",path:"",sections:[{_type:"para",title:"",text:'The [`$.templates()`](#d.templates) API can be used to obtain a compiled template object:\n\n```js\nvar myTmpl = $.templates(" {{:name}}");\n```\n\nThe compiled template object (`myTmpl`, in the example) provides a number of properties and methods, in particular:\n'},{_type:"para",title:"The render() method",text:"```js\nvar html = myTmpl.render(person);\n```\n\nSee [Render a template against data objects or arrays](#tmplrender)"},{_type:"para",title:"The markup property",text:'The declarative markup string for the template (available whether the template was registered by providing a markup string, or by a script block reference).\n\n```js\nvar test = myTmpl.markup; // " {{:name}}"\n```'},{_type:"para",title:"The compiled template object is actually a render() function",text:"The compiled template *is itself a function*, corresponding to its own render method, so the following two examples are actually equivalent.\n\n*Calling the render method:*\n\n```js\nvar html = myTmpl.render(person);\n```\n\n*Invoking the compiled template directly as render method:*\n\n```js\nvar html = myTmpl(person);\n```"}]},viewobject:{title:"The view object",path:"",sections:[{_type:"para",title:"",text:"JsRender templates render as a [*view hierarchy*](#views)."},{_type:"para",title:"A view object has the following properties and methods:",text:"- [type property](#viewobject@type)\n- [data property](#viewobject@data)\n- [parent property](#viewobject@parent)\n- [index property](#viewobject@index)\n- [getIndex() method](#viewobject@getindex)\n- [get(type) method](#viewobject@get)\n- [content property](#viewobject@content)\n- [root property](#viewobject@root)\n- [other properties (tmpl, views, ctx, tag)](#viewobject@other)\n\n"},{_type:"para",title:"",text:"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `view` objects have additional methods:*\n- *[refresh()](#jsvviewobject@refresh)*\n- *[contents()](#jsvviewobject@contents)*\n- *[childTags()](#jsvviewobject@childtags)*\n- *[nodes()](#jsvviewobject@nodes)*\n\n*See [JsViews `view` object](#jsvviewobject).*\n\n\n\n"},{_type:"para",title:"Accessing view objects",text:"The properties of the current view are accessed *declaratively* in a template using *[view paths](#paths)* -- such as `#parent` for the `view.parent` property.\n\nAccessing `view` objects *programmatically* is less common in JsRender, but can be useful for example:\n\n- in a helper function, `~myHelper()`, where the `this` pointer is the current view\n- in the render() method of a custom tag -- using `this.tagCtx.view`\n\n*Note:* In JsViews, accessing `view` objects programmatically is very common, thanks to the [`$.view()`](#jsv.d.view) method. For example in a click handler, `$.view(this);` returns the corresponding `view` object.

\n\n\n### Properties and methods:\n"},{_type:"para",title:"The type property:",text:'***view.type**: string corresponding to the type of view:*\n\n- `"data"` -- for the top-level view from a `render()` call\n- `"array"` or `"item"` -- from `{{for array}}` or `{{props object}}` (see *[array and item views](#views@itemview)*)\n- `"sometag"` -- for the view from `{{sometag}}...{{sometag}}` -- for example: `"include"`, `"if"`, `"for"`, `"props"`, `"mytag"`...\n',anchor:"type"},{_type:"para",title:"The data property:",text:"***view.data**: the current data context for the view* -- as in:\n\n```js\nvar team = view.data.team; // The team property of the current data object\n```\n\n`view.data` can be accessed declaratively in templates as `#data`-- as in:\n\n```jsr\n{{:#data}}\n{{>#data.description()}}\n{{for #data.team.members}}...\n```\n\nBut note that since `#data`, the current data context, is the starting point for *[data paths](#paths)* within templates, the above expressions with `#data' can be abbreviated to:\n\n```jsr\n{{:}}\n{{>description()}}\n{{for team.members}} etc.\n```\n\n ",anchor:"data"},{_type:"para",title:"The parent property:",text:"***view.parent**: the parent view* (used to step up through views in the hierarchy).\n\n```js\nvar index = view.parent.index; // The index of the parent view\n```\n\nAccessed declaratively as `#parent`:\n\n```jsr\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\n```\n\n(See also *[Accessing parent data](#parentdata)*)",anchor:"parent"},{_type:"para",title:"The index property:",text:'***view.index**: the view index* (only available on [item views](#views@itemview)).\n\n```js\nvar index = view.index; // The index of the view (for "item" views - otherwise an \'error string\')\n```\n\nAccessed declaratively as `#index`:\n\n```jsr\n{{if #index > 2}} {{!-- we are in an "item" view --}}\n {{:#parent.index}}... {{!-- "item" view index (- the parent - since we are inside the \'ifView\') --}}\n{{/if}}\n```\n\n**Note:** On non-"item" views, accessing the index property returns the error message prompt: *"For #index in nested block use #getIndex()."*',anchor:"index"},{_type:"para",title:"The getIndex() method:",text:'***view.getIndex()**: get the index of current "item" view* (steps up to nearest [item view](#views@itemview), and returns the index).\n\n```js\nvar index = view.getIndex(); // The index of the view\n```\n\nAccessed declaratively as `#getIndex()`:\n\n```jsr\n{{for teams}}\n {{for members}}\n {{if #getIndex() > 0}} {{!-- index of member (- this view is an "item" view for member) --}}\n {{:#getIndex()}} {{!-- index of member --}}\n {{/if}}\n\n {{:#parent.getIndex()}}... {{!-- index of team (-nearest "item" view of parent is team "item" view) --}}\n {{/for}}\n{{/for}}\n```\n',anchor:"getindex"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"If index is a multiple of 3, render new tr, and format index in bold.\n\nUse `getIndex()` to get *item* index from within *if* block.\n\n```jsr\n\n\n{{for members}}\n {{if #index===0}}\n \n{{/for}}\n\n
1:\n {{else #index%3===0}}\n
{{:#getIndex()+1}}:\n {{else}}\n {{:#getIndex()+1}}:\n {{/if}}\n {{:name}}\n
\n```"}],markup:"\n\n{{for members}}\n {{if #index===0}}\n \n{{/for}}\n\n
1:\n {{else #index%3===0}}\n
{{:#getIndex()+1}}:\n {{else}}\n {{:#getIndex()+1}}:\n {{/if}}\n {{:name}}\n
",data:{title:"The A Team",members:[{name:"Jeff"},{name:"Jack"},{name:"Jim"},{name:"Jo"},{name:"Joanna"},{name:"James"}]},title:"getIndex() – iterating + grouping by 3",jsrJsvJqui:"jsr",height:"80"},{_type:"para",title:"The get(type) method:",text:'***view.get(type)**: returns the nearest parent view of type `type`.*\n\n```js\nvar arrayView = view.get("array"); // Step through parents to nearest "array" view\nvar arrayLength = arrayView.data.length; // Get length of data array\n```\n\nAccessed declaratively as `#get(...)`:\n\n```jsr\n{{for members}}\n {{if #index+1 === #get("array").data.length}}\n The last member in the list\n {{/if}}\n{{/for}}\n```\n\n**Note:** An additional signature is available: ***view.get(true, type)*** (for advanced scenarios) -- which steps *down* through descendant views (depth first traversal) and returns *the first descendant view of type `type`*.\n\n```jsr\n{{for members}}\n {{:name}}\n{{/for}}\n{{:#get(true, "item").data.name}} {{!-- get the name of the first member --}}\n```\n\nIn using this API it is sometimes necessary to be aware of the processing order. For example in the sample code above, placing `{{:#get(true, "item")...}}` before `{{for members}}` will not return any "item" view, since the `{{:get(...)...}}` is being evaluated during the rendering, and the "item" views for `{{for ...}}` will not yet have been rendered. (View instantiation is part of rendering, which is a single-pass process.) \n\n',anchor:"get"},{_type:"para",title:"The content property (for views which wrap inline block content):",text:'***view.content**: template corresponding to the inline block content.*\n\nAccessed declaratively as `#content`:\n\nIn the [wrapping content](#tagsyntax@wrap) scenarios, the tag:\n\n```jsr\n{{sometag ... tmpl="externalTmpl"}}...{{/sometag}}\n```\n\nor\n\n```jsr\n{{mytag}}...{{/mytag}}\n```\n\nwill render with a view which has both a `view.tmpl` template property and a `view.content` template property.\n\nThe `view.content` template corresponds to the inline block content, and is used for wrapping that content as in:\n\n```jsr\nbefore {{include tmpl=#content /}} after\n```\n',anchor:"content"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*mytag:* \n\n```js\n$.views.tags(\n "mytag",\n "startTag {{include tmpl=#content /}} endTag"\n);\n```\n\n*externalTmpl:* \n\n```js\n$.templates(\n "externalTmpl",\n "startTmpl {{include tmpl=#content /}} endTmpl"\n);\n```\n\n*Template:* \n\n```jsr\n{{mytag}}\n
inside mytag
\n{{/mytag}}\n\n
\n\n{{mytag tmpl="externalTmpl"}}\n
inside mytag with external tmpl
\n{{/mytag}}\n```\n'}],html:'
\n\n\n',code:'$.views.tags(\n "mytag",\n "startTag {{include tmpl=#content /}} endTag"\n);\n\n$.templates(\n "externalTmpl",\n "
startTmpl {{include tmpl=#content /}} endTmpl
"\n);\n\n$("#result").html(\n $.templates("#myTmpl").render()\n);\n', -jsrJsvJqui:"jsr",title:"view.content – wrapping content",height:"170"},{_type:"para",title:"The root property:",text:"***view.root**: the root view (top-level ancestor view for this view)* -- as in:\n\n```js\nvar topLevelData = view.root.data; // Get the top-level data (obtained from the root view)\n```",anchor:"root"},{_type:"para",title:"Other view object properties:",text:'The following additional properties of the `view` object are used by JsRender for processing templates:\n\n- *tmpl*: the template used to render the view\n- *views*: the child views in the view hierarchy\n- *ctx*: object (hash) with the named contextual helpers/template parameters for this view\n- *tag*: the `"mytag"` view rendered by a custom tag `{{mytag ...}}`, has a `view.tag` property -- the instance of the `mytag` tag object.',anchor:"other"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsvviewobject",label:"JsViews view object"},{_type:"topic",hash:"views",label:"View hierarchy"}]}]},tagobject:{title:"The tag object",path:"",sections:[{_type:"para",title:"Tag object properties and event handlers provided as tag options",text:"The following tag properties and event handlers can be specified as tag options in the [`$.views.tags()`](#tagsapi) call, when registering a custom tag:\n\n*Tag properties*\n\n- [`baseTag`](#tagsapi@basetag)\n- [`flow`](#tagsapi@flow)\n- [`template`](#tagsapi@template)\n- [`bindTo`](#tagsapi@bindto)\n- [`ctx`](#tagsapi@ctx)\n- [`contentCtx`](#tagsapi@contentctx)\n- [`argDefault`](#tagsapi@argdefault)\n\n*Event handlers*:\n\n- [`init()`](#tagsapi@init)\n- [`render()`](#tagsapi@render)\n- [`convert()`](#tagsapi@convert)"},{_type:"para",title:"Additional properties and methods on the tag object",text:"In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\n\n*Tag properties*\n\n- [parent](#tagobject@parent)\n- [parents](#tagobject@parents)\n- [tagCtx](#tagobject@tagctx)\n- [tagCtxs](#tagobject@tagctxs)\n- [tagName](#tagobject@tagname)\n- [rendering](#tagobject@rendering)\n\n*Tag methods*\n\n- [ctxPrm()](#tagobject@ctxprm)\n- [cvt()](#tagobject@cvt)\n- [cvtArgs()](#tagobject@cvtargs)\n- [bndArgs()](#tagobject@bndargs)\n- [base()](#tagobject@base)\n- [baseApply()](#tagobject@baseapply)"},{_type:"para",title:"Accessing tag objects",text:"The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\n\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\n\n```jsr\n{{:~tag.parent.tagName}}`\n```\n\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\n\n```jsr\n{{:~tagCtx.props.mode}}`\n```\n\n### Tag properties and methods:\n"},{_type:"para",title:"The parent property",text:"***tag.parent**: the parent tag* (used to step up through views in the hierarchy).\n\n```js\nvar index = view.parent.index; // The index of the parent view\n```\n\nAccessed declaratively as `#parent`:\n\n```jsr\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\n```\n\n(See also *[Accessing parent data](#parentdata)*)",anchor:"parent"},{_type:"para",title:"The parents property",text:"Additional detailed documentation to follow...",anchor:"parents"},{_type:"para",title:"The tagCtx property",text:"Additional detailed documentation to follow...",anchor:"tagctx"},{_type:"para",title:"The tagCtxs property",text:"Additional detailed documentation to follow...",anchor:"tagctxs"},{_type:"para",title:"The tagName property",text:"Additional detailed documentation to follow...",anchor:"tagname"},{_type:"para",title:"The rendering property",text:"Additional detailed documentation to follow...",anchor:"rendering"},{_type:"para",title:"The ctxPrm() method",text:"Additional detailed documentation to follow...",anchor:"ctxprm"},{_type:"para",title:"The cvt() method",text:"Additional detailed documentation to follow...",anchor:"cvt"},{_type:"para",title:"The cvtArgs() method",text:"Additional detailed documentation to follow...",anchor:"cvtargs"},{_type:"para",title:"The bndArgs() method",text:"Additional detailed documentation to follow...",anchor:"bndargs"},{_type:"para",title:"The base() method",text:"Additional detailed documentation to follow...",anchor:"base"},{_type:"para",title:"The baseApply() method",text:"Additional detailed documentation to follow...",anchor:"baseapply"}]},viewcontextobject:{title:"The view context object",path:"",sections:[]},tagcontextobject:{title:"The tag context object",path:"",sections:[{_type:"para",title:"",text:"- render function(data, context, noIteration, parentView, key, onRender) {\n- tmpl\tfunction() {\n- args\t[]\tObject, (Array)\n- ctx\t{...}\tObject\n- index\t0\tNumber\n- params\t{...}\tObject\n- props\t{...}\tObject\n- tag\t{...}\tObject, (Tag)\n- view\t{...}\tObject\n \nAdditional detailed documentation to follow…\n"}]},"node/browserify":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Browserify support for JsRender and JsViews\n\n[Browserify](http://browserify.org/) lets you create modular JavaScript projects for the browser, using the npm `require()` pattern for packages/modules.\n"},{_type:"para",title:"JsRender as a Browserify module",text:"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the Browserify client script bundle, and loaded in the browser.\n\nThere are three options for loading JsRender in the browser as a Browserify module:\n\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the Browserify client script bundle:\n ```js\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\n ```\n- Load both jQuery and JsRender as modules in the Browserify client script bundle:\n ```js\n var $ = require('jquery'); // Load jQuery as a module\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\n ```\n- Load JsRender as a module in the Browserify client script bundle, without loading jQuery at all:\n ```js\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\n ```\n\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \n\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \n\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\n",anchor:"jsrender"},{_type:"para",title:"Example – jQuery loaded globally:",text:"**index.html:**\n\n```jsr\n\n \n\n
\n \n\n```\n\n**source.js:**\n\n```js\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"Example – jQuery loaded as module:",text:"**index.html:**\n\n```jsr\n\n
\n \n\n```\n\n**source.js:**\n\n```js\nvar $ = require('jquery'); // Load jQuery as a module\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"Example – JsRender without jQuery:",text:"**index.html:**\n\n```jsr\n\n
\n \n\n```\n\n**source.js:**\n\n```js\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\nvar tmpl = jsrender.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\ndocument.querySelector('#container').innerHTML = html;\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"JsViews as a Browserify module",text:"JsViews can also be included in the Browserify client-script bundle, and loaded in the browser.\n\nAfter installing on the server (using `$ npm install jsviews`), call:\n\n```js\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\n```\n\nor -- if also loading jQuery as a Browserify module, use:\n\n```js\nvar $ = require('jquery');\n...\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as a parameter)\n```",anchor:"jsviews"},{_type:"para",title:"Loading templates as Browserify modules",text:"JsRender includes a Browserify transform: `jsrender/tmplify` (see [below](#node/browserify@clientbundle)) which allows you also to include your server [file-based templates](#node/filetmpls) in the client-script bundle generated by Browserify. \n\nYou can then access the compiled templates in the browser, as modules.\n\nThe exact syntax depends on whether jQuery is loaded globally, loaded as a Browserify module, or not loaded at all.\n\n- If jQuery is loaded globally then use:\n ```js\n var tmpl = require('./templates/myTemplate.html'); // Load template (jQuery \n // is loaded globally)\n var html = tmpl.render(myData);\n ...\n ```\n- If jQuery is loaded as a module, use:\n ```js\n var $ = require('jquery');\n ...\n var tmpl = require('./templates/myTemplate.html')($); // Load template (local\n // jQuery as parameter)\n var html = tmpl.render(myData);\n ...\n ```\n- If loading JsRender as a module, without jQuery, use:\n ```js\n var jsrender = require('jsrender')(); // function call -- no parameter\n ...\n var tmpl = require('./templates/myTemplate.html')(jsrender); // Load template (jsrender\n // namespace as parameter)\n var html = tmpl.render(myData);\n ...\n ```\n\n**Note on relative paths:** The `./...` paths used to identify bundled templates are always interpreted as relative paths *relative to the location of your calling script*, which in this case is the Browserify script that created the client bundle. (Note that declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths)."},{_type:"para",title:"Nested templates",text:'Template inclusion in the bundle can be recursive, so for example if you call `require("./templates/myTemplate.html");` and *myTemplate.html* includes a nested reference to another template, such as `{{include tmpl="./another/tmpl2.html"/}}`, then the client-script bundle will include that template too.\n'},{_type:"para",title:"Generating the client bundle",text:"If *source.js* includes template references such as: `var tmpl=require('./some/path/myTemplate.html')`, then Browserify generates a client script bundle which will include the referenced templates.\n\n[Browserify](http://browserify.org/) provides three different ways of generating a *bundle.js* script from a *source.js* script, and calling a transform:\n\n**Command line:**\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\n**package.json:**\n\n```bash\n\"browserify\": {\n \"transform\": [\n [\"jsrender/tmplify\"]\n ]\n}\n```\n\n**API:**\n\n```bash\nbrowserify('./source.js')\n .transform(require('jsrender/tmplify'))\n .bundle()\n .pipe(fs.createWriteStream('./bundle.js'));\n```",anchor:"clientbundle"},{_type:"para",title:"Option: extensions",text:"The `jsrender/tmplify` Browserify transform uses a white-space-separated list of extensions: `\"html jsrender jsr\"`, by default. This means that when you generate a client-script bundle using the `tmplify` transform, it will treat any `.html`, `.jsrender` or `.jsr` file as a template, and will include the compiled template in the client-script bundle for rendering in the browser. \n\nYou can instead specify a different list of file extensions for templates, by using the `--extensions` or `-e` option, as in the following examples:\n\n```bash \nbrowserify -t [jsrender/tmplify --extensions 'htm jsrender'] ./source.js > ./bundle.js\n```\n\n```bash \nbrowserify -t [jsrender/tmplify -e 'htm jsrender'] ./source.js > ./bundle.js\n```\n\n```bash \n\"browserify\": {\n \"transform\": [\n [\"jsrender/tmplify\", {\n \"extensions\": \"htm jsrender\"\n }]\n ]\n}\n```\n\n```bash \nbrowserify('./source.js')\n .transform(require('jsrender/tmplify'), {extensions: 'htm jsrender'})\n .bundle()\n .pipe(fs.createWriteStream('./bundle.js'));\n```"},{_type:"para",title:"Including jQuery and/or JsRender/JsViews in the client-script bundle",text:"When using Browserify with JsRender on Node.js, you will generally need jQuery and JsRender/JsViews in the client, to render (and optionally data-link) the templates.\n\njQuery, JsRender and JsViews are all available as npm/Browserify modules, so you can choose whether to load them globally, using a script block, or as a module. Here are three examples following alternative strategies:\n\n**Load jQuery and JsRender/JsViews globally**\n\n`$` is defined as a global variable (`window.$`, or `window.jQuery`).
\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n\n\n...\n\n```\n\n*source.js:*\n\n```js\nvar myTmpl = require('./templates/myTemplate.html'); // Include compiled template in client-script bundle\nvar html = myTmpl(data); // Render using compiled template\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\nSee the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project for complete examples:\n- [clientcode-hello.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-hello.js) and [layout-hello.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello.html) using JsRender\n- [clientcode-movies.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-movies.js) and [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) using JsViews.\n \n**Load jQuery and JsRender/JsViews as Browserify modules**\n\nUse `var $ = require('jquery')` to load jQuery, and `require('jsrender')($)` or `require('jsviews')($)` to load JsRender/JsViews.
\nUse `require(templatePath)($)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n...\n\n```\n\n*source.js:*\n\n```js\nvar $ = require('jquery');\nrequire('jsrender')($);\nvar myTmpl = require('./templates/myTemplate.html')($)\nvar html = myTmpl(data);\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\nSee:\n- [clientcode-hello-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify.js) and [layout-hello-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify.html) for an example loading jQuery and JsRender as modules\n- [clientcode-hello-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-hello-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading JsRender as a module (without jQuery)\n- [clientcode-movies-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-movies-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading jQuery and JsViews as modules\n\n**Mixed approach: Load jQuery globally, and JsRender/JsViews as a Browserify module**\n\n`$` is defined as a global variable (`window.$` or `window.jQuery`).
\nUse `require('jsrender')` or `require('jsviews')` to load JsRender/JsViews.
\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n\n...\n\n```\n\n*source.js:*\n\n```js\nrequire('jsrender');\nvar myTmpl = require('./templates/myTemplate.html');\nvar html = myTmpl(data);\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\nSee [clientcode-movies-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-movies-browserify.js) and [layout-movies-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies-browserify.html) for an example using JsViews.",anchor:"clientscript"},{_type:"para",title:"Sample code",text:"For running code examples using JsRender, Browserify, and the `tmplify` transform, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project."},{_type:"para",title:"See also:",text:"*[Webpack support](#node/webpack)*"}]},"node/renderfile":{title:"renderFile() method",path:"",sections:[{_type:"para",title:"",text:"JsRender on Node.js provides a shortcut `renderFile` method, for convenience, to compile and render in one step:\n\n```js\nvar jsrender = require('jsrender');\n\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n// result: Name: Jim
\n```\n"}]},"node/filetmpls":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## File-based templates"},{_type:"para",title:"Defining templates as .html files",text:"On Node.js, JsRender templates can be stored directly in the file system (e.g. as `.html`, `.jsr.` or `.jsrender` files) -- for example:\n\n**Template:** *./templates/myTemplate.html* -- with contents:\n\n```jsr\nName: {{:name}}
\n```\n\n**Code:** JsRender recognizes file paths (for valid relative file paths starting with `'./'`), so you can write:\n\n```js\nvar jsrender = require('jsrender');\n\nvar tmpl = jsrender.templates('./templates/myTemplate.html'); // Compile the template\n\nvar html = tmpl({name: \"Jim\"}); // Render\n// result: Name: Jim
\n```\n\n**Note:** The `./...` paths are always interpreted as relative paths *relative to the location of your calling script*. Declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths."},{_type:"para",title:"renderFile() method",text:"JsRender on Node.js provides a shortcut `renderFile()` method, for convenience, to compile and render in one step:\n\n```js\nvar jsrender = require('jsrender');\n\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n// result: Name: Jim
\n```"},{_type:"api",typeLabel:"API:",title:"jsrender.renderFile(filepath, data)",name:"renderFile",object:"jsrender",method:!0,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"filepath",type:"string",optional:!1,description:"Relative path to template file - starting with './'"},{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."}],args:[],sections:[],example:"var jsr = require('jsrender');\nvar html = jsr.renderFile('./.../tmpl.html', data);",description:"Load file-based template, compile and render against data"}],description:"Shortcut method – compile and render",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Nested calls to file-based templates (composition)",text:"JsRender's awareness of Node.js file paths (relative paths starting with `'./'`) means your templates can include recursive calls to other templates (partials). You don't need to register or compile those templates separately. (See also: [template composition](#tagsyntax@composition)).\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\nName: {{:name}}
Address: {{include tmpl='./templates/other/addressTemplate.jsr'}}\n```\n\n**Template:** *./templates/other/addressTemplate.jsr*:\n```jsr\nStreet: {{:street}}\n```\n\n**Code:** Compile and render, recursively:\n\n```js\nvar jsrender = require('jsrender');\n\nvar tmpl = jsrender.templates('./templates/personTemplate.html');\n// Compile template - and also any recursively called templates\n\nvar html = tmpl({name: \"Jim\", street: \"Main St\"});\n// result: Name: Jim
Address: Main St\n```",anchor:"composition"},{_type:"para",title:"Register a file-based template by name – and render it",text:'For convenience you can register file-based templates by name, just as you can for [templates from strings](#d.templates@namedfromstring).\n\n```js\n// Register named template - "myTmpl1\n$.templates("myTmpl1", "./templates/myTemplate.html");\n\n// Render named template\nvar html = $.templates.myTmpl1(person);\n\n// Alternative syntax: var html = $.render.myTmpl1(person);\n```\n'},{_type:"para",title:"Automatic caching of file-based templates",text:"The first time `jsrender.templates('./templates/myTemplate.html')` is called, JsRender will:\n\n - load the template file from the file system\n - compile the template\n - cache the template\n - return the compiled template\n\nThe cached template can be accessed directly as `jsrender.templates['./templates/myTemplate.html']` - and can also be deleted by calling `delete jsrender.templates['./templates/myTemplate.html']`, or `jsrender.templates('./templates/myTemplate.html', null)`\n\nOn subsequent calls, JsRender will simply:\n - return the compiled template\n\nThe caching means you can load and compile the template during server initialization, and avoid the cost of reading the file or compiling during HTTP requests:\n\n```js\njsrender.templates('./templates/myTemplate.html'); // Cache the compiled template\n\napp.get('/...', function(req, res) {\n res.render('myTemplate', {name: \"Jim\"}); // Render previously cached template, using Express\n});\n```\n\nSimilarly when using the alternative forms for rendering templates:\n\n```js\napp.get('/...', function(req, res) {\n var tmpl = jsrender.templates('./templates/myTemplate.html'); // Get previously cached template\n var html = tmpl.render({name: \"Jim\"});\n res.send(html);\n});\n```\n\nor \n\n```js\napp.get('/...', function(req, res) {\n // Render previously cached template\n var html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n res.send(html);\n});\n```"},{_type:"para",title:"Using the same template on the server and in the browser",text:"JsRender lets you easily use the same templates for both server and browser rendering. See *[server/browser templates](#node/server-browser)* for details on two alternative approaches, one with the `{{clientTemplate}}` tag, and the other using *Browserify*."}]},jsrnode:{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"Quickstart",text:"See the [JsRender Node.js Quickstart](#jsr-node-quickstart) for an overview of JsRender support in Node.js"},{_type:"links",title:"Detail topics:",links:[],topics:[{hash:"node/install",label:"Installation and usage"},{hash:"node/filetmpls",label:"File-based templates"},{hash:"node/express-hapi",label:"Express and Hapi integration"},{hash:"node/server-browser",label:"Server/browser shared templates"},{hash:"node/browserify",label:"Browserify support"}]}]},"node/install":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Installation\n\nOn Node.js from the command line, install jsrender:\n\n```bash\n$ npm install jsrender\n```\n\n## Usage\n\nLoad the jsrender module:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call JsRender APIs, or use [Express](#node/express-hapi@express) or [Hapi](#node/express-hapi@hapi) integration, for server-rendering of JsRender templates.\n\n(For loading JsRender in the browser using Browserify or webpack, see *[JsRender as a Browserify module](#node/browserify@jsrender)* and *[JsRender as a webpack module](#node/webpack@jsrender)*)\n"},{_type:"para",title:"JsRender APIs on the server – same as in the browser!",text:"In the browser, when jQuery is present, JsRender loads as a jQuery plugin and adds APIs to the jQuery namespace object, as:\n\n`$.views`, `$.templates` and `$.render` \n\nOn the server exactly the same APIs are provided, associated instead with the `jsrender` namespace:\n\n`jsrender.views`, `jsrender.templates` and `jsrender.render`.\n\nFor convenience you can call the namespace `$` and then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy from the regular browser examples/samples -- as if in the browser with jQuery.\n\nFor example:\n\n```js\nvar $ = require('jsrender'); // Returns the jsrender namespace object - referenced for convenience as var $\n\nvar tmpl = $.templates('Name: {{:first}} {{upper:last'); // Compile template from string\n\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\n \nvar data = {first: 'Jo', last: 'Ryan'};\n\nvar html = tmpl(data); // Or alternative syntax: var html = tmpl.render(data);\n// result: \"Name: Jo RYAN\" \n```",anchor:"apis"},{_type:"para",title:"Using helpers, converters, custom tags...",text:'On Node.js you can use the full set of JsRender features, template tags and APIs, just as you would in the browser -- by simply using the `jsrender` namespace object returned from `require(\'jsrender\')`, instead of the jQuery object, `$`. In addition you can take advantage of [file-based templates](#node/filetmpls).\n\n**Custom Tags example:** -- For example, here is the JsRender Quickstart *[Custom Tags Sample](#jsr-quickstart@customtags)*, as you might write it on Node.js:\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\nName: {{fullName person/}}\n```\n\n**Code:**\n\n```js\nvar jsrender = require(\'jsrender\');\n\njsrender.views.tags("fullName", "{{:first}} {{:last}}"); // Register custom tag\n\nvar tmpl = jsrender.templates(\'./templates/personTemplate.html\'); // Compile template\n\nvar html = tmpl({person: {first: "Jim", last: "Varsov"}}); // Render\n// result: "Jim Varsov"\n```\n\n**Helpers example:** -- And here is the JsRender Quickstart *[Helpers](#jsr-quickstart@helpers)* example, in a version for Node.js:\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\n{{:~title}} {{:first}} {{:~upper(last)}}\n```\n\n**Code:**\n\n```js\nvar jsrender = require(\'jsrender\');\n\nvar myHelpers = {\n upper: function(val) { return val.toUpperCase(); },\n title: "Sir"\n};\n\nvar tmpl = $.templates(\'./templates/personTemplate.html\');\n\nvar data = {first: "Jim", last: "Varsov"};\n\nvar html = tmpl(data, myHelpers);\n// result: "Sir Jim VARSOV"\n```\n\nOr we can register helpers globally:\n\n```js\njsrender.views.helpers(myHelpers);\n\nvar data = {first: "Jim", last: "Varsov"};\nvar html = tmpl(data);\n// result: "Sir Jim VARSOV"\n```'}]},"node/express-hapi":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Express and Hapi integration"},{_type:"para",title:"Using Express to render templates",text:"In Express you can use JsRender APIs to render the template, as in the examples above, then return the html in the HTTP response:\n\n```js\napp.get('/...', function(req, res) {\n res.send(html);\n});\n```\n\nBut alternatively you can register JsRender as template engine for Express:\n\n```js\nvar jsrender = require('jsrender');\n\napp.engine('html', jsrender.__express); // Set JsRender as template engine for .html files\napp.set('view engine', 'html'); \napp.set('views', __dirname + '/templates'); // Folder location for JsRender templates for Express\n```\n\nRender template *./templates/myTemplate.html* -- content: `Name: {{:name}}
`:\n\n```js\napp.get('/...', function(req, res) {\n res.render('myTemplate', {name: \"Jim\"}); \n // result: Name: Jim
\n});\n```",anchor:"express"},{_type:"para",title:"Using Hapi to render templates",text:"JsRender also has built-in support as template engine for [Hapi](http://hapijs.com/):\n\nSet JsRender as the template engine for Hapi:\n\n```js\nvar jsrender = require('jsrender');\n\nserver.register(vision, function (err) {\n ...\n server.views({\n engines: { html: jsrender },\n relativeTo: __dirname,\n path: 'templates'\n });\n```\n\nUse Hapi to render a template:\n\n```js\nserver.route({\n method: 'GET',\n path: '/',\n handler: function (request, reply) {\n return reply.view('myTemplate', myData);\n }\n});\n```",anchor:"hapi"}]},"node/server-browser":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Sharing the same templates between server and browser\n\nJsRender lets you share templates between server and client, using either of the *Browserify* or *{{clientTemplate}}* approaches shown below."},{_type:"para",title:"Browserify",text:"Using Browserify with the `jsrender/tmplify` transform allows you to include your server [file-based templates](#node/filetmpls) in the Browserify client-script bundle. \n\nYou can then access the compiled templates in the browser, as modules, using:\n\n```js\nvar tmpl = require('./.../myTemplate.html)`\nvar html = tmpl.render(myData);\n...\n```\n\nFor details, see the *[Browserify](#node/browserify)* topic.\n\nFor complete running samples, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project."},{_type:"para",title:"Rendering file-based templates in the browser: {{clientTemplate}}",text:'JsRender also provides a `{{clientTemplate}}` tag that makes file-based templates available for rendering in the browser without needing to use Browserify.\n\nSimply include `{{clientTemplate "templateFilePath..."}}` in the layout template, for any template you want to expose in the browser:\n\n```jsr\n\n {{clientTemplate "./templates/myTemplate.html" /}}\n\n\n
\n\n\n```\n\nSee the *index-express.js* and *index-hapi.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.'},{_type:"para",title:"JsRender on the server, JsRender or JsViews in the browser...",text:'Both the *Browserify* and the *{{clientTemplate}}* approach to sharing templates between server and browser let you then render or link those templates in the browser, using JsRender or JsViews.\n\nIn the browser, you reference the templates using the same `./file/path/template.html` syntax as on the server. \n\nFor example, in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* samples, the [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) template contains the following:\n\n```html\n\n {{include tmpl="./templates/movie-list.html"/}}\n\n```\n\nHere, the `{{include ...}}` is used on the server to do initial rendering of the movies list using the *movie-list.html* template. Then in the browser, the `data-link="{include ...}` causes JsViews to access the same template in the browser, and provide dynamic data-binding of the list...\n' -},{_type:"para",title:"Single Page Apps with initial rendering on server",text:'An important scenario is a *single page app* using JsRender or JsViews in the client to create dynamic UI, combined with initial rendering of the content on the server by JsRender using the same template.\n\nThis can bring many advantages, including SEO, and eliminating flicker when the page is refreshed with a new server request.\n\n*Note:* To completely eliminate flicker on data-linked content which has already been rendered on the server, it is sometimes useful to use the syntax `data-link="...^{...}"` -- which data-links without doing the initial render. Here is an example from [movie-detail.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/movie-detail.html) in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)*:\n\n```html\n
\n```\n'}]},tagsyntax:{title:"Tag syntax",path:"",sections:[{_type:"para",title:"",text:'Template tags in JsRender use the Mustache style: `{{...}}`.
\n(You can choose different delimiters, such as `<%...%>`, using `$.views.settings.delimiters("<%", "%>")`.\n'},{_type:"para",title:"Tags without content",text:"The most common JsRender tags are [`{{: pathOrExpr}}`](#assigntag) -- which inserts the value of the path or expression, and [`{{> pathOrExpr}}`](#htmltag) which inserts the *HTML-encoded* value of the path or expression. \n\nThose tags, along with the *allow code* tag [`{{* ...}}`](#allowcodetag) and *comment tag* [`{{!-- ... --}}`](#commenttag), are self-contained tags which do not wrap other content:\n\n**Built-in tags without content:**\n\n```jsr\n{{: pathOrExpr}} (value)\n{{> pathOrExpr}} (HTML-encoded value)\n{{* mycode}} (using code)\n{{!-- this is a comment --}} \n```"},{_type:"para",title:"Block tags – tags with content: ",text:"**All other built-in tags, as well as all custom tags, use the block tag syntax:**\n\n```jsr\n{{include ...}}...{{/include}} or {{include .../}}\n{{for}}...{{/for}} or {{for.../}}\n{{props}}...{{/props}} or {{props .../}}\n{{if}}...{{/if}} or {{if .../}}\n{{myCustomTag}}...{{/myCustomTag}} or {{myCustomTag .../}}\n```\n\nTags using the *block tag syntax* have *open* and *close* tags, with content, or else they use the self-closing syntax, without content:\n\n**Block tag with content**\n\n```jsr\n{{sometag ...}}\n content\n{{/sometag}}\n```\n\n**Self-closing block tag (empty tag) -- no content:**\n\n```jsr\n{{sometag .../}}\n```\n\n",anchor:"blocktag"},{_type:"para",title:"Using tmpl=... to reference content as an external template",text:"A particular case of self-closing syntax is when any block tag uses the named parameter `tmpl=...` to reference an external template, which then replaces what would have been the block content.\n\nThis is a very useful technique for encapsulation and reuse of tag content. The content becomes a *'partial'* -- and is included thanks to template composition:\n\n**Self-closing block tag referencing an external template:**\n\n```jsr\n{{sometag ... tmpl=.../}}\n```\n\n(See for example `{{for languages tmpl=\"#columnTemplate\"/}}` in [this sample](#samples/jsr/composition/tmpl).)\n"},{_type:"para",title:"Template composition (partials)",text:"The most common way of composing templates is to have a layout template, and to use `{{include tmpl=... /}}`:\n\n```jsr\ntop level content\n{{include tmpl='myInnerTemplate' /}}\n```\n\nBut in fact template composition can be done by adding references to external templates using `tmpl=...` on ***any*** tag, as shown in the previous section.\n\n**Dynamic composition**\n\nNote that the `tmpl=...` can use any expression, so you can assign different nested templates dynamically based on data or context. For example you might write `{{include tmpl=~getTemplate(type) /}}` -- where `~getTemplate(...)` is a helper which returns a different template based in this case on the `type` property of the current data item.\n\nIn fact when setting `tmpl=...` dynamically, the returned template can be in any if the following forms:\n- a compiled template\n- a markup string\n- the name of a registered template\n- a selector\n- (on Node.js) a file path to a template",anchor:"composition"},{_type:"para",title:"Tag arguments and named parameters",text:'Tags can take both unnamed arguments and named parameters:\n\n```jsr\n{{sometag argument1 param1=...}}\n content\n{{/sometag}}\n```\nAn example of a named parameter is the `tmpl=...` parameter mentioned above:\n\n```jsr\n{{for languages tmpl="#columnTemplate"/}}\n```\n\nArguments and named parameters can be assigned values from simple data-paths such as:\n\n```jsr\n{{formattedAddress address.street format=~util.formats.upper /}}\n```\n\nor from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\n\n```jsr\n{{productValue product.quantity*3.1/4.5 description=name.toUpperCase() /}}\n```\n',anchor:"tagparams"},{_type:"para",title:"Wrapping content ",text:'If a tag has an external `tmpl=...` reference, ***and*** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (one or more times), thanks to the [`view.content`](#viewobject@content) or `#content` property:\n\n```jsr\n{{sometag ... tmpl="externalTmpl"}}\n inline block content\n{{/sometag}}\n```\n\n```js\n$.templates("externalTmpl", "before {{include tmpl=#content /}} after";\n```\n\nSimilarly, a custom tag can use a built-in template which wraps the inline content:\n\n \n```jsr\n{{mytag}}\n inline block content\n{{/mytag}}\n```\n\n```js\n$.view.tags("mytag", {\n ...\n template: "before {{include tmpl=#content /}} after"),\n ...\n});\n```',anchor:"wrap"},{_type:"para",title:"Block tags with {{else}}",text:'Some block tags provide features which involve using alternative content blocks. Block tag syntax supports this by allowing the content to be separated into two or more alternative content blocks, using `{{else}}` tags as separators:\n\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\n\n```jsr\n{{if firstExpression}}\n render this if the firstExpression is true\n{{else secondExpression}}\n else render this if the secondExpression is true\n{{else}}\n else render this\n{{/if}}\n```\n\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\n\n```jsr\n{{for members}}\n Member Name: {{:name}}\n{{else}}\n There are currently no members...\n{{/for}}\n```\n\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\n\n```jsr\n{{tabs caption="First Tab"}}\n first tab content\n{{else caption="Second Tab"}}\n second tab content\n{{/tabs}}\n```'},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsrtags",label:"Template tags"},{_type:"topic",hash:"paths",label:"Paths and expressions"}]}]},views:{title:"JsRender view hierarchy",path:"",sections:[{_type:"para",title:"A view is a rendered template/block tag",text:'Each instance of a rendered template or a template [block tag](#tagsyntax@blocktag) is associated with a JsViews [*"view"* object](#viewobject).\n\nFor example, if the following template is rendered, and inserted into the page --\n\n```jsr\n\n```\n\n```js\nvar team = {title: "The A team", members: [{name: "Jeff"}, {name: "Maria"}]};\n\nvar html = $("#teamTemplate").render(team);\n```\n\n-- then the rendered result will have the following *view structure*:\n\n
\n— teamView                (Team: The A team)\n   — ifView               (The team has members!)\n
\n\n\nEach view is associated with a [`view`](#viewobject) object, which provides APIs for accessing properties of that view, as well as for accessing parent or child views in the view hierarchy.'},{_type:"para",title:"The data context of a view",text:'In particular, a [`view`](#viewobject) has a [`data`](#viewobject@data) property, which is the *current data context* used for rendering that *view* (rendering that template, or inline block content):\n\n
\n— teamView                data: team\n   — ifView               data: team\n
\n',anchor:"datacontext"},{_type:"para",title:"Inline block content / external 'tmpl=...' reference: same view hierarchy...",text:'A view corresponds to an instance of a *[block tag](#tagsyntax@blocktag)* ***or*** a *rendered template* -- so if we replace the inline content of a tag by an external reference: `tmpl=...`, the rendered result will be unchanged, and *the view structure will also be identical*:\n\n```jsr\n\n\n\n```\n\nSame view structure as before:\n \n
\n— teamView                data: team\n   — ifView               data: team\n
',anchor:"nestedtmpl"},{_type:"para",title:"Stepping into a block tag – what is the new data context?",text:'Let\'s add a custom tag `{{mytag}}` to our template:\n\n```jsr\nMy team\n{{mytag members/}}\n...\n```\n\nWe\'ll define the custom tag, with a built-in template:\n\n```js\n $.views.tags("mytag", "{{:length}} member(s)");\n```\n\n`{{mytag members/}}` will render block content (with an associated view) using its tag template `"{{:length}} members"`. \n\n*What will the data context be for the `mytag` view?*\n\nBy default:\n\n- a block tag with no argument `{{sometag}}` will stay on the current data context\n- a block tag with an argument `{{sometag expr ...}}` will move the data context to `expr`.\n\nSo `{{mytag members}}` (just like `{{include members}}`) *will move the data context to `members`*.',anchor:"innerdata"},{_type:"para",title:"",text:'However a block tag may be designed to simply stay on the same data context as the parent block -- and that is the case for the `{{if}}` tag:\n\n- `{{if expr}}` does not move the data context.\n\nSo our template\n\n```jsr\n\n```\n\nwill have this view structure:\n\n
\n— teamView                data: team\n   — mytagView            data: team.members\n   — ifView               data: team (same as parent – teamView)\n
\n'},{_type:"para",title:"Array views and item views – {{for array}}",text:'Now let\'s add a `{{for members}}` tag to iterate over the `members`, inside the `{{if}}` block:\n\n```jsr\nTeam\n{{mytag members/}}\n\n{{if members.length}}\n Members:\n {{for members}}\n {{:name}}\n {{/for}}\n{{/if}}\n```\n\nWhen a [`{{for ...}}`](#propstag) tag is used with an array it creates:\n\n- an *"array" view*, whose `data` property is the array -- and under the "array" view:\n- an *"item" view* for each item in the array -- with as `data` property the item, and as [`index`](#getindex) property the index in the array:\n\n(Similarly, any tag which derives from the `{{for}}` tag -- such as the [`{{props}}`](#propstag) tag -- will also add an "array" view and "item" views...)\n\nSo our view structure with the `{{for}}` tag included will now be :\n\n
\n— teamView                data: team                 type: "data"\n   — mytagView            data: team.members         type: "mytag"\n   — ifView               data: team                 type: "if"\n      — arrayView         data: team.members         type: "array"\n         — itemView       data: team.members[0]      type: "item"\n         — itemView       data: team.members[1]      type: "item"\n
\n\n-- where we show also the [`type`](#viewobject@type) property of each `view`.',anchor:"itemview"},{_type:"para",title:"Array views and item views – tmpl.render(array)",text:'Suppose now we have an array of teams -- and we pass the `teams` array to the `render()` method:\n\n```js\nvar teams = [\n {title: "A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n```\n\nJsRender will render the `teamTemplate` once for each team -- and just like with the `{{for}}` it will create an *"item" view* for each item in the `teams` array -- with the two *"item" views* as children of an *"array" view*.\n\nHere it is as a working sample:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var html = $("#teamTemplate").render(teams);\n'}],markup:"",html:'\n\n
',code:'// mytag: custom tag to output "1 member" or "n members"\n$.views.tags("mytag", "{{:length == 1 ? \'1 member\' : length + \' members\'}}
");\n// Alternative version of mytag:\n// $.views.tags("mytag", "{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
");\n\nvar teams = [\n {title: "The A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "The B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"86"},{_type:"para",title:"",text:'And here is the resulting view structure:\n\n
\n— arrayView               data: teams\n   — itemView             data: teams[0]               (Team: The A Team - )\n      — mytagView         data: team.members           (2 members)\n      — ifView            data: teams[0]               (Members:)\n         — arrayView      data: teams[0].members\n            — itemView    data: teams[0].members[0]    (Jeff)\n            — itemView    data: teams[0].members[1]    (Maria)\n   — itemView             data: teams[1]               (Team: The B Team - )\n      — mytagView         data: team.members           (1 members)\n      — ifView            data: teams[1]               (Members:)\n         — arrayView      data: teams[1].members\n            — itemView    data: teams[1].members[0]    (Francis)\n
\n'},{_type:"para",title:"The default argument for a tag is the current data – #data",text:"For all built-in tags (and custom tags if you don't use the [argDefault](#tagsapi@argdefault) option), you can pass the current data to the tag by writing it without an argument.\n\nSo the following:\n\n```jsr\n{{:}} {{!--Render value of current data (string)--}}\n{{>}} {{!--Render value of current data (string)--}}\n{{for}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\n{{if}}...{{/if}} {{!--Render block if current data is truthy--}}\n{{props}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\n```\n\nare equivalent to:\n\n```jsr\n{{:#data}} {{!--Render value of current data (string)--}}\n{{>#data}} {{!--Render value of current data (string)--}}\n{{for #data}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\n{{if #data}}...{{/if}} {{!--Render block if current data is truey--}}\n{{props #data}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\n```"},{_type:"para",title:"In JsViews: From UI back to data:",text:"***Note:*** One of the features provided by JsViews data-linking (when you use the JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method) is the [`$.view(elem)`](#$view) method. This method provides a *reverse mapping* and lets you get from a rendered DOM element back to the corresponding view object in the view hierarchy. From the view you can get to the underlying data, the index, etc.\n\nSo in effect in JsViews, *the mapping from the view hierarchy to the UI becomes a two-way mapping...* \n\nSee [*Using $.view() to get from the rendered UI back to the data*](#jsv.d.view)",anchor:"#$view"},{_type:"links",title:"See also:",links:[],topics:[{hash:"getindex",label:"getIndex()"},{hash:"contextualparams",label:"Contextual parameters"},{hash:"parentdata",label:"Accessing parent data"}]}]},paths:{title:"Paths and expressions",path:"",sections:[{_type:"para",title:"",text:'JsRender tags can take [unamed arguments, or named parameters](#tagsyntax@tagparams):\n\n```jsr\n{{:arg0}}\n\n{{sometag arg1 arg2 param_a=param1 param_b=param2}}\n content\n{{/sometag}}\n```\n\nThe values of the arguments or parameters (such as `arg0`... `param1` ... above) must be valid JsRender paths or expressions.\n\nJsRender expressions are regular Javascript expressions, but with *no access to global variables*.\n\nInstead of global Javascript variables, JsRender expressions use *data paths*, *helper paths* and *view paths*, to access data values, values provided by helpers, and values obtained from the [view hierarchy](#views), such as the `#getIndex()`.\n\n***Data paths*** are of the form `dataProperty.bb.cc`, and they step through the data hierarchy, starting from the current data item (the [data context](#views@datacontext) for the current view). They can include array access, such as `team.members[id]`\n\n***View paths*** are of the form `#viewProperty.bb.cc`, and they start from the current [view](#views). So for example, `#data` is short for `#view.data` -- where `#view` is the current view.\n\n***Helper paths*** are of the form `~myHelper.bb.cc`, and they start from the named [helper](#helpers) `"myHelper"`. In addition they can be used to access *[contextual parameters](#contextualparams)*, or the built-in [`~root`](#contextualparams@root) \n\nHere are some examples of JsRender paths and values:\n\n*Data paths*:\n\n```jsr\n{{:name}}\n{{for address.street}}...{{/for}}\n{{>team.members[0].lastName}}\n{{:name.toUpperCase()}}\n```\n\n*Helper paths*:\n\n```jsr\n{{>~utilities.errorMessages.msg1}}\n{{if ~settings.show}}...{{/if}}\n{{:~root.selectedName}} {{!--Accessing root data--}}\n```\n\n*View paths*:\n\n```jsr\n{{:#getIndex()}}\n{{include #content /}}\n{{if #parent.parent.data.isLead}}...{{/if}}\n{{>~getDescription(#data)}}\n```\n\n*A primitive value of type string, number, boolean, null ...*:\n\n```jsr\n{{if isOpen tmpl=\'It is open\' /}}\n{{for address tmpl="#addressTemplate"}}...{{/for}}\n{{for members start=1 end=5 /}}\n{{for members reverse=true /}}\n```\n\nJsRender expressions can combine values in more complex expressions, using functions, parens, operators such as `+` `-` `*` `/` `!` `===` `==` `>` `!==` `||` `&&`, as well as ternary expressions: `...?...:...`, array and object accessors: `[...]` etc.\n\n*Here are some examples of expressions*: \n\n```jsr\n{{if book.author === "Jim Boyd"}}...{{/if}}\n{{:~utilities.format(book.title, \'upper\', true)}}\n{{for ~sort(~root.getMembers()}}}...{{/for}}\n{{:person.firstName + \' \' + person.lastName.toUpperCase()}}\n{{for #parent.data.members()/}}\n{{:(~addRebate(book.price) + 23.2)*3.5/2.1}}\n{{:~mode === "useTitle" ? book.title : book.name}}\n{{if error}}...{{else !utilities.valid(book.description)}}...{{else}}...{{/if}}\n{{:~books[id].title}}\n{{:people[~currentIndex].name}}\n```\n\nExpressions can include white space. The following two examples are equivalent:\n\n```jsr\n{{averageValue product.quantity*3.1/4.5 description=~getDescription(#data) /}}\n{{averageValue product.quantity * 3.1 / 4.5 description = ~getDescription( #data ) /}}\n```\n\nThe `{{averageValue}}` tag is being assigned one argument, and one named "description" parameter. The two expressions differ only in white space, and both are syntactically valid. However, removing optional white space -– as in the first example -– makes it easier to see the distinct arguments and parameters of the tag.\n'},{_type:"para",title:"Chained paths: Stepping through object properties (or functions)",text:"All of the paths above (whether *Data/Helper/View paths*) involve starting from an initial value (a *current data item property/helper/view property*) -- and then, if it is an object, perhaps stepping through one or more chained properties.\n\nFor example `team.manager.address.street` starts from a `team` object and steps through the `manager` property -- which is itself a 'person' object with an `address` property, etc. \n\n(See also *[Data-linked paths](#linked-paths)*.)",anchor:"paths"},{_type:"para",title:"Computed properties",text:"In some cases a property may be of type *function* (possibly taking parameters), so you might have:\n\n`team.manager().getAddress('home').street`\n\n-- where the manager property is in fact a *'getter'* function which returns a `person` object, which has a `getAddress()` parameterized accessor (taking `'home'` or `'work'` -- or maybe a Boolean `isHomeAddress`). Similarly a path can include an array accessor such as `team.members['id'].address`.\n\nProperties of type function -- returning a value -- are referred to as a *computed properties*, or *getter properties*, and
\n`team.manager().getAddress('home').street` is an example of chained computed properties.\n\n(See also *[Computed properties and computed observables](#computed)* -- for using computed properties with JsViews and data-linking.)\n\nA computed value can also use JavaScript methods, such `toFixed()` to format a number:\n\n```jsr\n{{:price.toFixed(2)}} \n{{:(+price).toFixed(2)}} \n```",anchor:"computed"},{_type:"para",title:"Getter properties and computed properties",text:"A common pattern using computed 'getter' functions would be to provide a `person.firstName()` 'getter' property which returns a value: `person._firstName`, considered as 'private'.\n\nIn addition, there may be computed properties which depend on other properties, such as a `person.fullName()` which concatenates first and last name.\n\nHere is a sample showing both types of computed property:\n"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Data:*\n\n```js\nfunction firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nvar data = {\n person: {\n _firstName: "Jo",\n _lastName: "Blow",\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n }\n};\n```\n\n*Template:*\n\n```jsr\n First name: {{:person.firstName()}}\n Last name: {{:person.lastName()}}\n Full name: {{:person.fullName()}}\n```'}],code:'function firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nvar data = {\n person: {\n _firstName: "Jo",\n _lastName: "Blow",\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n }\n};\n\nvar html = $("#personTmpl").render(data);\n\n$("#result").html(html);',html:'
\n\n',height:"72",jsrJsvJqui:"jsr",title:"Getter properties with plain objects",anchor:"getter-plain-sample"},{_type:"para",title:"Getter properties on a View Model",text:"Rather than using plain JavaScript objects with getter functions, as above, a more common pattern (providing better encapsulation) would be to define a *'View Model'* class -- with getter properties defined in the class -- and to instantiate that class to provide data instances.\n\n(See *[Plain objects or View Model](#explore/objectsorvm)* for details.)\n\nThe following sample uses that approach:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Data:*\n\n```js\nfunction firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nfunction Person(first, last) {\n this._firstName = first;\n this._lastName = last;\n}\n\nPerson.prototype = {\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n};\n\nvar data = {\n person: new Person("Jo", "Blow")\n};\n```\n\n*Template:*\n\n```jsr\n First name: {{:person.firstName()}}\n Last name: {{:person.lastName()}}\n Full name: {{:person.fullName()}}\n```'}],html:'
\n\n',jsrJsvJqui:"jsr",height:"72",code:'function firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nfunction Person(first, last) {\n this._firstName = first;\n this._lastName = last;\n}\n\nPerson.prototype = {\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n};\n\nvar data = {\n person: new Person("Jo", "Blow")\n};\n\nvar html = $("#personTmpl").render(data);\n\n$("#result").html(html);',title:"Getter properties with a View Model",anchor:"getter-vm-sample"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"tagsyntax",label:"Tag syntax"},{_type:"topic",hash:"settings/allowcode@security",label:"Expressions and security"}]}]},tmplsyntax:{title:"Template syntax and structure",path:"",sections:[{_type:"para",title:"",text:"The following topics provide information on JsRender template syntax:"},{_type:"links",title:"",links:[],topics:[{hash:"tagsyntax",label:"Tag syntax"},{hash:"paths",label:"Paths and expressions"},{hash:"views",label:"View hierarchy"}]}]},settings:{title:"Settings",path:"",sections:[{_type:"para",title:"",text:"JsRender provides the following APIs for modifying settings:"},{_type:"links",title:"",links:[],topics:[{hash:"settings/delimiters",label:"Delimiters"},{hash:"settings/debugmode",label:"Debug mode"},{hash:"settings/allowcode",label:"Allow code"},{hash:"settings/advanced",label:"Additional advanced settings"}]}]},"settings/delimiters":{title:"Setting tag delimiters for JsRender",path:"",sections:[{_type:"para",title:"",text:"See also *[Setting tag delimiters for JsViews](#jsvsettings/delimiters)*"},{_type:"para",title:"JsRender default tag delimiters",text:"Template tags in JsRender use the Mustache style: `{{...}}`\n\n(JsRender also accepts the data-linked tag syntax used in in JsViews: `{^{...}}`). "},{_type:"para",title:"Changing delimiters:",text:'Sometimes there can be a need to use different delimiters. For example there may be a conflict if the template is being rendered on the server using a declarative syntax such as *Django* with the same default delimiters `{{` and `}}`.\n\nThe following call:\n\n```js\n$.views.settings.delimiters("<%", "%>");\n```\n\nwill change the tag syntax to `<%...%>`.\n\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `["<%", %>"]` -- as shown in the last sample below.)\n'},{_type:"para",title:"Verifying current setting for tag delimiters:",text:'```js\nvar delimiters = $.views.settings.delimiters();\n// Returns an array ["{{", "}}", "^"] - JsRender tag delimiters (and JsViews link character)\n```\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Markup:* \n\n```jsr\n\n```\n\n*Code*\n\n```js\n$.views.settings.delimiters("[%", "%]");\n\nvar tmpl = $.templates("#peopleTmpl");\n...\n```'}],html:'
\n\n',code:'$.views.settings.delimiters("[%", "%]");\n\nvar tmpl = $.templates("#peopleTmpl");\n\nvar team = {\n title: "A team",\n members: [{name: "Jo"}]\n };\n\nvar html = tmpl.render(team);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"70",title:"Choosing alternative tag delimiters, with JsRender"},{_type:"para",title:"Using alternative delimiters to 'render a template with a template'",text:"In some scenarios you might want to use a template to generate a template, such as a template on the server to generate/render a template that will then be used in the browser.\n\nA good approach to achieving this is to use a different set of delimiters on the server.\n\nA similar scenario is to use a 'base' template to render different versions of a template for different languages/localities, as in this example:\n",anchor:"tmpl-for-tmpl"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n<%:hello%>, {{:name}}
\n<%:welcome%> {{:place}}\n```\n\n```js\n// Get current delimiters\nvar currentDelimiters = $.views.settings.delimiters();\n\n// Temporarily switch delimiters\n$.views.settings.delimiters("<%", "%>");\n\n// Translate to Spanish localized version\nvar localizedTemplate = $.templates("#baseTmpl").render(spanishTerms);\n\n// Revert to original delimiters\n$.views.settings.delimiters(currentDelimiters);\n\n// Render data using localized template\nhtml = $.templates(localizedTemplate).render(data);\n```'}],html:'\n\n
\n', -code:'var spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Get current delimiters\nvar currentDelimiters = $.views.settings.delimiters();\n\n// Temporarily switch delimiters\n$.views.settings.delimiters("<%", "%>");\n\n// Translate to Spanish localized version\nvar localizedTemplate = $.templates("#baseTmpl").render(spanishTerms);\n\n// Revert to original delimiters\n$.views.settings.delimiters(currentDelimiters);\n\n// Render data using localized template\nhtml = $.templates(localizedTemplate).render(data);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"54",title:"Template for a template"},{_type:"para",title:"",text:"Incidentally the above scenario of localized terms in a template can be achieved without the 'build step' of creating localized templates, simply by passing in the terms as helpers, distinct from the data itself."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Pass in localized terms as helpers\nvar html = $.templates("#tmpl").render(data, spanishTerms );\n```'}],html:'\n\n
\n',code:'var spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Pass in localized terms as helpers\nvar html = $.templates("#tmpl").render(data, spanishTerms );\n\n$("#result").html(html);\n',height:"54",title:"Passing in terms as helpers",anchor:"passing",jsrJsvJqui:"jsr"}]},"settings/onerror":{title:"onError",path:"",sections:[]},"settings/dbgmode":{title:"dbgMode",path:"",sections:[]},"settings/debugmode":{title:"Setting debug mode",path:"",sections:[{_type:"para",title:"",text:'JsRender has a *\'debug mode\'* setting which determines whether error messages encountered during rendering are displayed.\n\n***To get current debug mode:***\n\n```js\nvar isDebugMode = $.views.settings.debugMode(); // false by default\n```\n\n***To set debug mode:***\n\n```js\n$.views.settings.debugMode(...);\n```\n\nDebug mode can be set to any of the following:\n\n- `false` -- *errors during rendering will not be rendered* (but an exception will be thrown)\n- `true` -- no exception will be thrown, but *the error message will be rendered*, in place of the template tag or block\n- `"some string"` -- no exception. *The string `"some string"` will be rendered* in place of the tag or block\n- `""` (empty string) -- no exception. The tag or block will simply be *replaced by the empty string*\n- a function (to be used as an error handler) -- no exception. The handler will run, and *the error string will be rendered, or else, if the function returns a string, that string will be rendered*\n\nSee *[Error handling and debugging](#onerror)* for a full discussion of alternative approaches, together with [details and working examples](#onerror@debugmode) of `$.views.settings.debugMode(...)`.\n\n '}]},"settings/allowcode":{title:"Allow code",path:"",sections:[{_type:"para",title:"",text:"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\n\n```jsr\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\n```\n\n\n\nNevertheless, in order to improve encapsulation, security and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \n\nIf you want complete freedom to insert any code into a compiled template, you can set **allowCode** to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the [`{{* ...}}`](#allowcodetag) tag, or you can return (render into the template output) the result of evaluating any expression, using the [`{{*: ...}}`](#allowcodetag) tag.\n\n(*Note:* it is not recommended to set `allowCode` to true within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\n\n"},{_type:"para",title:"User-defined templates and security",text:"For most purposes there is no need to set `allowCode` to true, since the built-in template expressions provide rich functionality which is sufficient for most scenarios.\n\nJsRender can be used to render templates either on the server or in the browser -- and is often used for applications which allow users to create their own templates, or to insert markup and expressions into templates. With `allowCode` false, JsRender is designed to *make it impossible for such user-defined templates to run arbitrary code*.\n\nUsers can include rich template expressions in the template, but they won't be able to insert code that accesses any variables (or runs any methods) that are outside of the template scope. (They can only access the contextual data/model, use the standard operators, and use any helper methods and variables which the author decides to provide.)",anchor:"security"},{_type:"para",title:"To set allowCode to true, globally",text:"```js\n$.views.settings.allowCode(true);\n```\n(See samples for [`{{* ...}}` and `{{*: ...}}`](#allowcodetag@sample))\n \n"},{_type:"para",title:"To set allowCode back to false, globally",text:"```js\n$.views.settings.allowCode(false);\n```\n",anchor:""},{_type:"para",title:"To get current global allowCode setting",text:"```js\nvar allowCodeIsTrue = $.views.settings.allowCode(); // false by default\n```"},{_type:"para",title:"To set allowCode to true for a specific template",text:"```js\n$.templates(..., {\n markup: ...,\n allowCode: true,\n ...\n})\n```\n\n(See `{{* ...}}` and `{{*: ...}}` sample: *[allowCode for template](#allowcodetag@tmpl)*)."}]},"settings/advanced":{title:"Advanced settings",path:"",sections:[{_type:"para",title:"",text:"JsRender has the following advanced setting:\n\n- **useViews** -- *default:* `false`\n\nand also the following 'private' advanced setting:\n\n- **_jsv** -- *default:* `false`\n\n***useViews*** controls a JsRender performance optimization, while building the *[view hierarchy](#views)*. In very simple templates there will usually not be any need to access the [`view`](#viewobject). JsRender detects these cases, does not create a view, and hence obtains a slight performance gain. By setting `useViews` to `true`, you guarantee that JsRender will *always* create views for template blocks.\n\n***_jsv*** is a 'private' setting (could change in the future). If set to `true` JsRender provides a global `_jsv` variable, which gives access to the internal store of views.\n\n***To get current advanced settings:***\n\n```js\nvar advancedSettings = $.views.settings.advanced();\n```\n\nBy default the returned `advancedSettings` object is:\n\n```js\n{useViews: false, _jsv: false}\n```\n\n***To set advanced settings:***\n\n```js\n$.views.settings.advanced({useViews: true});\n// Set one or more advanced settings\n```"}]},onerror:{title:"Error handling and debugging",path:"",sections:[{_type:"para",title:"",text:"Sometimes when rendering a JsRender template, a JavaScript error is encountered. For example `{{:address.street}}` in a template will render without error provided there is an `address` property on the current data object. But if there is no `address` property, then *there will be an error*: ***\"Cannot read property 'street' of undefined\"***.\n\nJsRender provides two features which provide powerful control over rendering behavior when errors are encountered.\n\n- The optional [`onError=...` property](#onerror@onerror) that can be set on any tag -- for controlling error handling behavior on that specific tag\n- The [`$.views.settings.debugMode(...)` setting](#onerror@debugmode) -- which provides global control over error handling during rendering\n\nIn addition, for advanced debugging of compiled templates, see:\n\n- *[Using debugging helpers](#onerror@dbg)*\n\n
\n## Specifying onError fallback behavior on a tag"},{_type:"para",title:"Setting onError to a string",text:'All JsRender tags (including custom tags) such as `{{address.street}}` or `{{for getItems()}}` allow you to provide a `onError` tag property, with a fallback string to render in the case of errors:\n\n```jsr\n{{:address.street onError="Address unavailable"}}\n```\n\n```jsr\n{{for phones() onError="No phones"}}\n```\n\n```jsr\n{{myCustomTag ... onError=""}}\n```\n\nThe `onError` fallback string will be rendered whenever there an error (or exception) is encountered during the tag rendering.\n\nSetting to the empty string ensures that errors are simply ignored, and the tag renders as the empty string.',anchor:"onerror"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'In this sample, if a `member` object has no `address` property, the `address.street` expression will lead to a JavaScript error, and the `{{:address.street onError="Address unavailable"}}` will render the fallback string: `"Address unavailable"`.\n\nSimilarly, `{{for phones() onError="..."}}`, if `phones()` produces an error... \n\n*Template:*\n\n```jsr\n{{for phones() onError="No phones"}} ...\n{{:address.street onError="Address unavailable"}}\n```\n\n*Code:*\n\n```js\nfunction phones() { if (!this._phones) { throw new Error("phones() error"); } ... }\n```\n\n*Data:*\n\n```js\nmembers: [\n {address: {street: "1st Ave"}, _phones: ["888", "456"], ...\n {address: undefined, _phones: ["987", "111"], ... // No address\n {address: {street: "Main St"}, _phones: undefined, ... // _No phones\n]\n```\n'}],html:'
\n\n\n',markup:"",jsrJsvJqui:"jsr",data:[],code:'function phones() {\n if (!this._phones) {\n throw new Error("phones() error");\n }\n return this._phones;\n}\n\nvar team = {\n members: [\n {address: {street: "1st Ave"}, _phones: ["888", "456"],\n phones: phones},\n {address: undefined, _phones: ["987", "111"], // No address\n phones: phones},\n {address: {street: "Main St"}, _phones: undefined, // _No phones\n phones: phones}\n ]\n};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);',title:'onError="fallback string..." ',height:"164"},{_type:"para",title:"Setting onError to an expression",text:"More specific or powerful behavior can be obtained by setting onError to an expression, such as:\n\n```jsr\n{{:address.street onError=name + \" has no address\"}}\n```\n\n```jsr\n{{:address.street onError=~errorMessages(1, name, 'address')}}\n```"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{{for phones() onError=name + " has no phones"}} ...\n```\n\n```jsr\n{{:address.street onError=~errorMessages(1, name, "address")}}\n```\n\n```js\n$.views.helpers("errorMessages", function(id, param1, param2) {\n if (id === 1) { return param1 + " has no " + param2; } ...\n});\n```\n'}],html:'
\n\n',code:'function phones() {\n if (!this._phones) {\n throw new Error("phones() error");\n }\n return this._phones;\n}\n\nvar team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}, _phones: ["888", "456"],\n phones: phones},\n {name: "Jane", address: undefined, _phones: ["987", "111"], // No address\n phones: phones},\n {name: "Ava", address: {street: "Main St"}, _phones: undefined, // _No phones\n phones: phones}\n ]\n};\n\n$.views.helpers("errorMessages", function(id, param1, param2) {\n if (id === 1) {\n return param1 + " has no " + param2;\n } \n});\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',height:"210",jsrJsvJqui:"jsr",title:"onError=someExpression..."},{_type:"para",title:"Setting onError to a function",text:'If `onError=myOnErrorHandler` is set to a function, then the function will be called when there is an error.\n\n- If the function returns a string, then that string will be rendered, replacing the output of the tag\n- If the function has no return value, then the error message will be rendered\n\nFor example, you can provide a `person.error()` error handler method on a person object, and set `onError=error`. Or you can use global helper (or a helper passed to the render function), and set `onError=~myErrorHandler`, such as the following to log the error and display just the empty string:\n\n```js\nfunction myErrorHandler(e, view) {\n console.log(...); // Log the error \n return ""; // Display the empty string \n}\n```\n\nThe parameters of the onError handler function -- `myHandler(e, view)` -- will be:\n\n- `e` -- the `error` object\n- `view` -- the current `view` object\n- The `this` pointer will be the current data item, `view.data`'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{{:address.street onError=~myOnError}}\n```\n```js\nfunction onErrorHandler(e, view) {\n console.log(e.message);\n if (!this.address) {\n return this.name + " has no address (" + e.message + ")";\n }\n}\n\nvar html = $("#teamTmpl").render(team, {myOnError: onErrorHandler});\n```'}],code:'var team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}},\n {name: "Jane", address: undefined} // No address\n ]\n};\n\nfunction onErrorHandler(e, view) {\n console.log(e.message);\n if (!this.address) {\n return this.name + " has no address (" + e.message + ")";\n }\n}\n\nvar html = $("#teamTmpl").render(team, {myOnError: onErrorHandler});\n\n$("#result").html(html);\n',html:'
\n\n\n',height:"126",jsrJsvJqui:"jsr",title:"onError=~myOnError"},{_type:"para",title:"",text:"
\n## Setting debug mode",anchor:""},{_type:"para",title:"",text:"The `$.views.settings.debugMode(...)` setting provides control of error handling during rendering, similar to the `onError` feature [above](#onerror@onerror), but operating at a global level rather than on individual tags.\n\nThese two approaches are complementary and can be used together. "},{_type:"para",title:"Setting debug mode to true",text:"- By default *debug mode* is **false** -- and *an exception will be thrown if a JavaScript error is encountered while rendering a tag or template*\n- If *debug mode* is set to **true** -- any error message encountered while rendering a tag *will replace the rendered content of that tag*\n\n***To set debug mode to true:***\n\n```js\n$.views.settings.debugMode(true);\n```\n\n***To set debug mode back to false:***\n\n```js\n$.views.settings.debugMode(false);\n```\n\n***To get current debug mode:***\n\n```js\nvar isDebugMode = $.views.settings.debugMode(); // false by default\n```\n\nIn the following example *debug mode* is set to `true`. The error message is rendered, replacing the rendered tag.\n\n(Choose *Try it* and change *debug mode* to `false`, to see the difference.)\n",anchor:"debugmode"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Code:*\n\n```js\n$.views.settings.debugMode(true);\n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by the error message.\n\n```js\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n...\n```\n\n*Template:*\n\n```jsr\n{{for members}}\n
{{:name}} - {{:address.street}}
\n{{/for}}\n```'}],code:'$.views.settings.debugMode(true); \n// Change to $.views.settings.debugMode(false); - The error\n// will not be displayed, but an exception will be thrown.\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',html:'
\n\n\n',jsrJsvJqui:"jsr",height:"74",title:"Debug mode set to true"},{_type:"para",title:"",text:"The following example also illustrates setting *debug mode* to `true`, but this time it is used with JsViews, and the `link(...)` method, rather than JsRender and `render(...)`.\n\nThe error conditions can arise both in expressions within tags, such as `{^{:manager.name}}` and data-link expressions such as `\n {{if owner}}\n Owner: {^{:manager.name}}\n {{/if}}\n
\nEdit: \n```\n\n*Code:*\n\n```js\n$.views.settings.debugMode(true);\n// Debug mode is set to true, so error messages are rendered in place of the corresponding tag or data-link expression.\n\nvar team = {owner:\n {name:"Jo"}\n}; // team.manager is undefined...\n...\ntmpl.link("#result", team); // Error...\n```\n\nIf you choose *Try it* and change to `$.views.settings.debugMode(false);`, the error will instead be thrown as an exception.\n'}],html:'\n
\n\n\n\n',code:'$.views.settings.debugMode(true);\n\nvar team = {owner:\n {name:"Jo"}\n}; // team.manager is undefined...\n\nvar tmpl = $.templates("#teamTmpl");\n\ntmpl.link("#result", {team: team}); // Error...',height:"80",title:"Debug mode set to true – JsViews",anchor:"datalink"},{_type:"para",title:"Setting debug mode to a string",text:'By setting debug mode to a string rather than to `true`, no exception will be thrown, and the chosen string will be rendered, replacing the rendered tag. \n\n```js\n$.views.settings.debugMode("Error!");\n``` '},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.settings.debugMode("Error!"); \n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by `"Error!"`.'}],html:'
\n\n\n',code:'$.views.settings.debugMode("Error!"); // Do not throw exception - render "Error!"\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',title:"Debug mode set to a default string",jsrJsvJqui:"jsr",height:"74"},{_type:"para",title:"",text:'In some scenarios the desired behavior may be to ignore errors during rendering, by skipping any tag with an error, rendering it as an empty string. This is achieved very easily, by simply writing:\n\n```js\n$.views.settings.debugMode("");\n``` '},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n$.views.settings.debugMode("");\n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is skipped.'}],title:"Debug mode set to empty string",code:'$.views.settings.debugMode(""); // Do not throw exception - render ""\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',html:'
\n\n\n',jsrJsvJqui:"jsr",height:"74"},{_type:"para",title:"Providing a debug mode handler (function)",text:'If debug mode is set to a function, the function will be called each time an error is encountered during rendering. \n\n- If the function returns a string, then that string will be rendered, replacing the rendered tag\n- If the function has no return value, then the error message will be rendered\n\n```js\n$.views.settings.debugMode(myOnErrorHandler);\n\nfunction myOnErrorHandler(e, fallback, view) {\n // This handler will log the error, and then display the empty string\n console.log(...);\n return ""; \n}\n```\n\nThe parameters of the debug mode error handler function -- `myHandler(e, fallback, view)` -- will be:\n\n- `e` -- the error object\n- `fallback` -- the fallback error string, provided by the *[onError fallback](#onerror@onerror)* specified on the tag, if there is one\n- `view` -- the current view object\n- The `this` pointer will be the current data item, `view.data`\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{:address.street onError='address'}}\n```\n\n```js\nfunction onErrorHandler(e, fallback, view) {\n console.log(e.message);\n if (fallback === \"address\") {\n return 'Address error for ' + this.name + '. (\"' + e.message + '\")';\n }\n}\n```\n\n```js\n$.views.settings.debugMode(onErrorHandler);\n```\n"}],html:'
\n\n\n',code:'var team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}},\n {name: "Jane", address: undefined} // No address\n ]\n};\n\nfunction onErrorHandler(e, fallback, view) {\n console.log(e.message);\n if (fallback === "address") {\n return \'Address error for \' + this.name + \'. ("\' + e.message + \'")\';\n }\n}\n\n$.views.settings.debugMode(onErrorHandler);\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',title:"Debug mode – onError handler",jsrJsvJqui:"jsr",height:"116"},{_type:"para",title:"Advanced debugging, using debugging helpers",text:'***Inserting breakpoints during rendering:***\n\nJsRender (and JsViews) provide some helpers for debugging code within compiled templates:\n\n- The `{{dbg expression/}}` tag\n- The `{{dbg: expression}}` converter\n- The `~dbg(expression)` helper function\n\nEach of the above will\n- evaluate the expression\n- output a `console.log(...)` call\n- throw and catch an exception -- which you can use as a break point by *stopping on caught exceptions*\n- render the evaluated expression\n\nThis is done by inserting code into the compiled template which calls into the built-in *dbgBreak* code:\n\n```js\nfunction dbgBreak(val) {\n try {\n console.log("JsRender dbg breakpoint: " + val);\n throw "dbg breakpoint"; // To break here, stop on caught exceptions.\n }\n catch (e) {}\n```\n\n`val` will be the result of evaluating `expression`.\n\nWhen rendering execution breaks at the above code, you can then step up through the call stack to the compiled template code, for further debugging.\n\nUsage examples: `{{dbg:...}}`, `{{:~dbg(...)}}`, `{{dbg .../}}` etc.\n\n***Breakpoints during data linking:***\n\nIn JsViews, a breakpoint can also be inserted during template data-linking, as in `{^{for ... onAfterLink=~dbg}}`.\n\n___Using {{*debugger}}:___\n\nAn alternative (but similar) debugging technique is to use `allowCode` to insert a `debugger;` statement directly into the compiled template code, as follows:\n\n*Code:*\n\n```js\nvar tmpl = $.templates({\n markup: "#myTmpl",\n allowCode: true // Alternatively use global setting: $.views.settings.allowCode(true)\n});\n```\n\n*Template:*\n\n```jsr\n...\n{{*debugger}}\n...\n```',anchor:"dbg"}]},advanced:{title:"JsRender – advanced topics",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"onerror",label:"Error handling"},{hash:"settings/advanced",label:"Advanced settings"},{hash:"jsrobjects",label:"JsRender objects"}]}]},apps:{title:"Building apps",path:"",sections:[{_type:"para",title:"Apps using JsRender",text:"*JsRender* is a simple light-weight templating engine. It can be used in the browser within simple web pages, or within complex single-page apps, or in conjunction with other frameworks. It can also be used on the server, using *Node.js*.\n\nIt is highly flexible, expressive, and 'unopinionated' -- so it leaves you free to work within your own choice of overall application architecture (including architectures based on *MVVM*, *MVP* or *MVC* -- optionally with server/client integration), and lets you use your own flavor of data/model layer -- whether simple plain JavaScript objects, hand-coded *View Model* instances, or *[compiled View Models](#viewmodelsapi)*.\n\n\n"},{_type:"para",title:"Components of an app using JsRender",text:"Any app or web page using JsRender templates will generally involve defining or registering the following elements:\n\n- one or more **templates** -- see *[Templates](#compiletmpl)*\n- a **'data Layer'** -- see *[JsRender: Data or View Model](#jsrmodel)*\n- optionally, **helpers** -- in the form of metadata, helper functions and converter functions, see *[Helpers](#helpers)* and *[Converters](#converters)*\n- optionally, **reusable components** for use within your templates -- see *[Custom tags](#tags)*"},{_type:"para",title:"Apps using JsViews",text:"*JsRender* also provides optional integration with *JsViews*. *JsViews* is much more of a framework than *JsRender*. It does much more than just templating -- providing also data-binding, *MVVM* support, observability of the *data/View Model* layer, support for interactive encapsulated components (*JsViews tag controls*), and more. Nevertheless, it can also interoperate with other frameworks and components. See *[Building apps in JsViews](#jsvapps)* for more information."}]},getindex:{title:"Iterating over arrays: accessing the array index",path:"",sections:[{_type:"para",title:"",text:"If you pass an array to the JsRender [`.render(myArray)`](#rendertmpl) method, or if you use [`{{for myArray}}`](#propstag), in a template, JsRender will iterate over the array, and render an [*item view*](#views@itemview) for each item in the array.\n\nWithin an item view you can access the array-index of the current item, using `{{:#index}}`:\n\n- *Getting item index within a top-level item view (from `.render(myArray)`)*:\n\n ```jsr\n ...\n {{:#index}}\n ...\n ```\n\n- *Getting item index within a `{{for myArray}}` block*:\n\n ```jsr\n {{for myArray}}\n ...\n {{:#index}}\n ...\n {{/for}}\n ```\n\nIf there are additional nested tags, then from within the nested tags you can still access the index, by using `{{:#getIndex()}}`:\n\n- *Getting item index from nested tags within an item view*:\n\n ```jsr\n {{for myArray}}\n ...\n {{if ...}}\n ...\n {{:#getIndex()}}\n ...\n {{/if}}\n ...\n {{/for}}\n ```\n\nSee [`index`](#viewobject@index) and [`getIndex()`](#viewobject@getIndex) for additional details.\n"},{_type:"links",title:"See also",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"}]}]},contextualparams:{title:"Contextual parameters",path:"",sections:[{_type:"para",title:"Defining contextual parameters",text:'*Contextual parameters* provide a very convenient way of passing values in to nested tag contexts. (See *[View hierarchy](#views)*.)\n\nA contextual parameter is defined by simply writing `~myValue=...` (for any expression) on any block tag, such as `{{if}}` or `{{for}}`.\n\nThe resulting `~myValue` parameter can then be accessed within the block tag -- or deeper down within nested tag contexts, at any depth. \n\nFor example, the following template defines three contextual parameters, and uses them in nested contexts:\n\n```jsr\n...\n{{if isActive ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\n {{for members}}\n {{if ~teamIndex>2}}\n {{:~teamTitle}} {{:~teamData.description}}\n ...\n```\n\n*Note:* You can also set contextual parameters on `{{else}}` blocks, such as in the following example which uses the same template for the `{{if}}` and `{{else}}` blocks, but assigns different values to the `~teamTitle` parameter in each case:\n\n```jsr\n{{if isActive ~teamTitle=activeTitle tmpl="teamTmpl"}}\n{{else ~teamTitle=inactiveTitle tmpl="teamTmpl"}}\n{{/if}}\n```\n'},{_type:"para",title:"itemVar – contextual parameter for data 'item' of block",text:"The *itemVar* feature lets you set up a contextual parameter for the current data 'item' of a block. It is in effect an 'alias' for `#data` within the block.\n\nTo define an *itemVar* contextual parameter for a block tag, simply write `itemVar=~someName`. The parameter `~someName` can then be accessed like any other helper variable or contextual parameter, within nested contexts to any depth.\n\n```jsr\n...\n{{for teams itemVar=\"~team\"}}\n ...\n {{for members itemVar=\"~member\"}}\n ...\n {{if isActive}}\n {{:~team.title}} {{:~member.name}}\n```\n\nSee also [this sample](#fortag@itemvar).",anchor:"itemvar"},{_type:"para",title:"Accessing root data: the built-in '~root' contextual parameter",text:"The built-in contextual parameter `~root` provides direct access to the *root data* which was passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews). It can be accessed from anywhere within a template, at an level of nested tags.\n\n*Note:* If an array is passed to `render()` or `link()` then `~root` will be the array (so you can render `{{:root.length}}` for example).",anchor:"root"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"}]}]},parentdata:{title:"Accessing parent data",path:"",sections:[{_type:"para",title:'Accessing "parent" data, from nested views. Passing in template variables',text:'When a template (containing nested template tags) is rendered, the result is a [view hierarchy](#views) -- where the views provide information on how the underlying data objects map to the rendered UI.\n\nOften it is helpful to be able to access the data for a *parent view* from a [*nested* template](#views@nestedtmpl) or [block](#tagsyntax@blocktag) (*nested view*).\n\nThere are several ways to get to *parent data*:\n\n- Create a *[contextual parameter](#contextualparams)* to pass a value to nested views.\n\n Here are three examples:\n\n ```jsr\n ...\n {{if ... ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\n ...\n {{for ...}}\n ...\n {{:~teamTitle}} {{:~teamData.title}} {{:~teamIndex}}\n ```\n\n- Use [`itemVar`](#contextualparams@itemvar) to provide a contextual parameter for the current data \'item\' of a block, to be passed in to deeper nested contexts \n\n ```jsr\n ...\n {{for members itemVar="~member"}}\n ...\n {{props}}\n ...\n {{:~member.name}}\n ```\n\n- Use the [`view.parent`](#viewobject@parent) property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\n\n ```jsr\n ...\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#parent.parent.data.title}}\n ```\n\n- Use the [`view.get(type)`](#viewobject@get) method to get to a parent view of a given `type`:\n\n ```jsr\n ...\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#get("if").data.title}}\n\n ```\n\n- Use the [`view.getIndex()`](#viewobject@getIndex) method to get to the index of a parent *"item"* view:\n\n ```jsr\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#parent.getIndex()}}\n {{:#getIndex()}}\n ```\n\nHere is a sample showing all of these methods:' -},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"This sample shows all the ways to get to *parent data* described in the section above:\n\n- Create a *contextual parameter* to pass a value to nested views.
\n- Use `itemVar` to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \n- Use the `view.parent` property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\n- Use the `view.get(type)` method to get to a parent view of a given `type`:\n- Use the `view.getIndex()` method to get to the index of a parent *\"item\"* view:\n"}],html:'\n\n
',code:'// mytag: custom tag to output "1 member" or "n members"\n$.views.tags("mytag", "{{:length == 1 ? \'1 member\' : length + \' members\'}}
");\n// Alternative version of mytag:\n// $.views.tags("mytag", "{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
");\n\nvar teams = [\n {title: "The A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "The B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"290"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"}]}]},jsrmodel:{title:"JsRender: Data / View Model",path:"",sections:[{_type:"para",title:"",text:"*JsRender* is designed to work well with either plain JavaScript objects and arrays, or with instances of JavaScript classes, such as *View Model* classes.\n\nSo, for example, if you are using data obtained from a JSON request, you can choose between:\n- rendering your templates directly against the objects and arrays returned from the JSON request\n- passing the data through a 'mapping' process to create a hierarchy of *View Model* instances, and rendering your templates against those objects\n\nThe *plain objects* [approach](#jsrmodel@plain) is convenient and simple for getting rapidly up and running with templates. But for more complex projects the *View Model* approach is better for creating clean well-designed modular code, where each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state.\n"},{_type:"para",title:"Using JsRender built-in compiled View Models",text:"*JsRender* will work well with your own 'hand-coded' *View Model* classes (see [below](#jsrmodel@vm)).\n\nBut in most cases it is simpler and better to use the [`$.views.viewModels(...)`](#jsrmodel@compilevm) API. This API lets you very easily and rapidly compile *View Model* classes for your own needs, following a standard pattern, and with some additional powerful features:\n\n- It provides a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\n- It also provides a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server.\n"},{_type:"para",title:"Data / View Model with JsViews",text:"All of the alternatives mentioned above (plain object hierarchies, hand-coded *View Model* classes, or JsRender *compiled View Model* classes) can also be used with *JsViews* data-binding and observable data. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)"},{_type:"para",title:"Example: JsRender with plain objects and arrays",text:" "},{_type:"code",title:"Suppose this is our data from a JSON request:",code:'var person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n'},{_type:"template",title:"We'll render using a template structured like this:",markup:"... \n{{:name}}\n...\n{{:address.street}}\n...\n{{for phones}}\n ... \n {{:number}}\n ...\n{{/for}}\n..."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name}} ..."},{_type:"code",title:"Render template against person (plain object)",code:'$("#result").html(tmpl.render(person));\n'}],html:'
\n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Data: hierarchy of plain objects and arrays\nvar person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n\n// Render template against plain object hierarchy\n$("#result").html(tmpl.render(person));\n\n',height:"140",jsrJsvJqui:"jsr",title:"Render template directly against plain objects..."},{_type:"para",title:"",text:"Now we'll convert the above sample to use *View Model* classes."},{_type:"para",title:"Example: JsRender with 'hand-coded' View Model objects",text:"We'll convert the data to a corresponding hierarchy of simple 'hand-coded' *View Model* class instances. In each case we will replace properties by simple *getters*, and corresponding 'private' properties. ",anchor:"vm"},{_type:"para",title:"View Model classes:",text:"Here is the class definition for Person:\n\n```js\n// Constructor\nfunction Person(name, address, phones) {\n // Initialize private properties\n this._name = name;\n this._address = address;\n this._phones = phones;\n}\n\n// Prototype\nvar personProto = {\n // Define a getter for each property \n name: function() {\n return this._name;\n },\n address: function() {\n return this._address;\n },\n phones: function() {\n return this._phones;\n }\n};\n...\n```\n\nWe define exactly similar classes for our Address and Phone objects too.\n\nThe above pattern for *View Model* classes will work well with *JsRender*. (It will also work seamlessly with *JsViews* data-binding, if at some point you choose to upgrade to use *JsViews* features).\n\n*Note:* The standard JsRender *View Model* pattern provided by `$.views.viewModels` is similar, but provides also setters (along with optional *'observability'* for two-way binding in *JsViews*).",anchor:"handvm"},{_type:"para",title:"Getter functions",text:"Note that properties are now getter functions, which return the appropriate value (which may be of any type, including objects or arrays -- such as `address` and `phones` above).\n\nIn fact they are particular case of *[computed properties](#paths@computed)* -- a concept that can be used quite generally within *JsRender* and *JsViews*, not only for *View Model* properties.\n"},{_type:"para",title:"Template",text:"To convert our template from using plain objects to using *View Model* objects, the only change we need to make is to add parens for our properties, which are now getter functions:\n\n```jsr\n... \n{{:name()}}\n...\n{{:address().street()}}\n...\n{{for phones()}}\n ... \n {{:number()}}\n ...\n{{/for}}\n...\n```"},{_type:"para",title:"Instantiate and render:",text:"Now all we need to do is to construct our root `person` object (with its underlying hierarchy of *View Model* instance objects) and render the template against that object in the usual way."},{_type:"sample",typeLabel:"Sample:",codetabs:[{_type:"codetab",name:"",url:"samples/mvvm/person-view-models-jsr.js",label:"person-view-models-jsr.js"}],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n... {{:name()}} ...\n```"},{_type:"code",title:"Instantiate View Model hierarchy",code:'// Use previously defined View Model classes: Person, Address, Phone\nvar person = new Person(\n "Pete",\n new Address(\n "1st Ave"),\n [\n new Phone("111 111 1111"),\n new Phone("222 222 2222")\n ]\n );\n'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'}],html:'\n\n
\n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Instantiate View Model hierarchy\nvar person = new Person(\n "Pete",\n new Address("1st Ave"),\n [\n new Phone("111 111 1111"),\n new Phone("222 222 2222")\n ]\n );\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));',height:"140",jsrJsvJqui:"jsr",title:"Render template against a View Model object hierarchy",anchor:"vmsample"},{_type:"para",title:"Using the same function as both getter and setter",text:'For properties which are read-write, the above *getter* functions can be replaced by a corresponding *getter/setter*, as follows: \n\n```js\nname: function(val) {\n if (!arguments.length) {\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is a value argument, treat as a setter\n},\n```\n\nNote that when *JsRender* renders a template using a *get/set* property `{{:name()}}` it will *always call the function as a getter, not as a setter*. However the *setter* feature lets you modify the value of `name()` from code, using:\n\n```js\nsomePerson.name("newName"); // setter\n```\n\nAlso, if you use the same *View Model* class with *JsViews* then the *setter* will be called:\n\n- when the user modifies a value with two-way data-binding such as ``\n- when using `$.observable(person).setProperty("name", "newName")` from code
\n(See [JsViews Data/View Model](#jsvmodel) for details, and alternative *setter* patterns.)'},{_type:"para",title:"Adding methods and computed properties to the View Model ",text:"Typically a *View Model* does not only provide *getter* (or *get/set*) properties -- but also other methods or computed properties corresponding to the appropriate logic at that point in the application. For example, a *View Model* for a *Person* might include a `selectPhone(...)` method or a `fullName()` computed property.\n\n"},{_type:"para",title:"Example: Using JsRender compiled View Models, with $.view.viewModels(...)",text:"The built-in support in both *JsRender* and *JsViews* for compiled *View Models* makes it extremely easy to define *View Model* classes that include *get/set* properties using the pattern described above, along with any desired additional methods and computed properties. Simple calls to `$.views.viewModels(...)` allow you to compile *View Model* classes conforming to these patterns without having to manually write repetitive code for multiple such *get/set* properties.\n \nAnother advantage of the compiled *View Model* classes is when working with (or migrating to) *JsViews*. In that context the classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates.\n\nFor details on `$.views.viewModels` see: *[Compiled View Models](#viewmodelsapi)*.\n\nTo illustrate, let's convert our [sample above](#jsrmodel@vm) to use compiled *View Models*. At the same time we will add a `person.addPhone(...)` custom method to the `Person` *View Model* class, and we'll illustrate calling a setter -- `name(...)`:",anchor:"compilevm"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name()}} ..."},{_type:"code",title:"Compile View Model classes",code:'...\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"], // get/set properties\n extend: {addPhone: addPhone} // Additional methods or properties\n});\n...'},{_type:"code",title:"Instantiate View Model hierarchy using constructors",code:'var person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'},{_type:"code",title:"Call setter, call method...",code:'...\nperson.name("newName"); // Use the name(...) setter\n\n...\nperson.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method'}],html:'\n\n\n\n\n
\n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(Phone(phoneNo));\n}\n\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"],\n extend: {addPhone: addPhone}\n});\n\n// Compile Address View Model\nvar Address = $.views.viewModels({getters: ["street"]});\n\n// Compile Phone View Model\nvar Phone = $.views.viewModels({getters: ["number"]});\n\n// Instantiate View Model hierarchy using constructors\nvar person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});',height:"190",jsrJsvJqui:"jsr",title:"Render template against a hierarchy of compiled View Model objects",anchor:"compilevmsample"},{_type:"para",title:"",text:"See also the [corresponding sample](#jsvviewmodelsapi@compilevmsample) with JsViews and data-linking (and [this version](#jsvmodel@compilevmsample) with two-way binding)."},{_type:"links",title:"For additional details and scenarios for compiled View Models, see:",links:[],topics:[{hash:"viewmodelsapi",label:"Compiled View Models"}]},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsv-model",label:"JsViews: Data/View Model"},{_type:"topic",hash:"computed",label:"Computed Observables"}]}]},helpersapi:{title:"Registering helpers: $.views.helpers()",path:"",sections:[{_type:"para",title:"",text:"`$.views.helpers()` is used to register helpers, accessed within templates using the syntax `~myhelper`. See *[Using helpers](#helpers)* for information about what *helpers* are, and some additional ways of providing them to templates.\n\nThis topic provides more details.\n\nWith `$.views.helpers(...)` you can:\n- register one or more helpers globally, to be used in any template\n- add one or more helpers as [private resources](#helpersapi@private) for a parent template"},{_type:"para",title:"Registering one or more helpers",text:""},{_type:"api",typeLabel:"API:",title:"$.views.helpers(...)",name:"helpers",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of helper - to be used in template path expressions as ~name..."},{_type:"param",name:"helper",type:"any type",optional:!1,description:"the helper - a function, object, or value"}],args:[],sections:[],example:'$.views.helpers("format", myFormatFunction);',description:"Register a helper, for use in any template with the syntax:
~name"},{_type:"signature",title:"",params:[{_type:"param",name:"namedHelpers",type:"object",optional:!1,description:"Object (hash) of keys (name of helper) and values (function, object, or value)"}],args:[],sections:[],example:'$.views.helpers({\n format: myFormatFunction,\n utilities: {},\n mode: "filtered"\n});',description:"Register multiple helpers"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example using a 'hierarchy' of helpers..."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'Here is an example using a \'hierarchy\' of helpers...\n\n```js\n$.views.helpers({\n ...\n utilities: {\n maxCount: 23,\n subtractMax: function(val) {\n return val - this.maxCount;\n },\n errorMessages: {\n msg1: "not available"\n }\n },\n ...\n});\n```\n\n```jsr\n{{:~utilities.subtractMax(sold) > 0\n ? ~utilities.errorMessages.msg1\n : "immediate"\n}}\n```'}],code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\n$.views.helpers({\n format: myFormatFunction,\n utilities: {\n maxCount: 23,\n subtractMax: function(val) {\n return val - this.maxCount;\n },\n errorMessages: {\n msg1: "not available"\n }\n },\n mode: "filtered"\n});\n\nvar html = $("#myTemplate").render({title: "gizmo", sold: 27});\n\n$("#result").html(html);',html:'
\n\n',title:"Register multiple helpers, including objects, etc.",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Adding helpers as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.helpers(...)`.\n\nIn that way the helper you are registering becomes a 'private helper resource' for the `parentTemplate`, rather than being registered globally:",anchor:"private"},{_type:"api",typeLabel:"API:",title:"$.views.helpers(namedHelpers[, parentTemplate])",name:"",object:"",method:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"namedHelpers",type:"object",optional:!1,description:"Object (hash) of keys (name of helper) and values (function, object, or value)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these helper(s) are being added as private resources"}],args:[],sections:[],example:"$.views.helpers({\n format: myFormatFunction,\n ...\n}, parentTemplate);",description:"Add one or more helpers as private resources for a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"links",title:"See also:",links:[],topics:[{hash:"helpers",label:"Using helpers"},{_type:"topic",hash:"samples/jsr/helpers",label:"Sample: Passing helpers to template.render()"}]}]},helpers:{title:"Using helpers",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering helpers](#helpersapi): The `$.views.helpers()` API*.)"},{_type:"para",title:"What are helpers?",text:'JsRender templates are made up of HTML markup, text, and *template tags*. *Template tags* are used to evaluate data-paths or computed expressions, and insert those values into the rendered output.\n\nBut often the values you will want to insert are not actually taken from the data, but rather from other parameters or *metadata* which you want to use. And often you will want to process the values, using helper functions or other code, e.g. for converting values to other formats, or for computed values.\n\n*Helpers*, in JsRender, refers to any functions, objects, parameters or metadata which you want to provide, in addition to the actual data you passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews).\n\nHelpers can also be objects, arrays, etc.\n\nYou access helpers by prepending the `~` character. Here are some examples:\n\n```jsr\n{{:~myHelperValue}}\n{{:~myHelperFunction(name, title)}}\n{{for ~myHelperObject.mySortFunction(people, "increasing")}} ... {{/for}}\n```'},{_type:"para",title:"Passing in helpers",text:'There are three ways to provide helpers:\n\n- Global helpers -- registered using [`$.views.helpers(myHelpers)`](#helpersapi)\n- Helpers registered for a specific template -- [`$.templates("mytmpl", {markup: ..., helpers: myHelpers}`](#d.templates@resources)\n- Helpers passed in on a specific render call -- [`tmpl.render(data, myHelpers)`](#tmplrender@helpers)
\n(Similarly you can [pass helpers](#jsvhelpers-converters) to JsViews `link()` calls)\n'},{_type:"para",title:"Contextual parameters",text:"In addition to providing helpers as above, you can also define *[contextual parameters](#contextualparams)* within a template, which you access using the same `~someName` syntax as for regular helpers. "},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```js\nvar myHelpers = {format: myFormatFunction};\n\n$.views.helpers(myHelpers);\n```\n\n```jsr\n{{:~format(name, true)}}\n```"}],title:"Global helper: $.views.helpers(...)",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar myHelpers = {format: myFormatFunction};\n\n$.views.helpers(myHelpers);\n\nvar html = $("#personTemplate").render({name: "Robert"});\n\n$("#person").html(html);',html:'
\n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar myHelpers = {format: myFormatFunction};\n\n$.templates({\n mytmpl: {\n markup: "#personTemplate",\n helpers: myHelpers\n }\n});\n```\n\n```jsr\n{{:~format(name)}}\n{{:~format(name, true)}}\n```'}],title:"Helper resource for a specific template",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar myHelpers = {format: myFormatFunction};\n\n$.templates({\n mytmpl: {\n markup: "#personTemplate",\n helpers: myHelpers\n }\n});\n\nvar html = $.render.mytmpl({name: "Robert"});\n\n$("#person").html(html);',html:'
\n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar myHelpers = {format: myFormatFunction};\n\nvar html = $("#personTemplate").render(data, myHelpers); \n```\n\n```jsr\n{{:~format(name, true)}}\n{{:~format(name)}}\n```\n\nSee [`template.render(...)`](#rendertmpl)'}],title:"Passing helpers with a render() call",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar data = {name: "Robert"};\n\nvar myHelpers = {format: myFormatFunction};\n\nvar html = $("#personTemplate").render(data, myHelpers); \n\n$("#person").html(html);',html:'
\n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering helpers](#helpersapi): The `$.views.helpers()` API"},{_type:"links",title:"See also:",links:[],topics:[{hash:"rendertmpl",label:"Render a template"},{_type:"topic",hash:"samples/jsr/helpers",label:"Sample: Passing helpers to template.render()"},{_type:"topic",hash:"settings/delimiters@passing",label:"Sample: Passing in terms as helpers"}]}]},convertersapi:{title:"Registering converters: $.views.converters()",path:"",sections:[{_type:"para",title:"",text:"See *[Using converters](#converters)* for an overview of what *converters* are, and some examples.\n\nThis topic provided more details.\n"},{_type:"para",title:"Using custom or built-in converters",text:"In JsRender, a converter is a convenient way of processing or formatting a data-value, or the result of expression evaluation.\n\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \n\n```jsr\n{{html:movie.description}} - This data is HTML encoded\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\n\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\n```\n\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\n\n```jsr\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \n{{upper:name}} - This uses my 'upper' converter \n```\n\n(See: [sample](#converters@simple).)\n\nYou can also use converters with any JsRender tag, not just the `{{: ...}}` tag, using the following syntax:\n\n```jsr\n{{sometag convert='myconverter' ...}}\n```\n\n(See: [sample](#converters@fortag).)\n\n***Note:*** With JsViews, you can use converters with two-way data-binding, and you will have a convert and a convertBack converter -- one for each direction."},{_type:"para",title:"Registering converters",text:"`$.views.converters()` is used to register converters.\n\nWith `$.views.converters(...)` you can:\n- register one or more converters globally, to be used in any template\n- add one or more converters as [private resources](#convertersapi@private) for a parent template"},{_type:"para",title:"Registering one or more converters",text:"A simple sample of registering a converter is shown [here](#converters@simple)."},{_type:"api",typeLabel:"API:",title:"$.views.converters(...)",name:"converters",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of converter - to be used in template markup: {{name: ...}}"},{_type:"param",name:"converterFn",type:"function",optional:!1,description:"Converter function. Takes val parameter and returns converted value"}],args:[],sections:[],example:'$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n\n{{upper: "upper case: " + nickname}}',description:"Register a converter"},{_type:"signature",title:"",params:[{_type:"param",name:"namedConverters",type:"object",optional:!1,description:"Object (hash) of keys (name of converter) and values (converter functions)"}],args:[],sections:[],example:"$.views.converters({\n upper: function(val) {...},\n lower: function(val) {...}\n});",description:"Register multiple converters"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Adding converters as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.converters(...)`.\n\nIn that way the converter you are registering becomes a 'private converter resource' for the `parentTemplate`, rather than being registered globally:",anchor:"private"},{_type:"api",typeLabel:"API:",title:"$.views.converters(...) — adding to parent template",name:"converters",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of converter - to be used in template markup: {{name: ...}}"},{_type:"param",name:"converterFn",type:"function",optional:!1,description:"Converter function. Takes val parameter and returns converted value (See API: function converterFn below for details)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this converter is being added as private resource"}],args:[],sections:[],example:'$.views.converters(\n "upper",\n function(val) { ... },\n parentTemplate\n);',description:"Register a converter as private resources for a parent template"},{_type:"signature",title:"",params:[{_type:"param",name:"namedConverters",type:"object",optional:!1,description:"Object (hash) of keys (name of converter) and values (converter functions)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these converter(s) are being added as private resources"}],args:[],sections:[],example:"$.views.converters({\n upper: function(val) {...},\n lower: function(val) {...}\n}, parentTemplate);",description:"Add one or more converters as private resources for a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Unregister a named converter",text:'To unregister a previously registered converter, pass `null` to `$.views.converters()`:\n\n```js\n$.views.converters("myCvt", null);\n// Named converter "myCvt" is no longer registered\n```'},{_type:"para",title:"Converter functions",text:"In most cases a converter function will return a computed value based on the input parameter `val`:\n\n```js\nfunction myConverter(val) {\n ... \n return computedVal; // converted/encoded/formatted value for 'val'\n}\n```\n\nwhere `val` comes from the data value or expression passed to the tag `{{myconverter: someExpression}}`. \n\n(See: [sample](#converters@simple).)\n", -anchor:""},{_type:"para",title:"Converter function signature",text:"However a converter can access multiple [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag. (See for example `{{fullname: first last ...}}`, in the [fullname sample](#converters@fullname).)\n\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag parameters](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\n\n```js\nfunction myConverter(arg1, arg2, arg3 ...) {\n var tag = this;\n var namedTagParameters = tag.tagCtx.props; \n ...\n return computedArg1; // converted value for 'arg1' passed to tag\n}\n```\n\nHere is the *converterFn* API definition:",anchor:"signature"},{_type:"api",typeLabel:"API:",title:"function converterFn(val, ...) {...}",name:"",object:"",method:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"val1",type:"object or string",optional:!1,description:"first tag argument"},{_type:"param",name:"val2",type:"object or string",optional:!0,description:"additional tag arguments"}],args:[],sections:[],example:'function myConverterFn(val1, val2, ...) {\n var tag = this;\n var tagProperties = tag.tagCtx.props;\n ...\n return ...;\n}\n\n$.views.converters("myconverter", myConverterFn);',description:"Converter function:
  • parameters: one or more tag arguments
  • this pointer: the tag instance
  • computes return value: which is passed to tag as first argument
"}],description:"A converter function registered using $.views.converters(...)",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Using converters with other tags",text:"A converter can be used on any tag, thanks to the syntax\n\n```jsr\n{{sometag ... convert=...}}\n```\n\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}` or `{{for}}`.\n\nSee the [sample](#converters@fortag) using `{{for people convert='extraItems'}}`, where the converter adds additional items to the array. \n\n(***Note:*** This syntax can actually be used with the `{{: ...}}` tag too -- by writing `{{:name convert='upper'}}`...)"},{_type:"para",title:"Example: a converter for {{if}}",text:'Here is an advanced sample: an `"inlist"` converter for `{{if}}`.\n\n- It accepts an `item` argument and a `list` argument, and an optional `field` *named property*\n- It returns `true` if the `item` is found in the `list`\n- If there is a `field` specified, it takes the value of that field (property) on the `item` and searches for it in the `list`\n\nNote that the converter gets called once for the first `{{if}}` tag block and once for each subsequent `{{else}}` block.\n\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n ...\n {{for people}}\n ...\n {{if #data ~root.team convert='inlist'}}\n ...\n {{else #data ~root.reserve field=\"name\"}}\n ...\n {{else}}\n ...\n {{/for}}\n ...\n \n```\n\n```js\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}.\n ... // Return true\n\n // If the tag has a 'field' property, look for the value of that field among the list items\n ... // Return true if found\n\n // If no field property, look for the item among the list items\n ... // Return true if found\n\n return false; // Not found\n}\n\n// Register 'inlist' converter just for the 'teamTmpl' template \n$.views.converters({inlist: inlistConverter}, teamTmpl);\n```"}],title:"'inlist' converter for {{if}} tag",html:'
\n\n',code:'var teamTmpl = $.templates("#teamTmpl");\n\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}\n if (!list) {\n return true; // Final else, so return true\n }\n\n var field = this.tagCtx.props.field;\n var l = list.length;\n\n // If the tag has a \'field\' property, look for the value of that field among the list items\n if (field) {\n while (l--) {\n if (item[field] === list[l]) {\n return true; // Return true if found\n }\n }\n }\n\n // If no field property, look for the item among the list items\n else {\n while (l--) {\n if (item === list[l]) {\n return true; // Return true if found\n }\n }\n }\n return false; // Not found\n}\n\n// Register \'inlist\' converter just for the \'teamTmpl\' template \n$.views.converters({inlist: inlistConverter}, teamTmpl);\n\n// Define model \nvar model= {people: [\n {name: "Jo"},\n {name: "Liza"},\n {name: "Eli"},\n {name: "Pete"},\n {name: "Zoey"}\n ],\n // Specify list of reserves, by name\n reserve: ["Eli", "Liza"]\n};\n\n// Specify array of team members\nmodel.team = [model.people[0], model.people[3]];\n\n$("#result").html(teamTmpl.render(model));\n',jsrJsvJqui:"jsr",height:"114",anchor:"iftag"},{_type:"para",title:"Using helper functions, or dynamically assigning converters",text:"The `convert=...` syntax allows you to assign a converter function without it being registered by name. For example it can be a data method or a helper function -- such as `{{sometag ... convert=~myConverterHelper}}`.\n\n(You can do this with the `{{: ...}}` tag too -- by writing `{{: ... convert=~myConverterHelper}}`...)\n\nYou can even assign a converter dynamically. For example you can write: `{{sometag ... convert=~getConverter(...)}}`, where the `getConverter()` helper might return either a string (for a converter registered by name) or a function to be used as converter.\n\nTo illustrate, here is a modified version of the previous sample, using `{{if ... convert=~getConverter()}}`:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```js\n// Converter function\nfunction inlistConverter(item, list) { ... }\n\n// Helper to dynamically assign converters\nfunction getConverter() {\n return inlistConverter; // For this sample just return `inlistConverter` every time\n}\n\n// Register 'getConverter' helper just for the 'teamTmpl' template \n$.views.helpers(\"getConverter\", getConverter, teamTmpl);\n```\n\n```jsr\n{{if #data ~root.team convert=~getConverter()}}\n ...\n{{/if}}\n```"}],html:'
\n\n',code:'var teamTmpl = $.templates("#teamTmpl");\n\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}\n if (!list) {\n return true; // Final else, so return true\n }\n\n var field = this.tagCtx.props.field;\n var l = list.length;\n\n // If the tag has a \'field\' property, look for the value of that field among the list items\n if (field) {\n while (l--) {\n if (item[field] === list[l]) {\n return true; // Return true if found\n }\n }\n }\n\n // If no field property, look for the item among the list items\n else {\n while (l--) {\n if (item === list[l]) {\n return true; // Return true if found\n }\n }\n }\n return false; // Not found\n}\n\n// Helper to dynamically assign converters\nfunction getConverter() {\n return inlistConverter; // For this sample just return `inlistConverter` every time\n}\n\n// Register \'getConverter\' helper just for the \'teamTmpl\' template \n$.views.helpers("getConverter", getConverter, teamTmpl);\n\n// Define model \nvar model= {people: [\n {name: "Jo"},\n {name: "Liza"},\n {name: "Eli"},\n {name: "Pete"},\n {name: "Zoey"}\n ],\n // Specify list of reserves, by name\n reserve: ["Eli", "Liza"]\n};\n\n// Specify array of team members\nmodel.team = [model.people[0], model.people[3]];\n\n$("#result").html(teamTmpl.render(model));\n',jsrJsvJqui:"jsr",height:"114",title:"Dynamically assigning a converter"},{_type:"para",title:"Built-in converters:",text:"JsRender has the following built-in converters/encoders:\n\n- Built-in HTML encoder: [`{{html: ...}}`](#convertersapi@html) -- accessed programmatically as [`$.views.converters.html()`](#convertersapi@html)\n- Built-in attribute encoder: [`{{attr: ...}}`](#convertersapi@attr) -- accessed programmatically as [`$.views.converters.attr()`](#convertersapi@attr)\n- Built-in URL encoder: [`{{url: ...}}`](#convertersapi@url) -- accessed programmatically as [`$.views.converters.url()`](#convertersapi@url)\n- Basic [encode/unencode converters](#convertersapi@encode)\n"},{_type:"para",title:"Built-in HTML encoder",text:"JsRender includes an HTML encoder, which you can use programmatically as follows:\n\n```js\nvar myHtmlEncodedString = $.views.converters.html(myString);\n```\n\nThe same encoder is accessed declaratively as a converter, as in the following two examples:\n\n```jsr\n{{html:myExpression}}\n\n{{>myExpression}}\n```\n\nIn fact [`{{>...}}`](#htmltag) is exactly equivalent to `{{html:...}}` and is provided as a simpler syntax for HTML encoding values taken from data or from expressions and rendered within HTML content. \n\n(***Note:*** the [`{{> ...}}`](#htmltag) tag should be used in place of the [`{{: ...}}`](#assigntag) tag whenever the data being rendered is not full trusted -- in order to prevent HTML injection attacks.)",anchor:"html"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "< > \' \\" &";\n\nvar result = $.views.converters.html(value);\n\nalert(result);'}],code:'var value = "< > \' \\" &";\nvar result = $.views.converters.html(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the HTML encoder"},{_type:"api",typeLabel:"API:",title:"HTML encoder",name:"html",object:"$.views.converters",method:!0,returns:"HTML-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be HTML-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Encodes according to the following scheme:\n

\n`&` → `&`
\n`<` → `<`
\n`>` → `>`
\n`\\x00` → `�`
\n`'` → `'`
\n`\"` → `"`
\n\\` → ```
\n`=` → `=`\n"}],example:"var encoder = $.views.converters.html;\nvar encodedString = encoder(myString);",description:"Returns the HTML-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Built-in attribute encoder",text:'JsRender includes an encoder intended for use when attribute encoding is needed. You can use it programmatically as follows:\n\n```js\nvar myAttributeEncodedString = $.views.converters.attr(myString);\n```\n\nThe same encoder is accessed by declaratively as a converter:\n\n```jsr\n{{attr:myExpression}}\n```\n\nA typical use case would be to encode an HTML attribute value in a template:\n\n```jsr\n
...
\n```',anchor:"attr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "< > \' \\" &";\n\nvar result = $.views.converters.attr(value);\n\nalert(result);'}],code:'var value = "< > \' \\" & =";\nvar result = $.views.converters.attr(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the 'attribute' encoder"},{_type:"api",typeLabel:"API:",title:"Attribute encoder",name:"attr",object:"$.views.converters",method:!0,returns:"Attribute-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be attribute-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Encodes according to the following scheme:\n

\n`&` → `&`
\n`<` → `<`
\n`>` → `>`
\n`\\x00` → `�`
\n`'` → `'`
\n`\"` → `"`
\n\\` → ```
\n`=` → `=`"},{_type:"para",title:"",text:"Note that this scheme encodes more characters than is sometimes the case for attribute encoding. In fact currently `{{attr: ...}}` and `{{html: ...}}` are equivalent. This ensures that using attribute encoding when HTML encoding should have been used will not expose an injection attack risk from untrusted data."}],example:"var encoder = $.views.converters.attr;\nvar encodedString = encoder(myString);",description:"Returns the attribute-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Built-in URL encoder",text:'JsRender includes a URL encoder, which you can use programmatically as follows:\n\n```js\nvar myUrlEncodedString = $.views.converters.url(myString);\n```\n\nThe same encoder is accessed by declaratively as a converter:\n\n```jsr\n{{url:myExpression}}\n```\n\nA typical use case would be to encode a HTML URL attribute value in a template:\n\n```jsr\n\n```',anchor:"url"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "<_>_\\"_ ";\n\nvar result = $.views.converters.url(value);\n\nalert(result);'}],code:'var value = "<_>_\\"_ ";\nvar result = $.views.converters.url(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the 'url' encoder"},{_type:"api",typeLabel:"API:",title:"URL encoder",name:"url",object:"$.views.converters",method:!0,returns:"URL-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be URL-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Internally encodes by calling the JavaScript function `encodeURI`."}],example:"var encoder = $.views.converters.url;\nvar encodedString = encoder(myString);",description:"Returns the URL-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Minimalist HTML encode/unencode converters",text:"\nIn addition JsRender and JsViews provide encode/unencode converters for minimal encoding to prevent HTML injection (see the JsViews topic: [*Encoding to avoid XSS*](#link2way@encode)), by encoding just `<` `>` and `&` by the corresponding HTML entities, and for unencoding back from entities to characters:\n\n`&` ↔ `&`
\n`<` ↔ `<`
\n`>` ↔ `>`
\n\n*Usage:*\n\n```js\nencodedValue = $.views.converters.encode(unencodedValue);\nunencodedValue = $.views.converters.unencode(encodedValue);\n```\n\n*Declarative usage:*\n\n```jsr\n{{encode:myExpression}}\n```",anchor:"encode"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"converters",label:"Using converters"},{_type:"topic",hash:"samples/jsr/converters",label:"Converters and encoding sample"},{_type:"topic",hash:"tagsapi@bindto",label:"Custom tags: The bindTo / bindFrom options and converters"}]}]},converters:{title:"Using converters",path:"",sections:[{_type:"para",title:"What are converters?",text:"In JsRender, a converter is a convenient way of processing or formatting data-value, or the result of expression evaluation.\n\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \n\n```jsr\n{{html:movie.description}} - This data is HTML encoded\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\n\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\n```\n\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\n\n```jsr\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \n{{upper:name}} - This uses my 'upper' converter \n```"},{_type:"para",title:"Built-in converters",text:"JsRender has the following built-in converters -- based on encoders:\n\n- Built-in HTML encoder: [`{{> ...}}`](#convertersapi@html)\n- Built-in attribute encoder: [`{{attr ...}}`](#convertersapi@attr)\n- Built-in URL encoder: [`{{url ...}}`](#convertersapi@url)"},{_type:"para",title:"Registering a converter",text:'You can register your own custom converters, using [`$.views.converters()`](#convertersapi) as in:\n\n```js\n$.views.converters("upper", function(val) {\n // Convert data-value or expression to upper case\n return val.toUpperCase();\n});\n```\n\nTo use the `"upper"` converter with the [`{{:...}}`](#assigntag) tag, you write:\n\n```jsr\n{{upper:...}}\n```\n\nHere it is in a sample:'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n```\n\n```jsr\nName: {{:name}}. Upper case nickname: {{upper:nickname}}\n...\n{{upper: "This will be upper case too"}} \n```'}],code:'$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n\nvar person = {name: "Robert", nickname: "Bob"};\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',html:'
\n\n',height:"80",title:"A simple converter",jsrJsvJqui:"jsr",anchor:"simple"},{_type:"para",title:"Converter arguments",text:'A converter can access any number of [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag:\n\n```js\n$.views.converters("myConverter", function(arg1, arg2, arg3 ...) {\n```\n\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag parameters](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\n\nThe following sample shows a `"fullname"` converter, which provides a computed ***full name*** based on the first two tag arguments (*first* and *last*) and an optional named tag parameter `reverse=true`:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters("fullname", function(first, last) {\n var reverse = this.tagCtx.props.reverse; \n if (reverse) {\n return last.toUpperCase() + " " + first;\n }\n return first + " " + last;\n});\n```\n\n```jsr\n... {{fullname:first last}}\n... {{fullname:first last reverse=true}}\n```'}],html:'
\n\n',code:'$.views.converters("fullname", function(first, last) {\n var reverse = this.tagCtx.props.reverse; \n if (reverse) {\n return last.toUpperCase() + " " + first;\n }\n return first + " " + last;\n});\n\nvar person = {first: "Xavier", last: "Prieto"};\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',jsrJsvJqui:"jsr",height:"80",title:"Full name converter – accessing multiple arguments",anchor:"fullname"},{_type:"para",title:"Using converters with other tags",text:"A converter can be used on any tag, thanks to the syntax\n\n```jsr\n{{sometag ... convert=...}}\n```\n\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}`.\n\n(*Note:* When using JsViews [two-way binding](#link2way@converters), similar syntax is available for *convertBack*: `convertBack=...`.)\n\nFor example, you could register an `\"inList\"` converter which returns true if `item` is found in `itemList` (see [sample](#convertersapi@iftag)):\n\n```jsr\n{{if convert='inList' item itemList}}...{{/if}}\n``` \n\nThe following sample shows the `{{for ...}}` tag used with a named converter which returns the array with additional appended and prepended items:",anchor:"othertags"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters({\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n});\n```\n\n```jsr\n{{for people convert=\'extraItems\'}}\n ...\n```\n\n\n'}],html:'
\n\n',code:'$.views.converters({\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n});\n\nvar model= {people: [\n {name: "Jo1"},\n {name: "Jo2"},\n {name: "Jo3"}\n]};\n\nvar html = $("#myTmpl").render(model);\n\n$("#result").html(html);',title:"Using converters with the {{for}} tag",jsrJsvJqui:"jsr",height:"114",anchor:"fortag"},{_type:"para",title:"Using helper functions or data methods as converters",text:"The `convert=...` syntax not only works on any tag, but also allows you to use not only registered converters, by name, as in\n\n```jsr\n{{for people convert='odd'}}\n```\n\nbut alternatively to use helpers, or data methods as in\n\n```jsr\n{{for people convert=utility.extraItems}} // Using data method\n```\n\nYou can also use that approach on `{{:..}}` tags as in\n\n```jsr\n{{:name convert=~hlp.bold}} // Using a helper\n```\n\nNote that the one tag which does not support this syntax is `{{>...}}` -- for which you would need instead to write:\n\n```jsr\n{{>~hlp.bold(name)}} // Using helper \n```\n\nHere is a modified version of the sample above, using helpers and data methods:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n...\n{{for people convert=utility.extraItems}} {{!-- using data method --}}\n
  • \n {{:name convert=~hlp.bold}} {{!-- using helper --}}\n...\n```"}],code:'var helpers = {\n hlp: {\n bold: function(val) {\n return "" + val + "";\n }\n }\n};\n\nvar model= {people: [\n {name: "Jo1"},\n {name: "Jo2"},\n {name: "Jo3"}\n ],\n utility: {\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n }\n};\n\nvar html = $("#myTmpl").render(model, helpers);\n\n$("#result").html(html);',html:'
    \n\n',jsrJsvJqui:"jsr",height:"114"},{_type:"links",title:"For additional details and scenarios see:",links:[],topics:[{hash:"convertersapi",label:"Registering converters"},{_type:"topic",hash:"link2way",label:"Two-way binding (JsViews)"}]},{_type:"para",title:"See also the following sample:",text:"[Converters and encoding](#samples/jsr/converters)\n"}]},nojqueryapi:{title:"JsRender without jQuery",path:"",sections:[{_type:"para",title:"",text:"JsRender can be loaded in the browser with or without jQuery, as in these example pages:\n\n- [JsRender with jQuery](#download/pages-jsr-jq)\n- [JsRender without jQuery](#download/pages-jsr)\n\nWhen jQuery is present:\n\n- JsRender loads as a jQuery plugin and adds APIs to the `jQuery` global namespace object -- usually aliased as `var $ = jQuery;`\n- The JsRender APIs are\n - `$.views...`\n - `$.templates(...)`\n - `$.render...`. \n\nIf jQuery is not present:\n\n- JsRender automatically creates its own `jsrender` global namespace variable \n- JsRender APIs are the same as above, but they are now associated with the `jsrender` namespace variable: \n - `jsrender.views...`\n - `jsrender.templates(...)`\n - `jsrender.render...`. \n\nFor convenience you can follow the jQuery approach of creating a global `$` -- set this time to `var $ = jsrender;`\n\nYou can then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy code from the regular browser examples/samples -- *as if* using JsRender with jQuery.\n\nFor example:\n\n```js\nvar $ = jsrender; // Alias for the jsrender namespace object - referenced for convenience as var $\n\nvar tmpl = $.templates('Name: {{:first}} {{upper:last'); // Compile template from string\n\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\n \nvar data = {first: 'Jo', last: 'Ryan'};\n\nvar html = tmpl.render(data);\n// result: \"Name: Jo RYAN\" \n```\n\n***Note:*** The same approach can be used when using [JsRender on the server](#node/install@apis) with Node.js, where JsRender is also being used without jQuery. "}]},"node/webpack":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Webpack support for JsRender and JsViews\n JsRender and JsViews can be loaded using [webpack](https://webpack.github.io/)."},{_type:"para",title:"JsRender as a webpack module",text:"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the webpack client script bundle, and loaded in the browser.\n\nThere are three options for loading JsRender in the browser as a webpack module:\n\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the webpack client script bundle:\n ```js\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\n ```\n- Load both jQuery and JsRender as modules in the webpack client script bundle:\n ```js\n var $ = require('jquery'); // Load jQuery as a module\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\n ```\n- Load JsRender as a module in the webpack client script bundle, without loading jQuery at all:\n ```js\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\n ```\n\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \n\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \n\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.",anchor:"jsrender"},{_type:"para",title:"Example – jQuery loaded globally:",text:"**index.html:**\n\n```jsr\n\n \n\n
    \n \n\n```\n\n**source.js:**\n\n```js\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"Example – jQuery loaded as module:",text:"**index.html:**\n\n```jsr\n\n
    \n \n\n```\n\n**source.js:**\n\n```js\nvar $ = require('jquery'); // Load jQuery as a module\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"Example – JsRender without jQuery:",text:"**index.html:**\n\n```jsr\n\n
    \n \n\n```\n\n**source.js:**\n\n```js\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\nvar tmpl = jsrender.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\ndocument.querySelector('#container').innerHTML = html;\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"JsViews as a webpack module",text:"JsViews can also be included in the webpack client-script bundle, and loaded in the browser.\n\nAfter installing on the server (using `$ npm install jsviews`), call:\n\n```js\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\n```\n\nor -- if also loading jQuery as a webpack module, use:\n\n```js\nvar $ = require('jquery');\n...\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as parameter)\n```",anchor:"jsviews"},{_type:"para",title:"See also:",text:"*[Browserify support](#node/browserify)*"}]},viewmodelsapi:{title:"Compiled View Models, using $.views.viewModels()",path:"",sections:[{_type:"para",title:"",text:"This topic provides details on using `$.views.viewModels()` to register/compile *View Models*.\n\nThis is the third of the alternative approaches discussed in *[Data / View Models](#jsrmodel)* -- namely:\n- [using](#jsrmodel@plain) plain objects\n- [using](#jsrmodel@vm) 'hand-coded' View Models\n- [using](#jsrmodel@compilevm) `$.views.viewModels()` to compile and register View Models with specific *get/set* properties and methods."},{_type:"para",title:"Advantages of compiled View Models",text:"Using `$.views.viewModels()` to compile *View Models* brings some important advantages over plain object hierarchies or 'hand-coded' *View Models*:\n\n- Simple calls to `$.views.viewModels(...)` allow you to compile these *View Model* classes without having to manually write repetitive code for multiple such *get/set* properties\n- Using compiled *View Models* rather than plain objects makes it easier to have clean well-designed modular code, since each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state\n- The compiled *View Models* provide a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\n- They also provide a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server\n- When working with (or migrating to) *JsViews* the compiled classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates. Updates to the *View Model* hierarchy, and calls to the *View Model* setters both trigger observable changes, with corresponding incremental updates to the *Views*. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)" -},{_type:"para",title:"Using compiled View Models",text:"The basic *use scenarios* of compiled *View Models* are as follows:\n- Using `$.views.viewModels(...)` to [register/compile](#viewmodelsapi@compile) *View Models* (`myVM`)\n- Using a compiled View Model `myVM` as [constructor/factory](#viewmodelsapi@construct) method -- `MyVM(...)` -- to create View Model instances (`myVmInstance`)\n- Using `MyVM.map(...)` to [convert](#viewmodelsapi@map) a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances\n- Using `myVMInstance.merge(...)` to incrementally [update](#viewmodelsapi@merge) a *View Model* hierarchy, using updated plain data\n- Using `myVMInstance.unmap()` to [convert](#viewmodelsapi@unmap) a *View Model* hierarchy back to a plain object hierarchy\n\n"},{_type:"para",title:"API: $.views.viewModels(...)",text:'To register a *View Model*, you call the `$.views.viewModels(...)` API -- with four alternative signatures:\n- `var MyVM = $.views.viewModels(viewModelOptions);`
    returning a compiled *View Model* \n- `$.views.viewModels("MyVM", viewModelOptions);`
    registering a named *View Model*, accessible as `$.views.viewModels.MyVM`\n- `$.views.viewModels(namedViewModels);`
    where `namedViewModels` is a hash, declaring multiple *View Models*\n- `$.views.viewModels(namedViewModels, myViewModels);`
    where `namedViewModels` is a hash, declaring multiple *View Models* and `myViewModels` is a *View Models* collection (hash) which will provide access to the compiled *View Models*, as `myViewModels.MyVM`\n\nIn each case, the compiled *View Model* is specified by a `viewModelOptions` object, with a `getters: gettersArray` (specifying an array of *get/set* properties), and/or an `extend: extendObject` (specifying additional methods or properties).\n\nExample:\n\n```js\nvar Book = $.views.viewModels({ // Compile a Book View Model\n getters: ["title", "price"], // getters array - signature of constructor\n extend: { // extend object - additional methods \n placeOrder: function() { ... }\n }\n});\n\nvar book1 = Book("Hope", "1.50"); // Construct a Book View Model instance\nbook.price("2.50"); // Modify price\nbook.placeOrder(); // Call method\n```\n',anchor:"compile"},{_type:"api",typeLabel:"API:",title:"$.views.viewModels(...)",name:"viewModels",object:"$.views",method:!0,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"viewModelOptions",type:"object",optional:!1,description:"A viewModelOptions object which can include:
    • a 'getters' array (details below)
    • an 'extend' hash - with additional methods or properties
    • an 'id' specifier
    "}],sections:[],example:'var Book = $.views.viewModels({\n getters: ["title", "price"]\n});\n\nvar bk1 = Book("Hope", "$1.50");',description:"Return a compiled View Model (constructor/factory method) with specific get/set properties and methods",returns:"View Model constructor"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered View Model"},{_type:"param",name:"viewModelOptions",type:"object",optional:!1,description:"A viewModelOptions object which can include:
    • a 'getters' array (details below)
    • an 'extend' hash - with additional methods or properties
    • an 'id' specifier
    "}],args:[],sections:[],example:'$.views.viewModels("Book", {\n getters: ["title", "price"]\n});\n\nvar bk1 = $.views.viewModels.Book("Hope", "$1.50");\n',description:"Register (and return) a named View Model",returns:"View Model constructor"},{_type:"signature",title:"",params:[{_type:"param",name:"namedViewModels",type:"object",optional:!1,description:"hash of viewModelOptions objects - each of which can include:
    • a 'getters' array (details below)
    • an 'extend' hash - with additional methods or properties
    • an 'id' specifier
    "}],args:[],sections:[],example:'$.views.viewModels({\n Book: {getters: ["title", "price"]},\n ...\n});\n\nvar bk1 = $.views.viewModels.Book("Hope", "$1.50");\n',description:"Register multiple named View Models"},{_type:"signature",title:"",params:[{_type:"param",name:"namedViewModels",type:"object",optional:!1,description:"hash of viewModelOptions objects - each of which can include:
    • a 'getters' array (details below)
    • an 'extend' hash - with additional methods or properties
    • an 'id' specifier
    "},{_type:"param",name:"viewModels",type:"object",optional:!1,description:"View Model collection object (hash)"}],args:[],sections:[{_type:"para",title:"",text:"*Specifying **viewModelOptions** – details:*\n\n- The (optional) `getters` array.
    -- Each item in the array corresponds to a *get/set* property (and also a constructor argument, which initializes that *get/set* property).
    -- It must be either\n - a string -- the `getterName`, or\n - an object, which must have a *getter* property: `{getter: getterName}`.

    If an object, it can additionally specify:

    \n - a *type* property: `type: viewModelName` -- specifying the name of another *View Model* type (declared in the same View Model collection). In this case then when using `map()` to map from data to a generated *View Model* hierarchy (see below), data values for the *get/set* property will be mapped to instances of that *View Model*.\n - a *defaultVal* property -- specifying the value to be used at initialization if `undefined` -- such as\n - `defaultVal: null` (a value) or,\n - `defaultVal: function() { return ...; }` (a function, to return a computed value. The this pointer is the data item.) \n- The (optional) `extend` hash has additional members (methods or properties) to be included in the View Model prototype. The prototype will extend this object\n- The (optional) `id` is either a string (the name of a *View Model* property to be treated as **id**) or\na function. The specified *id* or the function call will be used for determining identity when `merge(...)` updates a *View Model* hierarchy (see below)"}],example:'var myVms = {};\n\n$.views.viewModels({\n Book: {getters: ["title", "price"]},\n ...\n}, myVms);\n\nvar bk1 = myVms.Book("Hope", "$1.50");\n',description:"Add one or more named View Models to a View Model collection (hash)",returns:"View Model collection (hash)"}],description:"Register one or more View Models",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Creating View Model instances, using the View Model constructor",text:'*View Models* compiled/registered/returned by `$.view.viewModels(...)` are in fact constructors for instances of the *View Model* class.\n\n```js\nvar Book = $.views.viewModels({ // Constructor\n getters: ["title", "price"] // getters array - signature of constructor\n ...\n});\n\nvar book1 = Book("Hope", "$1.50"); // Create Book instance\n```\n\nNote that:\n- The `new` keyword is not necessary when calling the constructor. (It is in effect a factory method, that calls `new` internally.)\n- The signature of the constructor call (parameters used to initialize the instance) corresponds to the array of getters specified in the `viewModelOptions` - in this case `["title", "price"]`',anchor:"construct"},{_type:"para",title:"View Model hierarchies",text:'The `Book` View Model example above has simple *get/set* properties `["title", "price"]` which are simple primitive types (string in this case).\n\nBut consider the `Person` *View Model*, used in the overview topic *[Data / View Model](#jsrmodel)*. Here a `person` object (whether a plain object or a *View Model* instance) is in fact a hierarchy of objects, since the `address` and `phones` properties of a `Person` are themselves objects (an `Address` object and a `Phone` array)\n\nHere is a `person` plain object/hierarchy (obtained perhaps by \'evaluating\' JSON data from the server): \n\n```js\nvar person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n```\n\nTo map this object hierarchy to the corresponding *View Model* hierarchy we need to define three *View Models*:\n\n```js\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"],\n extend: {addPhone: addPhone}\n});\n\n// Compile Address View Model\nvar Address = $.views.viewModels({getters: ["street"]});\n\n// Compile Phone View Model\nvar Phone = $.views.viewModels({getters: ["number"]});\n```\n\nWe can then instanciate the corresponding *View Model* hierarchy, using constructors:\n\n```js\nvar person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n```\n\nSee the [sample](#jsrmodel@compilevmsample) in the *[Data / View Model](#jsrmodel)* topic.'},{_type:"para",title:"Creating View Model instances by mapping from data",text:"The process of manually writing code to map from JSON data to a corresponding *View Model* hierarchy, as above, can be complex and inconvenient. It requires traversing the data hierarchy and using appropriate *View Model* constructors to instantiate corresponding *View Model* instances. \n\nFortunately *JsRender/JsViews* compiled *View Models* provide a `map(data)` feature which when used together with *View Model* typed hierarchies makes this process quite trivial.\n",anchor:"map"},{_type:"para",title:"API: MyViewModel.map(...)",text:"Any compiled *View Model*, `MyViewModel`, provides a `MyViewModel.map(...)` method, which can be used to convert a plain object or an array of plain objects (or the equivalent JSON string) to the corresponding *View Model* instance (or array of *View Model* instances)."},{_type:"api",typeLabel:"API:",title:"MyViewModel.map(...)",name:"map",object:"MyViewModel",method:!0,returns:"View Model instance or array or instances",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object, array of objects, or JSON string",optional:!1,description:"The data (typically from JSON request)"}],args:[],sections:[],example:"// View Model\nvar Person = $.views.viewModels.Person;\n\n// View Model instance\nvar person = Person.map(personData);",description:"Generate a View Model instance/hierarchy/array by mapping from data (a plain object instance/hierarchy/array, or JSON string)"}],description:"Generate a View Model hierarchy from data",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:'Example:\n\n```js\nvar Book = $.views.viewModels({ // Constructor\n getters: ["title", "price"]\n});\n```\n\nMap from `bookData` plain object to `book` View Model instance:\n\n```js\nvar bookData1 = {title: "Hope", price: "$1.50"}; // book (plain object)\nvar book1 = Book.map(bookData1); // book (instance of Book View Model)\n```\n \nMap from `bookDataArray` array of plain objects to `bookArray` array of View Model instances:\n\n```js\nvar bookDataArray1 = [ // book array (plain objects)\n {title: "Hope", price: "$1.50"},\n {title: "Courage", price: "$2.50"}\n];\nvar booksArray1 = Book.map(bookDataArray1); // book array (instances of Book View Model)\n```'},{_type:"para",title:"View Model typed hierarchies",text:"When specifying `getters` in the `$.views.viewModels(...)` call, you can declare the type of a *get/set* property. For example an `address` *get/set* property can be specified as being of type `Address` -- where `Address` is another *View Model* declared on the same collection.\n\nBy specifying View Model types for properties (and declaring those View Models in the same collection) you obtain a *'View Model typed hierarchy'*.\n\n"},{_type:"para",title:"Using MyViewModel.map(...) to map a whole object hierarchy to a View Model instance hierarchy",text:'In the case of a *\'View Model typed hierarchy\'*, simply pass the top-level plain object to the `map()` method for the top-level *View Model* class, and all *View Model* instances in the hierarchy will be correctly instantiated:\n\n*Compile View Model classes (typed hierarchy):* \n\n```js\n$.views.viewModels({\n Person: {\n getters: [\n "name", // Declare \'name\' as being a primitive type (string)\n {getter: "address", type: "Address"}, // Declare \'address\' as being an Address (View Model) type\n {getter: "phones", type: "Phone"} // Declare \'phones\' as being (an array) of Phone (View Model) types\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone: ...\n});\n```\n\n*Person data (plain object hierarchy, or JSON string):*\n\n```js\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, ...]\n };\n```\n\n*Use map() to convert from `personData` plain object hierarchy (or JSON string) to `person` *View Model* hierarchy:*\n\n```js\nvar person = $.views.viewModels.Person.map(personData);\n```\n\nThe getter properties then let you traverse the hierarchy, call methods, etc.\n\n```\nperson.name("newName"); // Use setter: change name\nperson.addPhone(...); // Call method: add phone\nvar phone2 = person.phones()[1].number(); // Traverse and use getter: get number\n```\n\nLet\'s modify the [sample](#jsrmodel@compilevmsample) in *[Data / View Model](#jsrmodel)* to use the `map(...)` approach:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name()}} ..."},{_type:"code",title:"Compile View Model classes",code:'...\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: ...\n Phone: ...\n});\n'},{_type:"code",title:"Instantiate View Model hierarchy using Person.map(data)",code:'var personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\nvar person = vmCollection.Person.map(personData);'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'},{_type:"code",title:"Call setter, call method...",code:'...\nperson.name("newName"); // Use the name(...) setter\n\n...\nperson.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method'}],html:'\n\n\n\n\n
    \n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone:{\n getters: ["number"]\n }\n});\n\nvar vmCollection = $.views.viewModels;\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(vmCollection.Phone(phoneNo));\n}\n\n// person plain object hierarchy:\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\n// Instantiate View Model hierarchy using map()\nvar person = vmCollection.Person.map(personData);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});',height:"190",jsrJsvJqui:"jsr",title:"Using map() to convert from a plain object hierarchy to a View Model hierarchy",anchor:"mapsample"},{_type:"para",title:"",text:"(See also the [corresponding sample](#jsvviewmodelsapi@mapsample) with JsViews and data-linking.)"},{_type:"para",title:"Along with the map() feature – merge() and unmap()",text:"When working with View Model typed hierarchies, there are two additional features that can be used together with the `map()` feature:\n\n- If later you obtain updated JSON data, `personData2`, you can use `merge()` ([below](#viewmodelsapi@merge)) to trigger an incremental update to the *View Model* hierarchy:\n ```js\n person.merge(personData2);\n ```\n- If values are modified (using setters, or methods) you can at any time can use `unmap()` ([below](#viewmodelsapi@unmap)) to convert back to plain data, but with updated values:\n ```js\n var updatedPersonData = person.unmap();\n ```"},{_type:"para",title:"Using myVMobjectOrArray.merge(...) to update a View Model hierarchy",text:"If a *View Model* hierarchy (or array of *View Model* instances) was created using the `map()` feature above to map from data, then the *View Model* instances (and arrays) will each have a `merge()` method available:\n\n```js\nvar person = Person.map(personData1);\nperson.merge(personData2); // Incrementally update person (hierarchy)\n```\n\nor for an array:\n\n```js\nvar peopleArray = Person.map(peopleDataArray1);\npeopleArray.merge(peopleDataArray2); // Incrementally update people array\n```\n\nOr, deeper in the hierarchy:\n\n```js\nvar person = Person.map(personData1);\nperson.phones.merge(phonesDataArray2); // Update just the person.phones array\n```",anchor:"merge"},{_type:"para",title:"Updating with merge() makes minimal incremental changes, and preserves state",text:"Note that the `merge()` update process does not replace the whole hierarchy of *View Model* instances, but works incrementally to add/remove/modify instances as appropriate. So if most of the data in `personData2` is the same as `personData1`, calling `merge(personData2)` will make only minimal changes to the hierarchy. \n\nThis means that if *View Model* instances have state (such as additional properties that were set programmatically and are not driven by data) then that state can be maintained across the `merge()` update. "},{_type:"api",typeLabel:"API:",title:"myVMobjectOrArray.merge(...)",name:"merge",object:"myVMobjectOrArray",method:!0,returns:"View Model instance or array",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object, array of objects, or JSON string",optional:!1,description:"The updated data (typically from JSON request)"}],args:[],sections:[],example:"person.merge(personData2);\n// person (View Model hierarchy) has now\n// been updated, with modified data...",description:"Update a previously generated View Model instance/hierarchy/array by mapping from updated data"}],description:"Update a View Model hierarchy, from modified data",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Using myVMobjectOrArray.unmap() to convert back to a plain object hierarchy",text:"If a *View Model* hierarchy (or array of *View Model* instances) was created by mapping from data, using the `map()` feature above, then the View Model instances (and arrays) will each have an `unmap()` method (in addition to the `merge()` method mentioned above):\n\n```js\nvar person = Person.map(personData1);\nperson.addPhone(newPhone);\nperson.name(newName)\nvar modifiedPersonData = person.unmap(); // Convert back to a plain object hierarchy\n```\n\nor for an array:\n\n```js\nvar peopleArray = Person.map(peopleDataArray1);\npeopleArray[1].address.street(newStreet) // Make changes anywhere in the peopleArray\nvar modifiedPeopleDataArray = people.unmap(); // Convert back to a plain object array\n```\n\nOr, deeper in the hierarchy:\n\n```js\nvar person = Person.map(personData1);\nperson.addPhone(newPhone);\nvar modifiedPhonesArray = person.phones.unmap(); // Get a plain object array for person.phones\n```",anchor:"unmap"},{_type:"api",typeLabel:"API:",title:"myVMobjectOrArray.unmap()",name:"unmap",object:"myVMobjectOrArray",method:!0,returns:"object or array",signatures:[{_type:"signature",title:"",params:[],args:[],sections:[],example:"// Convert back to a plain object hierarchy\nvar modifiedPersonData = person.unmap();\n",description:"Obtain an updated plain object instance/hierarchy/array, from a previously generated View Model instance/hierarchy/array"}],description:"Get a plain object hierarchy from a View Model hierarchy",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an updated version of our [previous](#viewmodelsapi@mapsample) sample, where now we have added the use of `merge()` and `unmap()`"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"Compile View Model classes",code:'...\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: ...\n Phone: ...\n});\n'},{_type:"code",title:"Instantiate View Model hierarchy, using map()",code:'var personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\nvar person = vmCollection.Person.map(personData);'},{_type:"code",title:"Update View Model hierarchy, using merge()",code:'$("#update").on("click", function() {\n person.merge(personData2); // Update person View Model hierarchy\n $("#result").html(tmpl.render(person));\n});\n'},{_type:"code",title:"Get current data, using unmap()",code:'$("#getData").on("click", function() {\n var updatedPersonData = person.unmap(); // Get plain object hierarchy from current View Model hierarchy\n window.alert(JSON.stringify(updatedPersonData));\n});'}],jsrJsvJqui:"jsr",code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone:{\n getters: ["number"]\n }\n});\n\nvar vmCollection = $.views.viewModels;\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(vmCollection.Phone(phoneNo));\n}\n\n// First version of data (e.g. from JSON request):\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\n// Second version of data (e.g. new JSON request):\nvar personData2 = {\n name: "Peter",\n address: {street: "2nd Ave"},\n phones: [{number: "111 111 9999"},{number: "333 333 9999"}]\n};\n\n// Instantiate View Model hierarchy, using map()\nvar person = vmCollection.Person.map(personData);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#update").on("click", function() {\n // Update View Model hierarchy, using merge()\n person.merge(personData2);\n $("#result").html(tmpl.render(person));\n});\n\n$("#revert").on("click", function() {\n // Revert View Model hierarchy, using merge()\n person.merge(personData);\n $("#result").html(tmpl.render(person));\n});\n\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});\n\n$("#getData").on("click", function() {\n // Get current data, using unmap()\n var updatedPersonData = person.unmap();\n window.alert(JSON.stringify(updatedPersonData));\n});',html:'\n\n\n\n
    \n\n\n\n
    \n\n',height:"230",title:"Using merge() to update View Models, and unmap() to return to plain objects",anchor:"mergesample"},{_type:"para",title:"",text:"(See also the [corresponding sample](#jsvviewmodelsapi@mergesample) using JsViews and data-linking.)"},{_type:"para",title:"Overriding generated get/set functions",text:'To override a generated get/set property provided by a compiled View Model you can provide an implementation in the `extend` hash, with the same name as the *get/set* in the `getters` array:\n\n```js\n// Define a myNameGetSet(...)function, to override the compiled name(...) get/set function\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Declare a Person View Model with an overridden name() get/set property\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", ...}, // Compiled name() get/set\n ...\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n ...\n }\n ...\n },\n ...\n});\n```\n\nThe above is equivalent to the generated version except that it adds custom logging to the getter/setter function.\n\n**Note:** In the context of JsViews, the View Model get/set properties can be data-linked (one-way or two-way data-binding) -- and will then be invoked automatically during observable changes to the property. (This applies also to overridden properties -- using a variant of the above pattern, described in [the corresponding JsViews topic](#jsvviewmodelsapi@override)).',anchor:"override"},{_type:"para",title:"Sample showing some of the advanced View Model features",text:"The next sample is similar to the [previous](#viewmodelsapi@mergesample) one, but specifically highlights some of the advanced features of compiled *View Models*.\n\n- It stores compiled *View Models* on a `myVmCollection` hash, as a *View Model typed collection*, rather than on
    `$.views.viewModels`\n- It maps from an array of 'people' rather than a single person:
    \n `var people = Person.map(peopleData);`\n- It specifies an `id` key for `Person`. When updating the `phones` array the `id` value is treated as 'primary key', and used to map 'identity':
    \n `id: \"id\"`\n- It provides an `id()` callback on `Person`, for determining identity -- allowing identification of corresponding *View Model* instances within the people array, and hence preventing unnecessary disposal and re-instantiation (which would destroy state, such as the `comment` value).\n- It has a `comment()` get/set property that is added as part of the `extend` definition, not the `getters`, so it is not initialized from data, in the constructor. Note therefore that if you set a *comment* on each `person` instance, then click *Update*, then *Revert*, one *comment* is conserved (since that instance is never disposed -- based on the 'identity' determination) but the other is lost since the instance is disposed and then re-created by *Revert*:
    \n `extend: {...comment: comment...}`\n- It has `defaultVal` specified for `name`, `address` and `phones`, either as 'static' values or computed by a callback function:
    \n `address: {type: \"Address\", defaultVal: defaultStreet}`\n- It overrides the generated `person.name()` *get/set* by a `myNameGetSet` function which includes logging\n- It passes a JSON string to `merge()` or `map()`\n(See also the [same sample](#jsvviewmodelsapi@mergesampleadv) using JsViews and data-linking.)",anchor:"mergesampleadv"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var myVmCollection = {};\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", defaultVal: "No name"}, // Compiled name() get/set\n {getter: "address", type: "Address", defaultVal: defaultAddress},\n {getter: "phones", type: "Phone", defaultVal: []}\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n addPhone: addPhone,\n comment: comment // Additional get/set property, not initialized by data)\n },\n id: function(vm, plain) { // Callback function to determine \'identity\'\n return vm.personId === plain.personId;\n }\n },\n ...\n Phone: {\n getters: ["number"],\n id: "phoneId" // Treat phoneId as \'primary key\', for identity\n }\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\n\n// Override generated name() get/set\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Method for Person class\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\n this.phones().push(myVmCollection.Phone(phoneNo));\n}\n\n// get/set for comment (state on View Model instance, not initialized from data)\nfunction comment(val) {\n if (!arguments.length) {\n return this._comment;\n }\n this._comment = val;\n}\n\nfunction defaultAddress() { // Function providing default address if undefined in data\n return {street: \'No street for "\' + this.name + \'"\'};\n}\n\n// First version of data - array of objects (e.g. from JSON request):\nvar peopleData = [{personId: "1", ...}, {personId: "2", name: "Pete",...}];\n\n// Second version of data - JSON string (e.g. new JSON request):\nvar peopleData2 = \'[{"personId":"2","name":"Peter","address":...}]\';\n\n// Instantiate View Model hierarchy using map()\nvar people = myVmCollection.Person.map(peopleData);\n\n// Render template against people (array of Person instances)\n$("#result").html(tmpl.render(people));\n...\n\n// Button handlers\n$("#update").on("click", function() {\n people.merge(peopleData2);\n ...\n});\n...' -}],code:'var tmpl = $.templates("#personTmpl");\n\nvar myVmCollection = {};\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", defaultVal: "No name"}, // Compiled name() get/set\n {getter: "address", type: "Address", defaultVal: defaultAddress},\n {getter: "phones", type: "Phone", defaultVal: []}\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n addPhone: addPhone,\n comment: comment // Additional get/set property, not initialized by data)\n },\n id: function(vm, plain) { // Callback function to determine \'identity\'\n return vm.personId === plain.personId;\n }\n },\n Address: {\n getters: ["street"]\n },\n Phone: {\n getters: ["number"],\n id: "phoneId" // Treat phoneId as \'primary key\', for identity\n }\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\n\n// Override generated name() get/set\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Method for Person class\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\n this.phones().push(myVmCollection.Phone(phoneNo));\n}\n\n// get/set for comment (state on View Model instance, not initialized from data)\nfunction comment(val) {\n if (!arguments.length) {\n return this._comment; // If there is no argument, use as a getter\n }\n this._comment = val;\n}\n\nfunction defaultAddress() { // Function providing default address if undefined in data\n return {street: \'No street for "\' + this.name + \'"\'};\n}\n\n// First version of data - array of objects (e.g. from JSON request):\nvar peopleData = [\n {\n personId: "1",\n address: {\n street: "2nd Ave"\n }\n },\n {\n personId: "2",\n name: "Pete",\n phones: [\n {number: "333 333 3333", phoneId: "2a"}\n ]\n }\n];\n\n// Second version of data - JSON string (e.g. new JSON request):\nvar peopleData2 = \'[{"personId":"2","name":"Peter","address":{"street":"11 1st Ave"},\'\n+ \'"phones":[{"number":"111 111 9999","phoneId":"1a"},{"number":"333 333 9999","phoneId":"2a"}]}]\';\n\n// Instantiate View Model hierarchy using map()\nvar people = myVmCollection.Person.map(peopleData);\n\n// Render template against people (array of Person instances)\n$("#result").html(tmpl.render(people));\n\n// Button handlers\n$("#update").on("click", function() {\n people.merge(peopleData2);\n $("#result").html(tmpl.render(people));\n});\n\n$("#revert").on("click", function() {\n people.merge(peopleData);\n $("#result").html(tmpl.render(people));\n});\n\n$("#changeName").on("click", function() {\n people[0].name("newName");\n $("#result").html(tmpl.render(people));\n});\n\n$("#addPhone").on("click", function() {\n people[0].addPhone("xxx xxx xxxx");\n $("#result").html(tmpl.render(people));\n});\n\n$("#result").on("change", ".comment", function(val) {\n // If comment is modified, update View Model state with new value\n people[this.getAttribute("data-index")].comment(this.value);\n});\n\n$("#getData").on("click", function() {\n var updatedPeopleData = people.unmap();\n window.alert(JSON.stringify(updatedPeopleData));\n});\n',html:'\n\n\n\n
    \n\n\n\n
    \n\n',height:"350",jsrJsvJqui:"jsr",anchor:"",title:"Mapping from JSON data to View Model hierarchy – further features"},{_type:"para",title:"Adding a custom get/set property to a compiled View Model ",text:"Finally, here is a sample which extends a compiled *View Model* with a custom `Person.isManager() `*get/set* property. The property is coupled to the `Team.manager()` property -- so setting `Person.isManager(...)` will update the `Team.manager()` correspondingly (and conversely when setting `Team.manager(...)`.\n\n`Person.isManager` is not included in the `getters` declaration, so that the constructor for `Person` will not expect an `isManager` parameter to be provided for initialization.\n\n(See also the [related sample](#jsvviewmodelsapi@ismanagersample) using JsViews and data-linking.)",anchor:"ismanagersample"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Custom function for Person.isManager get/set property\nfunction myIsManager(val) {\n if (!arguments.length) {\n return this === team.manager(); // If there is no argument, use as a getter\n }\n if (val) {\n // Make this team member manager\n team.manager(this);\n } else if (this.isManager()) {\n // Set team manager to null\n team.manager(null);\n }\n}\n\n// Compile View Models\n$.views.viewModels({\n Team: {...},\n Person: {\n getters: [\n "name",\n ...\n ],\n extend: {\n isManager: myIsManager // use custom function\n }\n },\n Address: {...}\n});\n\n...\n\n//Initialize second team member to be manager.\nvar manager = team.members()[1];\nmanager.isManager(true);\n\n...\n\n// Attach handler for checkbox\n$("#result")\n .on("change", ".isManager", function() {\n ...\n member.isManager(this.checked);\n renderTemplate(); // Refresh rendering, with modified data\n })\n ...\n```'}],html:'
    \n\n',code:'// Compile template\nvar tmpl = $.templates("#teamTmpl");\n\n// Custom function for Person.isManager get/set property\nfunction myIsManager(val) {\n if (!arguments.length) {\n return this === team.manager(); // If there is no argument, use as a getter\n }\n if (val) {\n // Setting this.isManager() to true\n // So make this team member manager\n team.manager(this);\n } else if (this.isManager()) {\n // Setting this.isManager to false, and this team member is currently manager.\n // So set team manager to null\n team.manager(null);\n }\n}\n\n// Compile View Models\n$.views.viewModels({\n Team: {\n getters: [\n {\n getter: "manager",\n type: "Person"\n },\n {\n getter: "members",\n type: "Person"\n }\n ]\n },\n Person: {\n getters: [\n "name",\n {\n getter: "address",\n type: "Address"\n }\n ],\n extend: {\n isManager: myIsManager // use custom function\n }\n },\n Address: {\n getters: ["street", "ZIP"]\n }\n});\n\n// Initial data \nvar teamData = {\n manager: null,\n members: [{\n name: "Pete",\n address: {\n street: "1st Ave",\n ZIP: "12345"\n }\n },{\n name: "Bess",\n address: {\n street: "Central Way",\n ZIP: "98765"\n }\n },\n {\n name: "Henry",\n address: {\n street: "Main St",\n ZIP: "54321"\n }\n }]\n };\n\n// Instantiate View Models\nvar team = $.views.viewModels.Team.map(teamData);\n\n//Initialize second team member to be manager.\nvar manager = team.members()[1];\nmanager.isManager(true);\n\nfunction renderTemplate() {\n // Refresh template rendering completely\n $("#result").html(tmpl.render(team));\n}\n\nrenderTemplate();\n\n// Attach handlers for checkbox and buttons\n$("#result")\n .on("change", ".isManager", function() {\n var memberIndex = $(this).data("index"),\n member = team.members()[memberIndex];\n member.isManager(this.checked);\n renderTemplate(); // Refresh rendering, with modified data\n })\n .on("click", ".changeManager", function() {\n var memberIndex = $(this).data("index"),\n member = team.members()[memberIndex];\n member.isManager(true);\n renderTemplate(); // Refresh rendering, with modified data\n })\n .on("click", ".noManager", function() {\n team.manager(null);\n renderTemplate(); // Refresh rendering, with modified data\n }\n);',title:"Sample: extending Person with an isManager property",height:"294",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsvviewmodelsapi",label:"Compiled View Models (JsViews)"}]}]},lifecycle:{title:"Life-cycle events",path:"",sections:[{_type:"para",title:"",text:"paragraph"}]},globals:{title:"globals",path:"",sections:[{_type:"para",title:"",text:"JsRender\n\n- render()\n- templates()\n- views\n\nJsViews\n\n- link()\n- observe()\n- observable()\n- unlink()\n- unobserved()\n- view()\n\n"}]},tagsapi:{title:"Registering custom tags: $.views.tags()",path:"",sections:[{_type:"para",title:"",text:"`$.views.tags()` is used to register custom tags. See *[Using custom tags](#tags)* for an overview, and simple examples.\n\nThis topic provides more details."},{_type:"para",title:"What is a custom tag?",text:"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\n\nA custom tag can optionally use arguments (*args*) and named parameters (*props*), [as in](#tagsyntax@tagparams):\n\n```jsr\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\n```\n\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. "},{_type:"para",title:"Specifying tag options for a custom tag",text:'The following tag declaration registers a `{{mytag}}` custom tag:\n\n```js\n$.views.tags("mytag", tagOptions);\n```\n\nThe `tagOptions` object (hash) specifies the tag options and determines how the tag will function. It can include:\n\n- An [init()](#tagsapi@init) method: `init: tagInitFn`\n- A [render()](#tagsapi@render) method: `render: tagRenderFn`\n- A [template](#tagsapi@template): `template: tagTemplate`\n\nIn addition `tagOptions` can specify tag inheritance (so that the custom tag derives from a base tag):\n\n- [`baseTag: ...`](#tagsapi@basetag)\n\nIt can also specify the following more advanced options:\n\n- [`contentCtx: ...`](#tagsapi@contentctx)\n- [`convert: ...`](#tagsapi@convert)\n- [`argDefault: ...`](#tagsapi@argdefault)\n- [`bindTo: ...` / `bindFrom: ...`](#tagsapi@bindto)\n- [`flow: ...`](#tagsapi@flow)\n- [`ctx: ...`](#tagsapi@ctx)\n'},{_type:"para",title:"Registering custom tags: $.views.tags(...)",text:'To register a custom tag, you call the `$.views.tags(...)` API.\n\nThere are four alternative signatures:\n\n- `$.views.tags("mytag", tagOptions);` -- where the properties of the `tagOptions` object will typically include a `render: tagRenderFn` (specifying a render() method), and/or a `template: tagTemplate` (specifying a template to be rendered)\n- `$.views.tags("mytag", tagRenderFn);` -- simplified form, when the only option being specified is a render() method\n- `$.views.tags("mytag", tagTemplate);` -- simplified form, when the only option being specified is a tag template to be rendered\n- `$.views.tags(namedTags);` This version is for declaring multiple custom tags, and `namedTags` is a hash (with custom tag names as keys and `tagOption` objects as values)\n\nHere are the details:',anchor:"register"},{_type:"api",typeLabel:"API:",title:"$.views.tags(...)",name:"tags",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagOptions",type:"object",optional:!1,description:"A tagOptions object with a render() method and/or a template property, and optionally other properties or methods"}],args:[],sections:[],example:'$.views.tags("mytag", {\n render: function(...) {...},\n template: ...\n});\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a custom tag, specifying chosen tag options",returns:"Compiled tag object"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagRenderFn",type:"function",optional:!1,description:"Tag render() method. Returns the rendered tag"}],args:[],sections:[],example:'$.views.tags("mytag", function(...) {\n ...return rendered content\n});\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a simple 'render' function as a custom tag",returns:"Compiled tag object"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagTemplate",type:"object or string",optional:!1,description:"A string containing template markup to be rendered by the tag (or a selector for a script block template definition, or a compiled template object)"}],args:[],sections:[],example:'$.views.tags("mytag", "templateMarkup...");\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a template as a custom tag",returns:"Compiled tag object"},{_type:"signature",title:"",params:[{_type:"param",name:"namedTags",type:"object",optional:!1,description:"Object (hash) of keys (name of tag) and values (render function, template, or tagOptions object)"}],args:[],sections:[],example:"$.views.tags({\n mytag1: {\n render: function(val) {...},\n template: ...\n },\n mytag2: function(val) {...},\n mytag3: tag3TemplateString,\n});",description:"Register multiple custom tags",returns:""}],description:"Register one or more custom tags",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:'For simple samples showing the above alternative `$.views.tags(...)` signatures, see the [*Using custom tags*](#tags) overview topic:\n\n- [A custom tag using just a render() method](#tags@render-sample)\n- [A custom tag using just a template](#tags@template-sample)\n- [Accessing context within the render() method](#tags@context-sample)\n- [Accessing context from the tag template](#tags@tmplcontext-sample)\n\nThe [*Using custom tags*](#tags) overview also provides samples of custom tags which render block content -- `{{mytag}}...{{/mytag}}`:\n\n- [Rendering block content from a custom tag render() method](#tags@renderblock-sample)\n- [Rendering block content from a custom tag template](#tags@tmplblock-sample)\n- [A {{runningTotal}} custom tag, using a render() method](#tags@runningtotal-sample)\n- [A {{runningTotal}} custom tag, with render() method and a template as "fallback"](#tags@renderplustmpl-sample)',anchor:""},{_type:"para",title:'Custom tag options: Specifying init(), render(), template, baseTag:',text:"A custom tag in JsRender has a very simple *'life-cyle'* consisting of two events for which you can optionally provide event handlers: the `init()` event, followed by the `render()` event. (If the custom tag is used in the context of JsViews, additional lifecycle events will also come into play, for data-binding, disposal, etc.)",anchor:"options"},{_type:"para",title:"Providing an init() method",text:'The *init()* method acts as a handler for the *init* event of the custom tag, and is called with the tag instance as `this` parameter.\n\n```js\n$.views.tags("mytag", {\n init: function(tagCtx, linkCtx, ctx) { ... },\n ...\n});\n``` \n\nThe *init()* method arguments are:\n- `tagCtx`: the [tagCtx object](#tagcontextobject), also available as `this.tagCtx`\n- `linkCtx`: always 0 unless using [data-linked tags](#linked-tag-syntax) with *JsViews* (See [linkCtx object](#linkctxobject).)\n- `ctx`: [View context object](#ctxobject)\n\nThe following example uses the *init()* method to set the tag template based on the value of the `mode` prop:',anchor:"init"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Tag declaration:*\n\n```js\n$.views.tags("mytag", {\n init: function(tagCtx) {\n this.template = tagCtx.props.mode === "a"\n ? "template A ..."\n : "template B ...";\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{mytag name mode=\'a\' /}}\n{{mytag name mode=\'b\' /}}\n```'}],html:'\n\n
    \n\n',code:'$.views.tags("mytag", {\n init: function(tagCtx) {\n this.template = tagCtx.props.mode === "a"\n ? "template A: {{:}} aaa
    "\n : "template B: {{:}} bbb
    ";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render({name: "Jo"});\n\n$("#page").html(html);',jsrJsvJqui:"jsr",height:"60",anchor:"initsample",title:"Providing init()"},{_type:"para",title:"Providing a render() method",text:'The *render()* method acts as a handler for the *render* event of the custom tag, and is called with the tag instance as `this` parameter, and with arguments `arg1, arg2, ...`, corresponding to the unnamed arguments passed in the tag markup, `{{mytag expression1 expression2 ... }}`.\n\nIf no arguments are passed in the markup, then the `render()` method will be called with the current data context as argument (unless modified by the [argDefault](#tagsapi@argdefault) option.)\n\n```js\n$.views.tags("mytag", {\n render: function(value1, value2) { ... return ...; },\n ...\n});\n```\n\nThe *render()* method can optionally be used to define how the tag renders, by returning an HTML markup string.\n\nSee the example: [*A custom tag using just a render() method*](#tags@render-sample).\n',anchor:"render"},{_type:"para",title:"Providing a template",text:"The *template* option is used for declarative rendering, as an alternative to providing a *render()* method.\n\nSee the example: [*A custom tag using just a template*](#tags@template-sample).\n",anchor:"template"},{_type:"para",title:"Data context of a tag template",text:"If the custom tag is called with an argument: `{{mytag someArgument ...}}` then the template will be rendered using the value of that argument as data context.\n\nOtherwise, the data context will be the same as the outer data context.\n\n(*Note:* This behavior can be changed using [contentCtx](#tagsapi@contentctx)) \n"},{_type:"para",title:"Using both a template and a render() method",text:'If the tag has both a *render()* method and a *template*, then the *render()* method is used to render the tag. But if *render()* returns `undefined` (or has no return value), then the *template* is used. \n\nSee example: [*A {{runningTotal}} custom tag, with render() method and a template as "fallback"*](#tags@renderplustmpl-sample).\n\nIt is also possible to provide both a *template* and a *render()* method, and to make use of the rendered template within the content returned by the render method. (In fact `this.tagCtx.render(...)` will return the rendered template). ',anchor:"tmpl-fallback"},{_type:"para",title:"Specifying tag inheritance: the baseTag option",text:'A custom tag can inherit from another tag (either built-in or custom).\n\nFor example the `{{runningTotal}}` sample, linked above, can be rewritten in a more powerful but compact form, by making it inherit from the `{{for}}` tag (since the functionality of iterating over an array is common to both).\n\nTo inherit from another tag, set the `baseTag` option to the name of the tag you want to derive from (or to the compiled tag object):\n\n```js\n$.views.tags("runningTotal", {\n baseTag: "for",\n ...\n});\n```\n\nCustom tag methods (*init()* or *render()*) can invoke the corresponding base tag method by calling one of the following API variants:\n\n```js\nthis.base(a, b, ...); // Pass chosen arguments\nthis.baseApply(arguments); // Pass on the calling arguments (or an array of args)\n```\n\nThis is illustrated in the following sample, which takes the *Providing init()* [sample](#tagsapi@initsample) above, and defines a derived `{{mytag2}}` which overrides *init()* and adds an error message when no valid `mode` was specified:\n',anchor:"basetag"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"*Tag declaration:*\n\n```js\n$.views.tags(\"mytag2\", {\n baseTag: \"mytag\",\n init: function() { // Override the init() method\n this.baseApply(arguments); // Call the base method\n this.template = this.template || \"Error: Specify mode 'a' or 'b'\"; // If no template was assigned, render error message\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{mytag2 name mode='a' /}}\n{{mytag2 name mode='b' /}}\n{{mytag2 name /}}\n```"}],html:'\n\n
    \n\n',code:'$.views.tags("mytag", {\n init: function(tagCtx) {\n this.templates = {\n a: "template A: {{:}} aaa
    ",\n b: "template B: {{:}} bbb
    "\n }; \n this.template = this.templates[tagCtx.props.mode];\n }\n});\n\n$.views.tags("mytag2", {\n baseTag: "mytag",\n init: function() { // Override the init() method\n this.baseApply(arguments); // Call the base method\n // If no template was assigned, render error message\n this.template = this.template || "Error: Specify mode \'a\' or \'b\'";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render({name: "Jo"});\n\n$("#page").html(html);',jsrJsvJqui:"jsr",height:"75",anchor:"basetagsample",title:"baseTag"},{_type:"para",title:"",text:"The previous `{{runningTotal}}` [sample](#tags@renderplustmpl-sample) was relatively complex. Here is an updated version rewritten to derive from `{{for}}`:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'This version is much simpler and supports sorting, filtering, etc. as well as `start=... end=... step=...`, without any additional code (thanks to the inherited features of `{{for}}`).\n\nAlso the fallback rendering for *No line items* is no longer hard-coded in the tag, but instead uses the `{{runningTotal}}...{{else}}...` pattern.\n\nNote that `~total()` is a function. The call to `~total()` increments the value and returns the running total.\n\n*Tag declaration:*\n\n```js\n$.views.tags("runningTotal", {\n baseTag: "for",\n ctx: {\n total: function() { // A ~total() helper (now a function)\n ...\n tag.totalVal += this.data[totalCol]; // Compute running total\n return tag.totalValue; // Return value from ~total()\n }\n },\n render: function() {\n this.totalVal = 0; // Initialize total before rendering\n return this.baseApply(arguments); // Render\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{runningTotal lineItems start=1 end=4 totalColumn="quantity"}} \n ...{{:~total()}}...\n{{else}}\n ...No line items...\n{{/runningTotal}}\n```\n'}],jsrJsvJqui:"jsr",height:"244",title:"A {{runningTotal}} custom tag derived from {{for}}",header:"",action:"append",html:'
    \n\n',code:'$.views.tags("runningTotal", {\n baseTag: "for",\n ctx: {\n total: function() { // A ~total() helper (now a function)\n var tag = this.ctx.tag,\n totalCol = tag.tagCtx.props.totalColumn\n tag.totalVal += this.data[totalCol]; // Compute running total\n return tag.totalVal; // Return value from ~total()\n }\n },\n render: function() {\n this.totalVal = 0; // Initialize total before rendering\n return this.baseApply(arguments); // Render\n }\n});\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ],\n lineItems2: []\n};\n\nvar html = $("#myTmpl").render(data, {\n category: function(item, index, items) {\n return item.category === this.props.category;\n }\n});\n\n$("#lineItems").html(html);',anchor:"derivedfor"},{_type:"para",title:"",text:"Our `{{runningTotal}}` [samples](#tagsapi@derivedfor) so far have initialized the running total to `0` in the render method, and then relied on the rendering process to do the incrementing of the running total. This approach would fail if the rendering sequence was changed for any reason.\n\nThe sample below takes the `{{runningTotal}}` tag above, and converts it to a more complete and more powerful \n `{{purchases}}` tag, again deriving from the `{{for}}` tag. The `{{purchases}}` tag, which is more flexible and more robust, and supports any number of running total columns.\n\nThe `~total(expression)` helper function now allows you to provide any expression as parameter. Here, running total values are recomputed for each line, separately, so no longer depend on the render processing sequence:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'The `~total(expr)` helper function now accepts an *expression* parameter for each running total -- to be used to compute the incremental amount for each row.\n\n*Tag declaration:*\n\n```js\n$.views.tags("purchases", {\n baseTag: "for",\n ctx: {\n total: function(expr) { // A ~total(expression) helper\n var tmpl = $.templates[expr] // Get named compiled template for expression, or else...\n || $.templates(expr, "{{:" + expr + "}}"), // ...if this is first call, create it\n\n runningTotal = 0,\n view = this, // The content view with the ~total(...) helper call\n items = view.get("array").data,\n rowIndex = view.getIndex();\n\n for (var i = 0; i <= rowIndex; i++) {\n runningTotal += +tmpl(items[i]); // Compute running total up to this row, using render function\n } // of compiled tmpl (either tmpl() or tmpl.render()...)\n return runningTotal; // Return value from ~total(...)\n }\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{purchases lineItems sort="category" ...}} \n ...{{:~total(\'quantity*price\')}}...\n{{else}}\n ...No items...\n{{/purchases}}\n```\n'}],header:"",action:"append",html:"",code:"",jsrJsvJqui:"jsr",height:"550",url:"samples/jsrender/tags/extend-for/sample",title:"A {{purchases}} tag supporting totals for any expression",anchor:"totals-expr"},{_type:"para",title:"",text:"The above `{{purchases}}` custom tag can be easily updated to support data-binding. See [purchases sample](#samples/tag-controls/purchases@jsv)."},{_type:"para",title:'Tag context',text:"When a custom tag is used in a template then the rendered template instance will be part of the [view hierarchy](#views).\n\nThe instance of the tag is an object with properties and methods:\n\n- [tag object](#tagobject)\n\nAssociated with the tag instance is a [tag context object](#tagcontextobject), `tagCtx`, providing most of the useful context for a tag, in particular:\n\n- context passed down through the view hierarchy:\n\n - current view\n - current data\n - parent tags\n - contextual parameters\n\n- additional context coming from the tag itself, or its markup:\n\n - arguments (*args*) and named parameters (*props*)\n - rendered tag template\n - block content\n - content of else blocks\n",anchor:"context"},{_type:"para",title:"Accessing the tag instance object",text:"From a tag method (*init()* or *render()*), the `this` pointer is the instance of the tag (a [tag object](#tagobject).)\n\nFrom a tag template, the tag instance can be accessed as `~tag`.\n"},{_type:"para",title:"Accessing the tag context object: tagCtx",text:"From a tag method the `tagCtx` object is available as `this.tagCtx`.\n\nIn the [*init()*](#tagsapi@render) method it is also passed directly as an argument (`function(tagCtx ...)`).\n\nFrom a tag template, `tagCtx` can be accessed as `~tag.tagCtx`.\n"},{_type:"para",title:"Accessing the tag arguments or named parameters",text:'The values of arguments can be accessed as `tagCtx.args`, and named parameters as `tagCtx.props`.\n\nFor example, if we have the following tag, which has two arguments and one named parameter:\n\n```jsr\n{{sometag title name mode="edit"}}\n```\n\nthen from within the *init()* or *render()* method of `sometag`, the arguments and named parameters can be accessed as:\n\n```js\nvar title = this.tagCtx.args[0];\nvar name = this.tagCtx.args[1];\nvar mode = this.tagCtx.props.mode;\n```\n\nand from the tag template, the values can be accessed as `~tagCtx.args` or `~tagCtx.props`, and so might be rendered as: \n\n```jsr\n...title: {{>~tagCtx.args[0]}}
    name: {{>~tagCtx.args[1]}}
    mode: {{>~tagCtx.props.mode}}...\n```\n\nIn addition to being available as `tagCtx.args`, arguments are also passed directly as arguments to the *render()* method, so `sometag` might use the following *render()* method, rather than a template, to render similar content:\n\n```js\nfunction sometagRenderMethod(title, name) {\n return "...title: " + title + "
    name: " + name + "
    mode: " + this.tagCtx.props.mode ...;\n}\n```\n\nThe `tagCtx` object also provides access to the markup expression for arguments and named parameters, as `tagCtx.params.args` and `tagCtx.params.props`.' -},{_type:"para",title:"Accessing the parent view and the current data",text:"The contextual (parent) view for the tag instance is accessed as `tagCtx.view`. The corresponding (parent) data context is `tagCtx.view.data`."},{_type:"para",title:'Custom tag child views',text:" ",anchor:"childviews"},{_type:"para",title:'Custom tag rendering with template: "mytag" child view',text:'A custom tag template instance will be part of the [view hierarchy](#views), and the rendered tag may add additional child views to the view hierarchy.\n\nIf `{{mytag members}}` renders using its *template*, that template will render as a child view (of type `"mytag"`). The default data context within the *template* will be the first argument passed to the tag (`members` in this case) which will be the `view.data` property of the child view.\n\nIf the *template* markup includes template tags (other custom tags, or built-in tags) then there will be corresponding additional child views below the *mytag* view. \n\n'},{_type:"para",title:"Rendering wrapped block content",text:'- Any tag can wrap [block content](#tagsyntax@blocktag), or use `tmpl=...` to reference external content:\n ```jsr\n {{mytag}}...{{/mytag}}\n\n {{mytag tmpl=... /}}\n ```\n- By default, a custom tag with no *render()* method or tag template will render its block content unchanged. A tag with an argument will move data context to the data passed in the argument: `{{mytag somedata ...}}`.\n- For a custom tag rendering using a *render()* method, wrapped block content can be included using `tagCtx.render()`.

    *Note:* To set the inner data context, pass in data as argument: `tagCtx.render(someData)`. Otherwise inner and outer data context are the same.\n ```js\n $.views.tags("mytag", {\n ...\n render: function() {\n return ... + this.tagCtx.render() + ...;\n },\n ...\n });\n ```\n See the sample: [*Rendering block content from a custom tag render() method*](#tags@renderblock-sample).

    \n (For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See the [template as fallback](#tags@tmpl-fallback) sample).

    \n- For a custom tag rendering using a tag template, wrapped block content can be included using:\n ```jsr\n {{include tmpl=#content/}}\n ```\n or equivalently:\n ```jsr\n {{include tmpl=~tagCtx.content/}}\n ```\n where in each case the inner data context can be modified by passing an argument, `{{include someData tmpl=... /}}`.\n See the sample: [*Rendering block content from a custom tag template*](#tags@tmplblock-sample).\n\nNote that if a custom tag has an external `tmpl=...` reference, **_and_** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (see: [*Wrapping content*](#tagsyntax@wrap)).\n\nThis can provide for cascading content, as in the following sample:\n\n```jsr',anchor:"wrapping"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.tags("mytag", {\n template: "mytagStart...{{include tmpl=#content/}}.../mytagEnd"\n});\n```\n```jsr\n{{mytag tmpl=\'#external\'}}wrappedContent{{/mytag}}\n```\n\n```jsr\n\n\n```'}],jsrJsvJqui:"jsr",html:'\n\n\n\n
    \n',code:'$.views.tags("mytag", {\n template: "mytagStart
    {{include tmpl=#content/}}
    /mytagEnd"\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = {},\n html = myTmpl.render(data);\n\n$("#page").html(html);',height:"106",title:"Cascading content"},{_type:"para",title:'Rendering else blocks',text:"Any tag can use [`{{else}}`](#elsetag) blocks. We might for example create a custom tag for rendering lists:\n\n```jsr\n{{list}}\n First item\n{{else}}\n Second item\n{{else}}\n Last item\n{{/list}}\n```\n\nA custom tag can provide specific behavior/rendering for `{{else}}` blocks:\n\n- For a tag with a render method, *render()* will be called once for the initial block and once for each `{{else}}` block.\n- Similarly, for a custom tag with a tag template, the template will be rendered once for the initial block and once for each `{{else}}` block.\n- During rendering a custom tag can detect which block is being rendered, using `tagCtx.index` (see below), and can then output the content corresponding to the desired functionality.\n",anchor:"elseblocks"},{_type:"para",title:"Tag context objects for {{else}} blocks: the tagCtxs array",text:"A tag with multiple blocks (initial block plus 1 or more `{{else}}` blocks) will have a `tagCtxs` array of `tagCtx` objects, one for each block.\n\n- From a tag method the `tagCtxs` array is available as `this.tagCtxs`.\n- From a tag template, `tagCtxs` can be accessed as `~tag.tagCtxs`.\n\nEach `tagCtx` object in `tagCtxs` has an `index` property (`0` for the initial block), as well as the other properties (`args`, `props` etc.) corresponding to the markup (arguments, named properties...) on the corresponding tag (`{{mytag ...}}` or `{{else ...}}`).\n\n- Within a tag *render()* method, `this.tagCtx` will be the current tag context object for that block.\n- Similarly, during rendering of the tag template, `~tag.tagCtx` will be the current `tagCtx`.\n\nTo determine the index of the block being rendered, use `tagCtx.index`. \n\nThese features are illustrated in the following sample:",anchor:"tagctxs"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Custom `{{list}}` tag:*\n\n```js\n$.views.tags("list", function() {\n // render() method\n var ret = "", // Return value\n index = this.tagCtx.index, // block index\n listElem = this.tagCtxs[0].props.numbered ? "ol" : "ul"; // Wrapper
      or
        element, based on numbered=true property \n\n if (index===0) {\n ret += "<" + listElem + ">"; // First block: add opening wrapper\n }\n ret += "
      • " + this.tagCtx.render() + "
      • "; // Add li element and block content\n if (index===this.tagCtxs.length-1) {\n ret += ""; // Last block: add closing wrapper\n }\n return ret;\n});\n```\n\n*Usage*:\n\n```jsr\n{{list numbered=true}}First{{else}}Second{{else}}Last{{/list}}\n{{list}}first{{else}}last{{/list}}\n```'}],jsrJsvJqui:"jsr",code:'// Define custom {{list}} tag\n$.views.tags("list", function() {\n // render() method\n var ret = "", // Return value\n index = this.tagCtx.index, // block index\n listElem = this.tagCtxs[0].props.numbered ? "ol" : "ul"; // Wrapper
          or
            element, based on numbered=true property \n\n if (index===0) {\n ret += "<" + listElem + ">"; // First block: add opening wrapper\n }\n ret += "
          • " + this.tagCtx.render() + "
          • "; // Add li element and block content\n if (index===this.tagCtxs.length-1) {\n ret += ""; // Last block: add closing wrapper\n }\n return ret;\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render();\n\n$("#page").html(html);\n',html:'\n\n
            \n\n',height:"130",title:"Custom {{list}} tag using {{else}} blocks"},{_type:"para",title:"",text:"And here is a version of the sample with the same tag implemented using a tag template, rather than a *render()* method.\n\nHere we use the *init()* method to assign a tag template dynamically, using a different wrapper (`ol` or `ul`) based on the `numbered` named property:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Custom `{{list}}` tag:*\n \n```js\n$.views.tags("list", {\n init: function() {\n var listElem = this.tagCtx.props.numbered ? \'ol\' : \'ul\'; // Wrapper ol or ul element\n this.template = \n // First block: add opening wrapper\n "{{if ~tagCtx.index===0}}<" + listElem + ">{{/if}}"\n // Add li element and block content\n + "
          • {{include tmpl=#content/}}
          • "\n // Last block: add closing wrapper\n + "{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}";\n }\n});\n```'}],jsrJsvJqui:"jsr",height:"130",title:"Custom {{list}} tag: Rendering {{else}} blocks from a tag template",html:'\n\n
            \n\n',code:'// Define custom {{list}} tag\n$.views.tags("list", {\n init: function() {\n var listElem = this.tagCtx.props.numbered ? \'ol\' : \'ul\'; // Wrapper ol or ul element\n this.template = \n // First block: add opening wrapper\n "{{if ~tagCtx.index===0}}<" + listElem + ">{{/if}}"\n // Add li element and block content\n + "
          • {{include tmpl=#content/}}
          • "\n // Last block: add closing wrapper\n + "{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render();\n\n$("#page").html(html);\n'},{_type:"para",title:"",text:"Custom tags with no *render()* method and no tag template can also render multiple blocks, using `{{else}}`. Here is an example:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'Custom `{{mytag}}` which simply renders each block as is:\n\n```js\n$.views.tags("mytag", {});\n```\n\nThe default data context of each block is the value passed to the first argument.\n\n```jsr\n{{mytag last}}\n First: {{:}}...\n{{else first}}\n ...\n{{else phone}}\n ...\n{{/mytag}}\n```\n'}],jsrJsvJqui:"jsr",html:'\n\n
            \n\n',code:'// Define custom {{mytag}} tag\n$.views.tags("mytag", {});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = {first: "Jo", last: "Blow", phone: "111-111-1111"},\n html = myTmpl.render(data);\n\n$("#page").html(html);\n\n',title:"Default behavior for custom tag with {{else}} blocks",height:"72"},{_type:"para",title:'Custom tag hierarchy – Accessing parent tags',text:"Nested custom tags can determine parent tags, and can be designed with functionality or rendering that is based on parent or child tags, as in the following example where a `{{layout}}` tag determines the layout for child `{{cell}}` tags:\n",anchor:"parents"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{layout 'vertical'}}\n {{cell}}one{{/cell}}\n {{cell}}two{{/cell}}\n{{/layout}}\n
            \n{{layout 'horizontal'}}\n {{cell}}one{{/cell}}\n {{cell}}two{{/cell}}\n{{/layout}}\n```\n"}],jsrJsvJqui:"jsr",html:'\n\n
            ',code:'$.views.tags({\n layout: {\n render: function(mode) {\n if (mode === "vertical") {\n this.vertical = true;\n return "" + this.tagCtx.render() + "
            ";\n } else {\n return "" + this.tagCtx.render() + "
            ";\n }\n }\n },\n cell: {\n render: function() {\n return this.parents.layout.vertical\n ? "" + this.tagCtx.render() + ""\n : "" + this.tagCtx.render() + "";\n }\n }\n})\n\nvar myTmpl = $.templates("#myTmpl"),\n data = { name: "Jo" },\n html = myTmpl.render(data);\n\n$("#page").html(html);',height:"140",header:""},{_type:"para",title:"",text:'The following properties provide access to ancestor custom tags:\n\n**parents property:**\n\nThe `parents` property is a hash of all the ancestor custom tags. In the above sample the `{{cell}}` instances have a `parents.layout` property, used to determine whether the assigned layout is vertical, and to render accordingly:\n\n```js\nrender: function() {\n return this.parents.layout.vertical\n ? "" + this.tagCtx.render() + ""\n : "" + this.tagCtx.render() + "";\n}\n```\n\n**parent property:**\n\nThe tag instance also has a `parent` property - in the above sample, the `parent` of the `{{cell}}` instance is the `{{layout}} instance`.\n\n**~parentTags contextual parameter:**\n\nThe `ctx` property of a tag instance also has a `parentTags` property, equivalent to the `parents` hash. This can be used in the following alternative implementation of the `{{cell}}` tag above, using a tag template rather than a *render()* method:\n\n```js\n$.view.tags("cell", {\n template:\n "{{if ~parentTags.layout.vertical}}{{include tmpl=#content/}}"\n + "{{else}}{{include tmpl=#content/}}{{/if}}"\n});\n```\n\nIn fact, in a tag template `~parentTags` and `~tag.parents` are equivalent.'},{_type:"para",title:'Accessing contextual parameters and helpers',text:'- From a tag template:\n - Contextual parameters and helpers can be accessed using `~myParamOrHelper`\n- From a tag method:\n - Contextual parameters and helpers can be accessed using `this.ctxPrm("myParamOrHelper")`\n - (Note: contextual parameters can also be accessed using `this.ctx.myParamOrHelper`, and global helpers can be accessed using `$views.helpers("myHelper")`)\n\nAs an advanced example of custom tag rendering based on contextual parameters, here is a modified version of the above *layout* sample, where instead of wrapping `{{cell}}` tags in a `{{layout}}` tag, we instead wrap in a simple `{{include}}` on which we set a contextual parameter specifying layout: `layout=\'vertical\'`:',anchor:"ctxparams"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{include ~layout='vertical'}}\n {{cell}}one{{/cell}}\n {{cell last=true}}two{{/cell}}\n{{/include}}\n
            \n{{include ~layout='horizontal'}}\n {{cell}}one{{/cell}}\n {{cell last=true}}two{{/cell}}\n{{/include}}\n```\n"}],jsrJsvJqui:"jsr",html:'\n\n
            ',code:'$.views.tags({\n cell: {\n render: function() {\n var res = "",\n vertical = this.ctxPrm("layout") === "vertical",\n parentView = this.tagCtx.view.parent,\n cellIndex = parentView.cellIndex = parentView.cellIndex === undefined ? 0 : parentView.cellIndex +1;\n if (vertical) {\n if (cellIndex===0) {\n res += "";\n }\n res += "";\n if (this.tagCtx.props.last) {\n res += "
            " + this.tagCtx.render() + "
            ";\n }\n } else {\n if (cellIndex===0) {\n res += "
            ";\n }\n res += "";\n if (this.tagCtx.props.last) {\n res += "
            " + this.tagCtx.render() + "
            ";\n }\n }\n return res;\n }\n }\n})\n\nvar myTmpl = $.templates("#myTmpl"),\n data = { name: "Jo" },\n html = myTmpl.render(data);\n\n$("#page").html(html);',header:"",height:"140"},{_type:"para",title:"",text:"### Advanced options"},{_type:"para",title:"Specifying data context within tag content: the contentCtx option",text:'*__Default behavior:__*\n\nBy default the data context within the tag is the value of the first argument. (See [View hierarchy -- inner data context](#views@innerdata)).\n\nSo if `{{mytag}}` uses a `template` then `{{mytag members/}}` will render the template with `members` as data context. \n\nSimilarly if `{{mytag}}` is used as a block tag, then the block content within `{{mytag members}}...{{/mytag}}` will render with `members` as data context.\n\n*__Modified behavior:__*\n\nTo make the data context for tag content the same as parent context, set the `contentCtx` option to `true`:\n\n```js\n$.views.tags("mytag", {\n ...\n contentCtx: true, // The data context inside {{mytag}} will be the same as the outer context\n ...\n});\n```\n\nTo specify a different data context for tag content, set the `contentCtx` option to a function returning the chosen data. (The `this` pointer of the `contentCtx` function is the tag instance. The default data context, `arg0` is passed to it as argument.) \n\nFor example, with the following tag option setting, the inner data context is given by the `dataCtx` named property:\n\n```js\n$.views.tags("mytag", {\n ...\n contentCtx: function(arg0) {\n return this.tagCtx.props.dataCtx; // The returned value will be the data context inside {{mytag}}\n },\n ...\n});\n```\n\nUsage:\n\n```jsr\n{{mytag ... dataCtx=.../}}\n``` ',anchor:"contentctx"},{_type:"para",title:"Providing a default converter: the convert option",text:"On any tag, including custom tags, a converter can be specified directly on the tag (see [*Using converters with other tags*](#converters@othertags)):\n\n```jsr\n{{mytag name convert='toUpperCase'/}}\n```\n\nTo provide a default converter on a custom tag (used as fallback if no converter is specified on the tag), set the `convert` tag option to a function, or to a registered converter name:\n\n```js\n$.views.tags(\"mytag\", {\n ...\n convert: 'toLowerCase', // Default converter. (A function or a registered converter name)\n ...\n});\n```\n\n\n\n",anchor:"convert"},{_type:"para",title:"Specifying a default argument: the argDefault option",text:'If a custom tag uses a *render()* method, then the arguments of the tag are passed to the render method:\n\n```jsr\n{{mytag arg0 arg1/}}\n```\n\n```js\n$.views.tags("mytag", {\n render: function(arg0, arg1) {...}\n});\n```\n\nIf the tag is called without arguments, then the render method will be called with the current data context as first argument, so therefore writing `{{mytag/}}` is equivalent to writing `{{mytag #data/}}` \n\nTo override this behavior, set the `argDefault` option to `false`. The first argument will then not default to current data, and the render method will instead be called without arguments.\n\n```jsr\n{{mytag/}}\n```\n\n```js\n$.views.tags("mytag", {\n render: function() {\n // arguments.length is 0\n },\n argDefault: false\n});\n```\n',anchor:"argdefault"},{_type:"para",title:"Specifying bound arguments and properties: the bindTo and bindFrom options",text:'The `bindTo` and `bindFrom` options are designed primarily for use with data binding, with JsViews, and allow specifying which arguments/properties are data-bound for two-way binding.\n\nIn JsRender, the `bindTo` or `bindFrom` option can be used in conjunction with converters. Set the `bindFrom` option (or the `bindTo` option if there is no `bindFrom` setting) to an array, such as `[0, 1, 2]`, or `["title", 1]` -- where integers refer to arguments and strings to named properties -- to determine what values are passed to the converter. (If neither `bindFrom` nor `bindTo` are set, then the values of all the [arguments](#tagsyntax@tagparams) will be passed to the converter.)\n\nBy default the value returned by the converter will be passed as first argument to the *render()* method. However, if the converter returns an array, then the values will be used to convert each of the targeted arguments or properties specified in `bindTo`/`bindFrom`.\n\nSee also [*JsViews* `bindTo`](#tagoptions@bindto)\n',anchor:"bindto"},{_type:"para",title:"Specifying flow behavior: the flow option",text:"A 'flow' tag -- which has the `flow` option set to `true` -- is a tag that does not appear in the [parent tags](#tagsapi@parents) hierarchy, so is not accessed via `this.parent`, `~tagParents` etc.\n\nThe built-in tags such as `{{for}}`, `{{props}}` and `{{if}}` are *flow tags*.",anchor:"flow"},{_type:"para",title:"Specifying default context: the ctx option",text:'The `ctx` option of a tag can be used to provide default values of [contextual parameters](#contextualparams):\n\n```js\n$.views.tags("mytag", {\n template: "{{:~mode}}",\n ctx: {mode: "readonly"}, // Specify default ~mode if not provided by a helper or as a contextual parameter, \n ...\n});\n```\n',anchor:"ctx"},{_type:"para",title:"Methods and properties available on a custom tag instance",text:"A custom tag instance can access the following methods and properties\n\n- tag.ctxPrm()\n- tag.cvt()\n- tag.cvtArgs()\n- tag.bndArgs() \n- tag.ctx\n- tag.parent\n- tag.parents\n- tag.tagCtx\n- tag.tagCtxs\n- tag.tagName\n- tag.base\n- rendering"},{_type:"para",title:"Adding tags as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.tags(...)`.\n\nIn that way the tag (or tags) you are registering become 'private tag resources' for the `parentTemplate`, rather than being registered globally:",anchor:"privatetags"},{_type:"api",typeLabel:"API:",title:"",name:"tags",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"Add one or more tags as private resources for a parent template",params:[{_type:"param",name:"namedTags",type:"object",optional:!1,description:"Object (hash) of keys (name of tag) and values (render function or tagOptions)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template – to which this/these tag(s) are being added as private resources"}],args:[],sections:[],example:"$.views.tags({\n mytag1: ...,\n mytag2: ...\n}, parentTemplate);",description:"Add multiple tags as resources, to a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Unregistering tags",text:'To unregister a previously registered tag, pass `null` to `$.views.tags()`:\n\n```js\n$.views.tags("mytag", null);\n// Tag "mytag" is no longer registered\n```',anchor:"unregister"},{_type:"para",title:"Custom tags and 'tag controls'",text:"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern."},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"tags",label:"Using custom tags"},{_type:"topic",hash:"samples/jsr/tags",label:"Samples: JsRender custom tags"},{_type:"topic",hash:"samples/tag-controls",label:"Samples: JsViews tag controls"},{_type:"topic",hash:"jsvtagcontrols",label:"JsViews tag controls"}]}]}}; +},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nfunction toUpper(val) {...}\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = myTmpl.render(person, myHelpers);\n```\n\n```jsr\n\n```\n\nClick Try it and change the color to "green"...'}],html:'
            \n {{:~format(name)}}\n
            \n\n',code:'function toUpper(val) { return val.toUpperCase(); }\n\nvar myTmpl = $.templates("#personTemplate");\n\nvar person = {\n name: "Adriana"\n };\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = myTmpl.render(person, myHelpers);\n\n$("#person").html(html);',title:"template.render(object, myHelpers):",height:"52",jsrJsvJqui:"jsr"},{_type:"para",title:"Passing an array to render(), but without iteration.",text:"When rendering an array, an additional optional boolean parameter, `true`, can be passed to the `render()` method, in order to prevent iteration.\n"},{_type:"api",typeLabel:"API:",title:"template.render(data, helpersOrContext, noIteration)",name:"render",object:"template",method:!0,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],args:[],sections:[],example:"var html = myTmpl.render(data, helpers, true);",description:"Render template against data, pass in helpers, and specify iteration behavior"}],description:"Render a template against data, along with helpers/context (and determine iteration behavior with array data). Return a string. ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:"noiteration"},{_type:"para",title:"",text:"By passing in `true` as the third *'noIteration'* parameter (or as second parameter if no `helpersOrContext` are passed), the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\n\nWithin the template, `{{for}}` (or equivalently `{{for #data}}`) can be used to iterate over the array, as in the following example:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"Code:\n\n```js\nvar html = myTmpl.render(people, true);\n```\n\nTemplate:\n\n```jsr\n\n \n \n {{for}}\n \n {{/for}}\n \n
            \n {{:#data.length}} people\n
            \n {{:name}}\n
            \n```"}],jsrJsvJqui:"jsr",height:"110",html:'
            \n\n',code:'var myTmpl = $.templates("#personTmpl");\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];\n\nvar html = myTmpl.render(people, true);\n\n$("#peopleList").html(html);',title:"template.render(array, helpers, noIteration):"},{_type:"para",title:"Alternative compact syntax for render() call",text:"The compiled template is in fact *itself a function*, equivalent to its own `render()` method. \n\nThis means that any `render()` call can be replaced by an equivalent (but more compact) syntax, as shown in the following example:\n\n```js\nvar html = myTmpl(people, helpers, true);"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},"d.render":{title:"Render a named template without needing the template object",path:"",sections:[{_type:"para",title:"$.render.myTmpl()",text:'If a template has been [registered](#d.templates) as a named template:\n\n```js\n$.templates("myTmpl", "#personTmpl");\n```\n\nor\n\n```js\n$.templates("myTmpl", "some markup string");\n```\n\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates).\n\nJust call `$.render.myTmpl(...)`, or `$.render["myTmpl"](...)`\n\n(**Note:** there is also an alternative syntax for rendering a named template: `$.templates.myTmpl(...);`)\n'},{_type:"api",typeLabel:"API:",title:"$.render.myTmpl(data, helpersOrContext, noIteration)",name:"myTmpl",object:"$.render",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],sections:[],example:"var html = $.render.myTmpl(data, helpers, true);",description:"Render template against data. Optionally pass in helpers and specify iteration behavior."}],description:"Render a template against data. Return a string.
            (Optionally provide helpers/context, and specify iteration behavior). ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", "#personTemplate");\n\nvar html = $.render.personTmpl(person);'}],html:'
            \n\n',code:'function toUpper(val) { return val.toUpperCase(); }\n\n$.templates("personTmpl", "#personTemplate");\n\nvar person = {\n name: "Adriana"\n };\n\nvar myHelpers = {color: "red", format: toUpper};\n\nvar html = $.render.personTmpl(person, myHelpers);\n\n$("#person").html(html);',title:"$.render.personTmpl(...):",height:"50",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},"db.render":{title:"jQuery instance method to render a template declared in a script block",path:"",sections:[{_type:"para",title:'$("#myTmpl").render()',text:'If a template has been [registered](#d.templates) using a script block:\n\n```jsr\n\n```\n\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates), and without registering a named template.\n\nJust call `$("#myTmpl").render(...)`'},{_type:"api",typeLabel:"API:",title:"$(tmplSelector).render(data, helpersOrContext, noIteration)",name:"render",object:"$(tmplSelector)",method:!0,tag:!1,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."},{_type:"param",name:"helpersOrContext",type:"object",optional:!0,description:"Contextual helper methods or properties - available to template as ~keyName"},{_type:"param",name:"noIteration",type:"boolean",optional:!0,description:"Pass in parameter true to prevent iteration on array data"}],sections:[],example:'var html = $("#myTmpl").render(myData, myHelpers, true);',description:"Render template against data. Optionally pass in helpers and specify iteration behavior."}],description:"Render a template against data. Return a string.
            (Optionally provide helpers/context, and specify iteration behavior). ",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\nvar html = $("#personTemplate").render(person);\n```'}],html:'
            \n\n',code:'var person = {\n name: "Adriana"\n };\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',title:'$("#personTemplate").render(...):',height:"50",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},compiletmpl:{title:"Using templates",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering templates](#d.templates): The `$.views.templates()` API*.)"},{_type:"para",title:"Defining templates",text:"To define a template you need to provide the markup for the template. JsRender will convert (compile) the markup into a JavaScript function -- the 'render' function for your template. In fact for convenience, JsRender creates a *template object* which has a [`template.render()`](#rendertmpl) method which is the compiled function.\n\nThere are two ways to create a template:\n\n- Pass the markup string to the [`$.templates()`](#d.templates) method\n- Declare the template in a script block with `type=\"text/x-jsrender\"` (or at least a type other than the default `text/javascript`), then pass the jQuery selector for the script block to the [`$.templates()`](#d.templates) method\n\nIn either case, the `$.templates()` method will compile a template object, and optionally register it by name.\n\nHere is an example of the first approach:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'We pass our markup string to the [`$.templates()`](#d.templates) method:\n\n```jsr\nvar myTmpl = $.templates(" {{:name}} ");\n```\n\nthen call the [`render()`](#rendertmpl) method on the returned template object:\n\n```js\nvar html = myTmpl.render(people);\n```'}],height:"40",jsrJsvJqui:"jsr",html:'
            ',code:'var myTmpl = $.templates(" {{:name}} ");\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];\n\nvar html = myTmpl.render(people);\n\n$("#peopleList").html(html);',title:"Registering a template from a template markup string:"},{_type:"para",title:"",text:"And here is an example of the second:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'This time we put our markup in a script block with `type="text/x-jsrender"`\n\n```jsr\n\n```\n\nand then in the code we call the [`$.templates()`](#d.templates) method with a jQuery selector for that script block: \n\n```jsr\nvar myTmpl = $.templates(" {{:name}} ");\n```\n\nThen as before we call the [`render()`](#rendertmpl) method on the returned template object:\n\n```js\nvar html = myTmpl.render(people);\n```'}],html:'
            \n\n',code:'var myTmpl = $.templates("#personTemplate");\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];\n\nvar html =myTmpl.render(people);\n\n$("#peopleList").html(html);',title:"Registering a template declared in script block:",jsrJsvJqui:"jsr",height:"40"},{_type:"para",title:"",text:"The first approach above has the advantage of keeping your template declaration independent of the HTML markup that you are loading into the browser. Indeed you may want to provide the template markup strings for your templates in different application-specific ways, such as loading the string from the server (using a script file or text or html file), creating 'computed' template markup strings on the fly, etc.\n"},{_type:"para",title:"Example of fetching the markup string from the server",text:'Here is a simple example of fetching the markup string from the server. We load a `.../person.js` file from the server which registers a named `"person"` template.'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'We load the *person.js* script from the server, which registers a named `"person"` template:\n\n```js\n$.templates("person", " {{:name}} ");\n```\n\nAs soon as the script is loaded, we call the [`render(...)`](#d.render) method for the registered template:\n\n```js\n$.getScript(".../person.js", function() {\n var html = $.render.person(people);\n $("#peopleList").html(html);\n });\n```\n\n*Note:* For a more sophisticated example of lazy loading of scripts for registering templates, see the [remote templates](#samples/jsr/composition/remote-tmpl) sample.'}],markup:"\n",data:{},code:'$.getScript("https://www.jsviews.com/samples/resources/templates/person.js", function() {\n var html = $.render.person(people);\n $("#peopleList").html(html);\n });\n\nvar people = [\n {\n name: "Adriana"\n },\n {\n name: "Robert"\n }\n];',html:'
            ',jsrJsvJqui:"jsr",height:"40",title:"Fetching a script file from the server, which registers a named template from a string",codetabs:[{_type:"codetab",name:"",url:"samples/resources/templates/person.js",label:"person.js"}]},{_type:"para",title:"",text:"And here is a variant of the same sample, where we fetch a text file containing the template markup:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"para",title:"",text:'The markup string is fetched in an AJAX request (the *person.txt* file).\n\n```jsr\n {{:name}}\n```\n\nAs soon as the request returns, we use the markup string to compile the `personTemplate` object. This time we will not register it as a *named template*, but instead directly call the [`render(...)`](#tmplrender) method of the returned `personTemplate` object:\n\n```js\n$.get("...person.txt", function(value) {\n personTemplate = $.templates(value);\n var html = personTemplate.render(people);\n $("#peopleList").html(html);\n});\n```'}],html:'
            \n',code:'var personTemplate;\n\n$.get("resources/templates/person.txt", function(value) {\n personTemplate = $.templates(value);\n var html = personTemplate.render(people);\n $("#peopleList").html(html);\n});\n\nvar people = [\n {name: "Adriana"},\n {name: "Robert"}\n];',title:"Registering a named template using markup fetched from the server in a text file",jsrJsvJqui:"jsr",height:"40",codetabs:[{_type:"codetab",name:"",url:"samples/resources/templates/person.txt",label:"person.txt"}]},{_type:"para",title:"",text:"And here is the second approach:"},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering templates](#d.templates): The `$.views.templates()` API"},{_type:"links",title:"See also:",links:[],topics:[{hash:"rendertmpl",label:"Render a template"},{_type:"topic",hash:"samples/jsr/composition/sub-tmpl",label:"Sample: sub-templates"}]}]},"d.templates":{title:"Registering templates: $.templates()",path:"",sections:[{_type:"para",title:"",text:"`$.templates()` is used to register or compile templates. See *[Using templates](#compiletmpl)* for an overview, and simple examples.\n\nThis topic provides more details."},{_type:"para",title:"Simple scenarios",text:"`$.templates(...)` is powerful and flexible. You can use it for many scenarios, including the following:\n- Compile a template from a string\n- Get a template object for a template declared in a script block\n- Register a template (from either a string or a script block declaration) as a *named template*\n- Get a template object for a previously registered *named template*\n- On Node.js: Get a template object for a template declared as a file on the file-system (see *[File-based templates on Node.js](#node/filetmpls)*).",anchor:"$.templates"},{_type:"api",typeLabel:"API:",title:"$.templates(...)",name:"templates",object:"$",method:!0,tag:!1,returns:"Compiled template object",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"markupOrSelector",type:"string",optional:!1,description:"A markup string or a selector for a template declaration script block"}],sections:[],example:"var myTemplate = $.templates(myMarkupString);",description:"Compile a template from a string or selector, and return the template object"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered template"},{_type:"param",name:"markupOrSelector",type:"string",optional:!1,description:"A markup string or a selector for a template declaration script block"}],args:[],sections:[],example:'$.templates("myTemplateName", myMarkupString);',description:"Register a named template from a string or selector"}],description:"Create one or more compiled templates – optionally registered as named templates",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:""},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample"},sections:[{_type:"code",title:"",code:'var myTmpl = $.templates(" {{:name}}");\n\nvar html = myTmpl.render(person);\n'}],html:'
            \n',code:'var myTmpl = $.templates(" {{:name}}");\n\nvar person = {name: "Robert"};\n\nvar html = myTmpl.render(person);\n\n$("#peopleList").html(html);',title:"Compile a template from a string",jsrJsvJqui:"jsr",height:"40",anchor:"tmpl-string"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\nvar myTmpl = $.templates("#personTemplate");\n\nvar html = myTmpl.render(person);\n```'}],title:"Get template object for script block template",html:'
            \n\n',code:'var myTmpl = $.templates("#personTemplate");\n\nvar person = {name: "Robert"};\n\nvar html = myTmpl.render(person);\n\n$("#peopleList").html(html);',height:"40",jsrJsvJqui:"jsr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", " {{:name}}");\n\nvar html = $.render.personTmpl(person);\n'}],code:'$.templates("personTmpl", " {{:name}}");\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',html:'
            ',height:"40",title:"Register named template from a string",anchor:"namedfromstring",jsrJsvJqui:"jsr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("personTmpl", "#personTemplate");\n\nvar html = $.render.personTmpl(person);\n'}],code:'$.templates("personTmpl", "#personTemplate");\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',html:'
            \n\n',title:"Register named template from script block",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Register multiple templates in one call",text:"You can register multiple named templates in one call to `$.templates()` as follows:"},{_type:"api",typeLabel:"API:",title:"$.templates(namedTemplates)",name:"",object:"",method:!1,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"namedTemplates",type:"object",optional:!1,description:"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)"}],args:[],sections:[],example:'$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: "<label>Name:</label>"\n});',description:"Register multiple named templates"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n```\n\n```js\n$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: ""\n});\n\nvar html = $.render.personTmpl(person);\n```'}],html:'
            \n\n',code:'$.templates({\n personTmpl: "#personTemplate",\n labelTmpl: ""\n});\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',title:"Registering multiple templates",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Get a template object for a named template",text:'You can get the template object for a previously registered *named template* as follows:\n\n```js\nvar myTemplate = $.templates.myTemplateName; // or $.templates["myTemplateName"]\n```'},{_type:"para",title:"Unregister a named template",text:'To unregister a previously registered named template, pass `null` to `$.templates()`:\n\n```js\n$.templates("myTemplateName", null);\n// Named template "myTemplateName" is no longer registered\n```'},{_type:"para",title:"Advanced scenarios: Associating private resources with templates",text:'$.templates() can also be used for the following more advanced scenarios:\n\n- Compile a template, (or multiple templates) along with specified resources to be available only within that template\n- Compile one or more templates to be added to the set of private resources of another (already compiled) template\n\nYou can use `$.templates()` to compile or register not only a template, but in addition some helpers, converters, custom tags or nested sub-templates, to be made available to the new template as private resources.\n\nNote that as an alternative you can register resources (helpers, converters, custom tags or templates) globally, using `$.views.helpers()`, `$.views.converters()`, `$.views.tags()`, or `$.templates()` -- rather than making them private to the template that needs to reference them.'},{_type:"api",typeLabel:"API:",title:"$.templates(...) — associating resources",name:"templates",object:"$",method:!0,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"templateOptions",type:"object",optional:!1,description:"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)"}],args:[],sections:[],example:'var myTmpl = $.templates({\n markup: "...",\n helpers: {...},\n tags: {...}\n ...\n});',description:"Compile a template, along with specified resources to be available only within this template"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered template"},{_type:"param",name:"templateOptions",type:"object",optional:!1,description:"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)"}],args:[],sections:[],example:'$.templates("myTmpl", {\n markup: "...",\n helpers: {...},\n tags: {...}\n ...\n});',description:"Register a named template, along with specified resources available only within that template"},{_type:"signature",title:"",params:[{_type:"param",name:"namedTemplates",type:"object",optional:!1,description:"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these template(s) are being added as private resources"}],args:[],sections:[],example:"$.templates(namedTemplates, parentTemplate);",description:"Register named templates as private resources for a 'parent template'"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"},anchor:"resources"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'A converter and a helper are registered as private resources for the `personTmpl` named template.\n\n```js\n$.templates("personTmpl", {\n markup: "#personTemplate",\n converters: {\n upper: function(val) {return val.toUpperCase();}\n },\n helpers: {\n append: function(a, b) {return a + b;}\n }\n});\n```\n\nThey are accessed within the `personTmpl`\n\n```jsr\n\n```'}],html:'
            \n\n',code:'// Register a template along with a converter and a helper that it will use.\n// These resources are private to the template, rather than being registered\n// globally using $.views.converters or $.views.helpers\n$.templates("personTmpl", {\n markup: "#personTemplate",\n converters: {\n upper: function(val) {return val.toUpperCase();}\n },\n helpers: {\n append: function(a, b) {return a + b;}\n }\n});\n\nvar person = {name: "Robert"};\n\nvar html = $.render.personTmpl(person);\n\n$("#peopleList").html(html);',title:"Register a named template along with specified resources",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Adding templates as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.templates(...)`. In that way the template you are registering becomes a 'private template resource' for the `parentTemplate`.\n\nHere is an example:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'$.templates("labelTmpl", "", personTmpl);\n'}],code:'var personTmpl = $.templates("#personTemplate");\n\n$.templates("labelTmpl", "", personTmpl);\n\nvar person = {name: "Robert"};\n\nvar html = personTmpl.render(person);\n\n$("#peopleList").html(html);',html:'
            \n\n',title:'Add a "labelTmpl" template resource as a \'sub template\' – a private resource for an existing "personTemplate"',height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Debug a template by including a debugger; statement",text:'As a technique for debugging compiled templates, you can temporarily set the template option `debug: true`:\n\n```js\n$.templates({\n myTmpl: {\n markup: "...",\n debug: true // This option will add a debugger; statement to the compiled template\n }\n});\n```\n\nThe result will be to include a `debugger;` statement at the beginning of the compiled template, which will behave as a breakpoint when debugging, and will facilitate understanding, or stepping through, the compiled template.\n'},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"compiletmpl",label:"Using templates"},{_type:"topic",hash:"samples/jsr/composition/sub-tmpl",label:"Sample: sub-templates"},{_type:"topic",hash:"rendertmpl",label:"Render a template"}]}]},jsrregister:{title:"Register helpers, converters, tags...",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"converters",label:"$.views.converters()"},{hash:"tags",label:"$.views.tags()"},{hash:"helpers",label:"$.views.helpers()"}]}]},tags:{title:"Using custom tags",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering tags](#tagsapi): The `$.views.tags()` API*.)"},{_type:"para",title:"What is a custom tag?",text:"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\n\nA tag renders itself as part of the template output. You determine how it renders, generally by specifying either a function as *render()* method or a template, when you declare your custom tag.\n\nThe *render()* method, or the *template*, can access both unnamed arguments (*args*) and named properties (*props*) and , [as in](#tagsyntax@tagparams):\n\n```jsr\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\n```\n\nIn fact it can also access the current data item -- or even the whole hierarchy of views and data...\n\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. "},{_type:"para",title:"Registering a custom tag",text:'To register a custom tag, you call [`$.views.tags(...)`](#tagsapi):\n```js\n$.views.tags("mytag", tagOptions)\n```\n\nYou provide a `tagOptions` object, whose properties will typically include a `render: tagRenderFn` (function to be used as *render()* method) and/or a `template: tagTemplate` (template to be rendered -- markup string, selector string or template object).\n\nFor the simple case where the *only* option you need to specify is a *render()* method, you can provide the function directly:\n\n```js\n$.views.tags("mytag", tagRenderFn);\n```\n\nOr if you *only* want to provide a template markup string, to show how it renders, you can again provide it directly:\n\n```js\n$.views.tags("mytag", tagTemplate);\n```\n\nHere is an example of a simple custom tag using just a function:'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Render method for the tag\nfunction renderBoldP(value) {\n return "

            " + value + "

            ";\n}\n\n$.views.tags("boldp", renderBoldP); // Provide just a render method\n```\n\nAlternatively we could have written:\n\n```js\n$.views.tags("boldp", {\n render: renderBoldP); // Provide just a render method\n});\n```\n' +},{_type:"template",title:"Using the tag",markup:"This is the title:{{boldp title /}}"}],title:"A custom tag using just a render() method",html:'
            \n\n',code:'// Render method for the tag\nfunction renderBoldP(value) {\n return "

            " + value + "

            ";\n}\n\n$.views.tags("boldp", renderBoldP); // Provide just a render method\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"70",jsrJsvJqui:"jsr",anchor:"render-sample"},{_type:"para",title:"",text:"And here is the equivalent sample using just a template:"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Template markup string for the tag\nvar tagTemplate = "

            {{:}}

            ";\n\n$.views.tags("boldp", tagTemplate); // Provide just a template markup string\n```\n\nAlternatively we could have written:\n\n```js\n$.views.tags("boldp", {\n template: tagTemplate; // Provide just a template markup string\n});\n```'},{_type:"template",title:"Using the tag",markup:"This is the title:{{boldp title /}}"}],code:'// Template markup string for the tag\nvar tagTemplate = "

            {{:}}

            ";\n\n$.views.tags("boldp", tagTemplate); // Provide just a template markup string\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',html:'
            \n\n',title:"A custom tag using just a template",height:"70",jsrJsvJqui:"jsr",anchor:"template-sample"},{_type:"para",title:"Accessing unnamed arguments, named properties, data, etc. within the render() method",text:'The `this` pointer within the tag *render()* method is the instance of the tag, and can be used to access properties, data, view hierarchy, and more. Most of the useful context is provided via `this.tagCtx`. (See [tagCtx object](#tagctxobject).)\n\nIn particular, unnamed arguments can be accessed via `tagCtx.args`, and named properties via `tagCtx.props`.\n\nHere is tag with two arguments and one named property:\n\n```jsr\n{{sometag title name mode="edit"}}\n```\n\nFrom within the *render()* method of `sometag`, you can access `title` and `name` as `this.tagCtx.args[0]` and `this.tagCtx.args[1]`. And you can access mode as `this.tagCtx.props.mode`.\n\nIn addition to being accessible as `tagCtx.args`, unnamed arguments are also passed directly as arguments to the *render()* method (if your tag is using one):\n\n```js\nfunction sometagRenderMethod(title, name) {\n // Here, this.tagCtx.args[1] and the name argument are the same thing\n}\n```\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Render method for the tag\nfunction sometagRenderMethod(title, name) {\n var parentData = this.tagCtx.view.data;\n\n return\n "title: " ... title ... // Get argument passed to render method\n + "parentData.title: " ... this.tagCtx.view.data.title ... // Get title from parent context\n\n + "args[1]: " ... this.tagCtx.args[1] ... // Get argument from args[]\n + "mode: " ... this.tagCtx.props.mode; // Get named property from props\n}\n```'}],jsrJsvJqui:"jsr",html:'
            \n\n',code:'// Render method for the tag\nfunction sometagRenderMethod(title, name) {\n var parentData = this.tagCtx.view.data;\n\n return "title: " + title + "
            " // Get argument passed to render method\n + "parentData.title: " + this.tagCtx.view.data.title + "
            " // Get title from parent context\n + "args[1]: " + this.tagCtx.args[1] + "
            " // Get argument from args[]\n + "mode: " + this.tagCtx.props.mode; + ""// Get named property from props\n}\n\n$.views.tags("sometag", sometagRenderMethod); // Provide just a render method\n\nvar team = {\n title: "theTitle",\n name: "theName"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",title:"Accessing context within the render() method",action:"append",header:"",anchor:"context-sample"},{_type:"para",title:"Accessing arguments, named properties, data, etc. from the tag template",text:"Within the template, the tag instance can be accessed as `~tag`, and so unnamed arguments and named properties are obtained using `~tagCtx.args[...]` and `~tagCtx.props...`"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Template markup for the tag\nvar sometagTemplate =\n "title: {{:}}" // The data context within the tag is the first argument, title\n + "title (#data): {{:#data}}" // Equivalent unabbreviated syntax for current data\n + "parentData.title: {{:~tagCtx.view.data.title}}" // Get title from parent context\n\n + "args[1]: {{:~tagCtx.args[1]}}" // Get argument from args[]\n + "mode: {{:~tagCtx.props.mode}}"; // Get named property from props";\n```'}],html:'
            \n\n',code:'// Template markup for the tag\nvar sometagTemplate =\n "title: {{:}}
            " // The data context within the tag is the first argument, title\n + "title (#data): {{:#data}}
            " // Equivalent unabbreviated syntax for current data\n + "parentData.title: {{:~tagCtx.view.data.title}}

            " // Get title from parent context\n + "args[1]: {{:~tagCtx.args[1]}}
            " // Get argument from args[]\n + "mode: {{:~tagCtx.props.mode}}"; // Get named property from props\n\n$.views.tags("sometag", sometagTemplate ); // Provide just a template markup string\n\nvar team = {\n title: "theTitle",\n name: "theName"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"124",header:"",action:"append",title:"Accessing context from the tag template",anchor:"tmplcontext-sample"},{_type:"para",title:"Accessing and rendering wrapped block content, in a custom tag",text:"A common requirement is to define a custom tag to be used as a block tag, which renders itself by wrapping the rendered block content with other markup.\n\nFor example, a `boldp` tag which wraps its content as: `

            ...

            `:\n\n```jsr\n{{boldp}}\n This is inside our block content:
            \n {{:title}}\n{{/boldp}}\n```\n\n**_Block content, using a render() method_**:\n\nIn a *render()* method, the block content can be included in the rendered output using:\n\n```js\n... this.tagCtx.render() ...\n```\n\n(For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See [template as fallback sample](#tags@tmpl-fallback) below) \n",anchor:"wrapping"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Tag render method:*\n\n```js\nfunction renderBoldP(val) {\n //To render the block content, we call this.tagCtx.render()\n return "

            " + this.tagCtx.render() + "

            ";\n}\n```\n\n*Using the tag:*\n\n```jsr\nThis is outside our block content: ...\n{{boldp}}\n This is inside our block content: ...\n {{:title}}\n{{/boldp}}\n```'}],title:"Rendering block content from a custom tag render() method",html:'
            \n\n',code:'function renderBoldP(val) {\n return "

            " + this.tagCtx.render() + "

            ";\n}\n\n$.views.tags("boldp", renderBoldP); // User renderBoldP() as render method\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",jsrJsvJqui:"jsr",anchor:"renderblock-sample"},{_type:"para",title:"",text:"When using `tagCtx.render()` without arguments, the data context within the block content is the same as the data context outside our custom tag. However by passing an argument to `tagCtx.render(myData)` the inner data context can be moved to the chosen data. \n\nThe following sample shows a custom `{{runningTotal}}` tag which renders an array of `lineItems` (with a column for each property), and provides a running total of one of the columns.\n\nIt uses a *render()* method to access tag arguments and named properties, and iterate over the `lineItems` array. It renders a row for each `lineItem`, using the code:\n\n```js\nret += this.tagCtx.render(lineItem, {total: totalVal});\n```\n\nHere, the row is rendered using the block content as template -- with the `lineItem` passed in as data context. The running total `totalVal` is provided as contextual helper: `~total`."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'You call the custom `{{runningTotal}}` tag like this:\n\n```jsr\n{{runningTotal lineItems totalColumn="quantity"}}\n ...{{:quantity}}\n ...{{:~total}}\n{{/runningTotal}}\n```\n\nAnd the *render()* method code accesses context (`this.tagCtx`) to get at the arguments and named properties... :\n\n```js\n$.views.tags("runningTotal", function renderLineItems(array) {\n ...\n totalVal = 0; // Initialize ~total to 0 before rendering\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\n for (var i = 0; i < array.length; i++) {\n lineItem = array[i];\n totalVal += lineItem[totalCol]; // Compute running total\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content as\n // template. Pass lineItem as data and totalVal as helper: ~total\n }\n ...\n```'}],html:'
            \n\n',code:'function renderLineItems(array) {\n var lineItem,\n ret = "",\n totalVal = 0, // Initialize ~total to 0 before rendering\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\n for (var i = 0; i < array.length; i++) { // Iterate over array and render a row for each lineItem \n lineItem = array[i];\n totalVal += lineItem[totalCol]; // Compute running total\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content\n // as template, and passing lineItem as current data and totalVal as helper: ~total\n }\n return ret;\n}\n\n$.views.tags("runningTotal", renderLineItems); // Use renderLineItems() as render method\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ]\n};\nvar html = $("#myTmpl").render(data);\n\n$("#lineItems").html(html);',jsrJsvJqui:"jsr",height:"152",title:"A {{runningTotal}} custom tag, using a render() method ",anchor:"runningtotal-sample",header:"",action:"append"},{_type:"para",title:"",text:"**_Block content, using a template_**:\n\nTo render block content declaratively within a custom tag template, use:\n\n```jsr\n{{include tmpl=#content/}}\n```\n\nor equivalently:\n\n```jsr\n{{include tmpl=~tagCtx.content/}}\n```\n\nHere is a modified [`{{boldp}}`](#tags@renderblock-sample) sample using a custom template instead of a *render()* method."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'To render block content, we use `{{include tmpl=#content/}}`\n\n```js\ntemplate: "

            {{include tmpl=#content/}}

            "\n```\n\n(The syntax `#content` is an example of a `view path` -- equivalent to `#view.content`.)\n\nThe `content` property on the `view` object is a compiled template for the block content, which is also available as the `content` property on the `tagCtx`.'}],html:'
            \n\n',code:'$.views.tags("boldp", {\n template: "

            {{include tmpl=#content/}}

            "\n});\n\nvar team = {\n title: "The A Team"\n};\n\nvar html = $("#teamTemplate").render(team);\n\n$("#team").html(html);',height:"90",title:"Rendering block content from a custom tag template",jsrJsvJqui:"jsr",anchor:"tmplblock-sample"},{_type:"para",title:"",text:"Here, the default data context within the block content is the same as the data context outside our custom tag (as was the case in the [previous](#tags@renderblock-sample) `{{boldp}}` sample). However by providing an argument to the `{{include...}}`, as in `{{include myData tmpl=#content/}}`, the inner data context can be moved to the chosen data.\n\n(Note: To be precise, the default data in the two samples is different. When using `tagCtx.render()` the outer context is *outside our `{{boldp}}` tag*. Whereas when using `{{include}}`, it is *outside the `{{include}}` and within the `{{boldp}}` template*. If we provide an argument to the tag: '{{mytag someArgument}}...' then in custom tag template approach the passed-in argument value will be used as default data context.)\n"},{_type:"para",title:"",text:"For further details and examples of custom tags which wrap content, see [*Rendering wrapped block content*](#tagsapi@wrapping)"},{_type:"para",title:"Custom tags using both a render() method and a template",text:'If there is both a *template* and a *render()* method, then the *template* will only be used if the *render()* method returns *undefined*.\n\nLet\'s take our `{{runningTotal}}` example using a *render()* method, but provide a *template* which will be used as "fallback" rendering for the tag in the case when there are no items to render in the chosen range. We will also provide support for limiting the range of line items by setting `start=... end=...`:',anchor:"tmpl-fallback"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'First, in the *render()* method, we will change the original code to test whether the item exists in the array, before rendering the block content.\n\nSecondly, we will make sure that when there is an item we do render the block content and not the template. So we call `this.tagCtx.content.render(...)`, rather than `this.tagCtx.render(...)`.\n\nThat\'s because `this.tagCtx.render(...)` will actually look to see if there is template associated with the tag, (either a template on the tag definition, or a `tmpl` property on the tag) -- in which case it will render that template and not the block content... \n\n```js\nfor (var i=start; iNo line items"\n```'}],code:'$.views.tags("runningTotal", {\n render: function(array) {\n var lineItem,\n ret = "",\n totalVal = 0, // Initialize ~total to 0 before rendering\n props = this.tagCtx.props,\n totalCol = props.totalColumn; // The column/property to use for running total\n start = props.start,\n end = props.end;\n for (var i=start; iNo line items" // Template for fallback if no line items\n});\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ],\n lineItems2: []\n};\n\nvar html = $("#myTmpl").render(data, {\n category: function(item, index, items) {\n return item.category === this.props.category;\n }\n});\n\n$("#purchases").html(html);',html:'
            \n\n',height:"244",jsrJsvJqui:"jsr",title:'A {{runningTotal}} custom tag, with render() method and a template as "fallback"',anchor:"renderplustmpl-sample",header:"",action:"append",url:""},{_type:"para",title:"",text:"In the above sample our feature for limiting the range of items by setting `start=... end=...` is basically identical to the corresponding feature available natively on the [`{{for}}`](#fortag@sortfilterrange) tag:\n\n```jsr\n{{for start=... end=...}}\n```\n\nIn fact we can add this feature to our `{{runningTotal}}` tag for free (along with providing sorting, filtering etc.) by making `{{runningTotal}}` derive from `{{for}}`, as `baseTag`. This will also simplify our code considerably. See [*Specifying tag inheritance*](#tagsapi@basetag) for details and an [updated](#tagsapi@derivedfor) `{{runningTotal}}` sample."},{_type:"para",title:"Custom tags and 'tag controls'",text:"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern."},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering tags](#tagsapi): The `$.views.tags()` API"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"samples/jsr/tags",label:"Samples: JsRender custom tags"},{_type:"topic",hash:"samples/tag-controls",label:"Samples: JsViews tag controls"},{_type:"topic",hash:"jsvtagcontrols",label:"JsViews tag controls"}]}]},jsrobjects:{title:"JsRender objects",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"viewsobject",label:"$.views object"},{hash:"templateobject",label:"template object"},{hash:"viewobject",label:"view object"},{hash:"tagobject",label:"tag object"},{hash:"ctxobject",label:"View context object (ctx)"},{hash:"tagctxobject",label:"Tag context object (tagCtx)"},{hash:"globals",label:"Globals"}]}]},viewsobject:{title:"The $.views object (JsRender)",path:"",sections:[{_type:"para",title:"",text:"The `$.views` object provides access to APIs for creating templates, tags, helpers etc.

            \n\n\n- `$.views.templates(...)` -- available also as `$.templates(...)`\n
            Used for defining templates -- see: [Registering templates](#d.templates)\n- `$.views.tags(...)`\n
            Used for defining custom tags -- see: [Registering custom tags](#tagsapi)\n- `$.views.converters(...)`\n
            Used for defining converters -- see: [Registering converters](#convertersapi)\n- `$.views.helpers(...)`\n
            Used for defining helpers -- see: [Registering helpers](#helpersapi)\n- `$.views.viewModels(...)`\n
            Used for defining View Models -- see: [Compiled View Models](#viewmodelsapi)\n\nIt also provides access to:

            \n- `$.views.settings`\n
            Used for modifying JsViews settings and options -- see: [Settings](#jsvsettings)\n- `$.views.map(...)`\n
            Used for defining custom maps (advanced) \n- `$.views.jsviews`\n
            Provides the version number of the currently loaded JsViews or JsRender library\n\n"}]},settingsobject:{title:"$.views.settings object",path:"",sections:[]},subobject:{title:"$.views.sub object",path:"",sections:[]},templateobject:{title:"The template object (JsRender)",path:"",sections:[{_type:"para",title:"",text:'The [`$.templates()`](#d.templates) API can be used to obtain a compiled template object:\n\n```js\nvar myTmpl = $.templates(" {{:name}}");\n```\n\nThe compiled template object (`myTmpl`, in the example) provides a number of properties and methods, in particular:\n'},{_type:"para",title:"The render() method",text:"```js\nvar html = myTmpl.render(person);\n```\n\nSee [Render a template against data objects or arrays](#tmplrender)"},{_type:"para",title:"The markup property",text:'The declarative markup string for the template (available whether the template was registered by providing a markup string, or by a script block reference).\n\n```js\nvar test = myTmpl.markup; // " {{:name}}"\n```'},{_type:"para",title:"The compiled template object is actually a render() function",text:"The compiled template *is itself a function*, corresponding to its own render method, so the following two examples are actually equivalent.\n\n*Calling the render method:*\n\n```js\nvar html = myTmpl.render(person);\n```\n\n*Invoking the compiled template directly as render method:*\n\n```js\nvar html = myTmpl(person);\n```"}]},viewobject:{title:"The view object (JsRender)",path:"",sections:[{_type:"para",title:"",text:"JsRender templates render as a [*view hierarchy*](#views)."},{_type:"para",title:"A view object has the following properties and methods:",text:"- [type property](#viewobject@type)\n- [data property](#viewobject@data)\n- [parent property](#viewobject@parent)\n- [index property](#viewobject@index)\n- [getIndex() method](#viewobject@getindex)\n- [get(type) method](#viewobject@get)\n- [content property](#viewobject@content)\n- [root property](#viewobject@root)\n- [ctxPrm() 'get' method](#viewobject@ctxprm)\n- [other properties and methods (tmpl, views, ctx, tag, getRsc()](#viewobject@other)\n\n"},{_type:"para",title:"",text:"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `view` objects have additional methods:*\n- *[refresh()](#jsvviewobject@refresh)*\n- *[contents()](#jsvviewobject@contents)*\n- *[childTags()](#jsvviewobject@childtags)*\n- *[nodes()](#jsvviewobject@nodes)*\n\n*See [JsViews `view` object](#jsvviewobject).*"},{_type:"para",title:"Accessing view objects",text:"The properties of the current view are accessed *declaratively* in a template using *[view paths](#paths)* -- such as `#parent` for the `view.parent` property.\n\nAccessing `view` objects *programmatically* is less common in JsRender, but can be useful for example:\n\n- in a helper function, `~myHelper()`, where the `this` pointer is the current view\n- in the render() method of a custom tag -- using `this.tagCtx.view`\n\n*Note:* In JsViews, accessing `view` objects programmatically is very common, thanks to the [`$.view()`](#jsv.d.view) method. For example in a click handler, `$.view(this);` returns the corresponding `view` object.

            \n\n\n### Properties and methods:\n"},{_type:"para",title:"The type property:",text:'***view.type**: string corresponding to the type of view:*\n\n- `"data"` -- for the top-level view from a `render()` call\n- `"array"` or `"item"` -- from `{{for array}}` or `{{props object}}` (see *[array and item views](#views@itemview)*)\n- `"sometag"` -- for the view from `{{sometag}}...{{sometag}}` -- for example: `"include"`, `"if"`, `"for"`, `"props"`, `"mytag"`...\n',anchor:"type"},{_type:"para",title:"The data property:",text:"***view.data**: the current data context for the view* -- as in:\n\n```js\nvar team = view.data.team; // The team property of the current data object\n```\n\n`view.data` can be accessed declaratively in templates as `#data`-- as in:\n\n```jsr\n{{:#data}}\n{{>#data.description()}}\n{{for #data.team.members}}...\n```\n\nBut note that since `#data`, the current data context, is the starting point for *[data paths](#paths)* within templates, the above expressions with `#data` can be abbreviated to:\n\n```jsr\n{{:}}\n{{>description()}}\n{{for team.members}} etc.\n```",anchor:"data"},{_type:"para",title:"The parent property:",text:"***view.parent**: the parent view* (used to step up through views in the hierarchy).\n\n```js\nvar index = view.parent.index; // The index of the parent view\n```\n\nAccessed declaratively as `#parent`:\n\n```jsr\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\n```\n\n(See also *[Accessing parent data](#parentdata)*)",anchor:"parent"},{_type:"para",title:"The index property:",text:'***view.index**: the view index* (only available on [item views](#views@itemview)).\n\n```js\nvar index = view.index; // The index of the view (for "item" views - otherwise an \'error string\')\n```\n\nAccessed declaratively as `#index`:\n\n```jsr\n{{if #index > 2}} {{!-- we are in an "item" view --}}\n {{:#parent.index}}... {{!-- "item" view index (- the parent - since we are inside the \'ifView\') --}}\n{{/if}}\n```\n\n**Note:** On non-"item" views, accessing the index property returns the error message prompt: *"For #index in nested block use #getIndex()."*',anchor:"index"},{_type:"para",title:"The getIndex() method:",text:'***view.getIndex()**: get the index of current "item" view* (steps up to nearest [item view](#views@itemview), and returns the index).\n\n```js\nvar index = view.getIndex(); // The index of the view\n```\n\nAccessed declaratively as `#getIndex()`:\n\n```jsr\n{{for teams}}\n {{for members}}\n {{if #getIndex() > 0}} {{!-- index of member (- this view is an "item" view for member) --}}\n {{:#getIndex()}} {{!-- index of member --}}\n {{/if}}\n\n {{:#parent.getIndex()}}... {{!-- index of team (-nearest "item" view of parent is team "item" view) --}}\n {{/for}}\n{{/for}}\n```\n',anchor:"getindex"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"If index is a multiple of 3, render new tr, and format index in bold.\n\nUse `getIndex()` to get *item* index from within *if* block.\n\n```jsr\n\n\n{{for members}}\n {{if #index===0}}\n \n{{/for}}\n\n
            1:\n {{else #index%3===0}}\n
            {{:#getIndex()+1}}:\n {{else}}\n {{:#getIndex()+1}}:\n {{/if}}\n {{:name}}\n
            \n```"}],markup:"\n\n{{for members}}\n {{if #index===0}}\n \n{{/for}}\n\n
            1:\n {{else #index%3===0}}\n
            {{:#getIndex()+1}}:\n {{else}}\n {{:#getIndex()+1}}:\n {{/if}}\n {{:name}}\n
            ",data:{title:"The A Team",members:[{name:"Jeff"},{name:"Jack"},{name:"Jim"},{name:"Jo"},{name:"Joanna"},{name:"James"}]},title:"getIndex() – iterating + grouping by 3",jsrJsvJqui:"jsr",height:"80"},{_type:"para",title:"The get(type) method:",text:'***view.get(type)**: returns the nearest parent view of type `type`.*\n\n```js\nvar arrayView = view.get("array"); // Step through parents to nearest "array" view\nvar arrayLength = arrayView.data.length; // Get length of data array\n```\n\nAccessed declaratively as `#get(...)`:\n\n```jsr\n{{for members}}\n {{if #index+1 === #get("array").data.length}}\n The last member in the list\n {{/if}}\n{{/for}}\n```\n\n**Note:** An additional signature is available: ***view.get(true, type)*** (for advanced scenarios) -- which steps *down* through descendant views (depth first traversal) and returns *the first descendant view of type `type`*.\n\n```jsr\n{{for members}}\n {{:name}}\n{{/for}}\n{{:#get(true, "item").data.name}} {{!-- get the name of the first member --}}\n```\n\nIn using this API it is sometimes necessary to be aware of the processing order. For example in the sample code above, placing `{{:#get(true, "item")...}}` before `{{for members}}` will not return any "item" view, since the `{{:get(...)...}}` is being evaluated during the rendering, and the "item" views for `{{for ...}}` will not yet have been rendered. (View instantiation is part of rendering, which is a single-pass process.) \n\n*Note:* `view.get("root")` returns [`view.root`](#viewobject@root), `view.get()` returns [`view.parent`](#viewobject@parent) and `view.get(true)` returns [`view.views[0]`](#viewobject@other).',anchor:"get"},{_type:"para",title:"The content property (for views which wrap inline block content):",text:'***view.content**: template corresponding to the inline block content.*\n\nAccessed declaratively as `#content`:\n\nIn the [wrapping content](#tagsyntax@wrap) scenarios, the tag:\n\n```jsr\n{{sometag ... tmpl="externalTmpl"}}...{{/sometag}}\n```\n\nor\n\n```jsr\n{{mytag}}...{{/mytag}}\n```\n\nwill render with a view which has both a `view.tmpl` template property and a `view.content` template property.\n\nThe `view.content` template corresponds to the inline block content, and is used for wrapping that content as in:\n\n```jsr\nbefore {{include tmpl=#content /}} after\n```\n',anchor:"content"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*mytag:* \n\n```js\n$.views.tags(\n "mytag",\n "startTag {{include tmpl=#content /}} endTag"\n);\n```\n\n*externalTmpl:* \n\n```js\n$.templates(\n "externalTmpl",\n "startTmpl {{include tmpl=#content /}} endTmpl"\n);\n```\n\n*Template:* \n\n```jsr\n{{mytag}}\n
            inside mytag
            \n{{/mytag}}\n\n
            \n\n{{mytag tmpl="externalTmpl"}}\n
            inside mytag with external tmpl
            \n{{/mytag}}\n```\n'}],html:'
            \n\n\n', +code:'$.views.tags(\n "mytag",\n "startTag {{include tmpl=#content /}} endTag"\n);\n\n$.templates(\n "externalTmpl",\n "
            startTmpl {{include tmpl=#content /}} endTmpl
            "\n);\n\n$("#result").html(\n $.templates("#myTmpl").render()\n);\n',jsrJsvJqui:"jsr",title:"view.content – wrapping content",height:"170"},{_type:"para",title:"The root property:",text:"***view.root**: the root view (top-level ancestor view for this view)* -- as in:\n\n```js\nvar topLevelData = view.root.data; // Get the top-level data (obtained from the root view)\n```",anchor:"root"},{_type:"para",title:"The ctxPrm() 'get' method",text:'***view.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the view).\n\n```js\nvar value = view.ctxPrm("color");\n// Get value of contextual parameter (or helper) "color"\n```\n\nAvailable also as [`tag.ctxPrm()`](#tagobject@ctxprm).\n\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\n\n(*Note:* in JsRender, the `ctxPrm()` method is used only for *getting* the value, whereas in JsViews, [`ctxPrm()`](#jsvviewobject@ctxprm) can also be used for *setting* the value.)',anchor:"ctxprm"},{_type:"para",title:"Other view object properties and methods:",text:'The following additional properties of the `view` object are used by JsRender for processing templates:\n\n- *tmpl*: the template used to render the view\n- *views*: the child views in the view hierarchy\n- *ctx*: object (hash) with the named contextual helpers/template parameters for this view\n- *tag*: the `"mytag"` view rendered by a custom tag `{{mytag ...}}`, has a `view.tag` property -- the instance of the `mytag` tag object\n- *getRsc(namedCollection, itemName)*: returns a named resource (*converter* function, compiled *template* object, compiled *tag*, *helper* or *viewModel*), as available contextually in the scope of the view (i.e. global, or local as a template resource from one of the parent templates)

            The `namedCollection` parameter can be `"templates"`, `"converters"`, `"tags"`, `"helpers"` or `"viewModels"`). For example:\n ```js\n var upperCvtFunction = view.getRsc("converters", "upper");\n ```',anchor:"other"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsvviewobject",label:"JsViews view object"},{_type:"topic",hash:"views",label:"View hierarchy"}]}]},tagobject:{title:"The tag object (JsRender)",path:"",sections:[{_type:"para",title:"Tag object properties and event handlers provided as tag options",text:"The following tag properties and event handlers can be specified as tag options in the [`$.views.tags()`](#tagsapi) call, when registering a custom tag:\n\n*Tag properties*\n\n- [`baseTag`](#tagsapi@basetag)\n- [`flow`](#tagsapi@flow)\n- [`template`](#tagsapi@template)\n- [`bindTo`](#tagsapi@bindto)\n- [`ctx`](#tagobject@ctx)\n- [`contentCtx`](#tagsapi@contentctx)\n- [`argDefault`](#tagsapi@argdefault)\n\n*Event handlers*:\n\n- [`init()`](#tagsapi@init)\n- [`render()`](#tagsapi@render)\n- [`convert()`](#tagsapi@convert)"},{_type:"para",title:"Additional properties and methods on the tag object",text:"In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\n\n*Tag properties*\n\n- [parent](#tagobject@parent)\n- [parents](#tagobject@parents)\n- [tagCtx](#tagobject@tagctx)\n- [tagCtxs](#tagobject@tagctxs)\n- [tagName](#tagobject@tagname)\n- [rendering](#tagobject@rendering)\n\n*Tag methods*\n\n- [ctxPrm()](#tagobject@ctxprm)\n- [cvtArgs()](#tagobject@cvtargs)\n- [bndArgs()](#tagobject@bndargs)\n- [base()](#tagobject@base)\n- [baseApply()](#tagobject@baseapply)",anchor:"propsmethods"},{_type:"para",title:"",text:"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `tag` object has many additional properties, methods and events. See [JsViews `tag` object](#jsvtagobject).*"},{_type:"para",title:"Accessing tag objects",text:"The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\n\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\n\n```jsr\n{{:~tag.parent.tagName}}`\n```\n\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\n\n```jsr\n{{:~tagCtx.props.mode}}`\n```"},{_type:"para",title:"Tag properties",text:" ",anchor:"properties"},{_type:"para",title:"The parent property",text:"***tag.parent**: the parent custom tag* (nearest ancestor custom tag) in the hierarchy of custom tags.\n\n```js\nvar outerTag = innerTag.parent;\n```\n\nAccessed declaratively as `~tag.parent`.\n\nSee *[Custom tag hierarchy -- Accessing parent tags](#tagsapi@parents)*",anchor:"parent"},{_type:"para",title:"The parents property",text:"***tag.parents**: a hash of all the ancestor custom tags.*\n\nFor example if `outerTag` is a `{{layout}}` tag:\n\n```js\nvar outerTag = innerTag.parents.layout;\n```\n\nAccessed declaratively as `~parentTags`.\n\nSee *[Custom tag hierarchy -- Accessing parent tags](#tagsapi@parents)*",anchor:"parents"},{_type:"para",title:"The tagCtx property",text:"***tag.tagCtx**: a [tag context](#tagctxobject) object* providing access to instance information such as arguments/properties/view etc., as in:\n\n```js\n var propA = tag.tagCtx.props.propA;\n```\n\nAccessed declaratively (in a tag template or wrapped content) as `~tagCtx`.\n\nSee [*Tag Context*](#tagsapi@context)",anchor:"tagctx"},{_type:"para",title:"The tagCtxs property",text:"***tag.tagCtxs**: an array of [tag context](#tagctxobject) objects, -- one for each {{else}} block*.\n\nThe first item in `tag.tagCtxs` is the `tag.tagCtx` object.\n\nIf the tag has `{{else}}` blocks, there will be an additional `TagCtx` object for each `{{else}}` block.\n\nAccessed declaratively as `~tag.tagCtxs`.\n\nSee [*Tag context objects for {{else}} blocks*](#tagsapi@tagctxs)",anchor:"tagctxs"},{_type:"para",title:"The ctx property",text:"***tag.ctx**: a [view context](#ctxobject) object (hash) providing access to the [contextual parameters](#contextualparams)*.\n\nAccessed declaratively as `~tag.ctx`.\n\nSee also:\n- [`tag.ctxPrm()`](#tagobject@ctxprm), below\n- The [`ctx` tag option](#tagsapi@ctx) (for specifying default context on a custom tag)",anchor:"ctx"},{_type:"para",title:"The tagName property",text:'***tag.tagName**: the name of the tag*.\n\n(e.g. `"mytag"` for the `{{mytag}}` custom tag.)',anchor:"tagname"},{_type:"para",title:"The rendering property",text:"***tag.rendering**: an object (hash) that is only present during rendering*.\n\nIt can be used to test whether the tag is currently rendering. It is also available as a means of passing parameters (application state) from one context to another, during rendering.",anchor:"rendering"},{_type:"para",title:"Tag methods",text:" ",anchor:"methods"},{_type:"para",title:"The ctxPrm() 'get' method",text:'***tag.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the tag instance).\n\n```js\nvar value = tag.ctxPrm("color");\n// Get value of contextual parameter (or helper) "color"\n```\n\nAvailable also as [`view.ctxPrm()`](#viewobject@ctxprm).\n\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\n\n(*Note:* in JsRender, the `ctxPrm()` method is used only for *getting* the value, whereas in JsViews, [`ctxPrm()`](#jsvtagobject@ctxprm) can also be used for *setting* the value.)',anchor:"ctxprm"},{_type:"para",title:"The cvtArgs() method",text:'***tag.cvtArgs()***: returns an array `[arg1, arg2, ...]`, corresponding to the values of the arguments passed in the tag markup.\n\n```jsr\n{{myTag lastName age \'edit\'/}}\n```\n\n```js\nvar args = tag.cvtArgs(); // ["Jones", 55, "edit"]\n```\n\nIf the tag uses a converter, then `cvtArgs(...)` will return the arguments *after* conversion.\n\nIf the tag uses multiple `{{else}}` blocks, then passing the `elseBlock` index as parameter to `cvtArgs(elseBlock)` returns the arguments for that `{{else}}` block.',anchor:"cvtargs"},{_type:"para",title:"The bndArgs() method",text:'If a tag uses a [`bindFrom/bindTo`](#tagsapi@bindto) setting, then ***tag.bndArgs()***: returns an array `[argOrProp1, argOrProp2, ...]`, corresponding to the values of the arguments/properties specified in the `bindFrom/bindTo` option.\n\nIf there is no `bindFrom/bindTo` setting, then `tag.bndArgs()` is equivalent to `tag.cvtArgs()`\n\n```jsr\n{{myTag lastName age mode=\'edit\'/}}\n```\n\n```js\n$.views.tags("myTag", {\n bindFrom: ["mode", 1, 0],\n init: function() {\n var args = tag.bndArgs(); // ["edit", 55, "Jones"]\n }\n)\n```\n\nIf the tag uses a converter, then arguments/properties returned by `bndArgs(...)` will be *after* conversion.\n\nIf the tag uses multiple `{{else}}` blocks, then passing the `elseBlock` index as parameter to `bndArgs(elseBlock)` returns the arguments/properties for that `{{else}}` block.\n\nSee also [*Specifying bound arguments and properties: the `bindTo` and `bindFrom` options*](#tagsapi@bindto)',anchor:"bndargs"},{_type:"para",title:"The base() method",text:"***tag.base()***: Used in a derived tag, when overriding a method/handler, to call the corresponding *base* method.\n\nAllows passing specific arguments.\n\n```js\nthis.base(a, b, ...); // Pass chosen arguments\n```\n\nSee [`baseTag`](#tagsapi@basetag)",anchor:"base"},{_type:"para",title:"The baseApply() method",text:'***tag.baseApply()***: Used in a derived tag, when overriding a method/handler, to call the corresponding *base* method.\n\nAllows passing on the `arguments` array (or some other chosen array of arguments).\n\n```js\nthis.baseApply(arguments); // Pass arguments array\n```\n\nExample:\n\n```\n$.views.tags("mytag2", {\n baseTag: "mytag",\n render: function() { // Override the render() method\n var ret = this.baseApply(arguments); // Call the base method\n ... // Modify return string...\n return ret;\n }\n});\n```\n\nSee [*Specifying tag inheritance: the `baseTag` option*](#tagsapi@basetag)',anchor:"baseapply"}]},ctxobject:{title:"The view context object, ctx (JsRender)",path:"",sections:[{_type:"para",title:"",text:"Each view has a view context object: ***view.ctx***, which is a 'hash' whose properties correspond to the set of [contextual parameters](#contextualparams), `~foo` accessible from that view, within a template. (See [*Accessing contextual parameters and helpers*](#tagsapi@ctxparams).)\n\nIt also has the following built-in properties (contextual parameters):\n\n- `ctx.root`: The [root data](#contextualparams@root) (accessed from a template as `~root`)\n- `ctx.tag`: The [tag object](#tagobject) (accessed from a template as `~tag`)\n- `ctx.tagCtx`: The [tagCtx object](#tagobject@tagctx) (accessed from a template as `~tagCtx`)\n- `ctx.parentTags`: [parent tags](tagsapi@parents) (accessed from a template as `~parentTags`)\n\nFor programmatic access to contextual parameters, it may be better to use the [view.ctxPrm()](#viewobject@ctxprm) or [tag.ctxPrm()](#tagobject@ctxprm) API."}]},tagctxobject:{title:"The tag context object, tagCtx (JsRender)",path:"",sections:[{_type:"para",title:"",text:"When a template is rendered, each tag is instantiated.\n\n```jsr\n{{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr .../}}\n```\n\nThe tag instance has an associated tag context object, `tag.tagCtx`, giving contextual information for the tag.\n\nSee [*Tag context*](#tagsapi@context)\n\nIn the case of a tag with `{{else}}` blocks it has an array of `tagCtx` objects, `tag.tagCtxs`, one for each `{{else}}` block):\n\n```jsr\n{{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr ...}}\n ...\n{{else argExpr2 prop2=propExpr2 ~ctxprm2=prmExpr2 ...}}\n ...\n{{/sometag}}\n```"},{_type:"para",title:"tagCtx properties",text:"- ***tagCtx.props:***\n - a hash of the values of the named properties (such as `tagCtx.props.prop1`)\n- ***tagCtx.args:***\n - an array with argument value (such as `tagCtx.args[0]`)\n- ***tagCtx.params:***\n - provides access to argument, property and contextual parameter expressions (such as `tagCtx.params.props.prop1`, `tagCtx.params.args[0]` or `tagCtx.params.ctx.ctxprm1`)\n- ***tagCtx.content:***\n - for a block tag (see [wrapping block content](#tagsapi@wrapping)), the compiled template for wrapped content\n - otherwise, for a tag with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, the compiled external template (same as `tagCtx.tmpl`)\n - otherwise, `false`\n- ***tagCtx.tmpl:***\n - for a tag with an external template, `tmpl=...`, the compiled external template\n - otherwise, for a block tag, the template for wrapped content (same as `tagCtx.content`)\n - otherwise, `false`\n- ***tagCtx.index:***\n - for `{{else}}` blocks, the index of the block (see [`tag.tagCtxs`](#tagobject@tagctxs))\n - otherwise, `0`\n- ***tagCtx.tag:***\n - the tag instance\n- ***tagCtx.view:***\n - the contextual (containing) view object\n- ***tagCtx.ctx:***\n - the [ctx](#ctxobject) (view context) object with the contextual helpers/template parameters for this tag.",anchor:"properties"},{_type:"para",title:"tagCtx methods",text:'- ***tagCtx.render(data, context, noIteration):***\n - if there is a tag template, renders the template\n - otherwise for a template with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, renders the external template\n - otherwise, for a block tag, renders the wrapped content\n - otherwise, returns `""`\n - *Note:* as an alternative, to render wrapped content even if there is a tag template, or an external template (`tmpl-=...`), use
            ***tagCtx.content.render(data, context, noIteration)***. (See [sample](#tags@renderplustmpl-sample))\n- ***tagCtx.ctxPrm(name):***\n - equivalent to [`tag.ctxPrm(name)`](#tagobject@ctxprm)\n - however, for a tag with `{{else}}` blocks such as:\n ```jsr\n {{mytag}}...{{else ~myparam=...}}...{{/mytag}}\n ```\n the context is the specific `{{else}}` block -- e.g. accessing `tag.tagCtxs[1].ctxPrm("myparam")` for the example above\n- ***tagCtx.cvtArgs():***\n - equivalent to [`tag.cvtArgs()`](#tagobject@cvtargs)\n - however, for a tag with `{{else}}` blocks) the context is the specific `{{else}}` block
            \n -- i.e. equivalent to `tag.cvtArgs(tagCtx.index)`\n- ***tagCtx.bndArgs():***\n - equivalent to [`tag.bndArgs()`](#tagobject@bndargs)\n - however, for a tag with `{{else}}` blocks) the context is the specific `{{else}}` block
            \n -- i.e. equivalent to `tag.bndArgs(tagCtx.index)`',anchor:"methods"},{_type:"para",title:"",text:"*Note:* When using JsViews data-linking, the tagCtx object has additional [properties](#jsvtagctxobject@properties) and [methods](#jsvtagctxobject@methods). See JsViews [`tagCtx`](#jsvtagctxobject) object.\n"}]},"node/browserify":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Browserify support for JsRender and JsViews\n\n[Browserify](http://browserify.org/) lets you create modular JavaScript projects for the browser, using the npm `require()` pattern for packages/modules.\n"},{_type:"para",title:"JsRender as a Browserify module",text:"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the Browserify client script bundle, and loaded in the browser.\n\nThere are three options for loading JsRender in the browser as a Browserify module:\n\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the Browserify client script bundle:\n ```js\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\n ```\n- Load both jQuery and JsRender as modules in the Browserify client script bundle:\n ```js\n var $ = require('jquery'); // Load jQuery as a module\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\n ```\n- Load JsRender as a module in the Browserify client script bundle, without loading jQuery at all:\n ```js\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\n ```\n\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \n\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \n\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\n",anchor:"jsrender"},{_type:"para",title:"Example – jQuery loaded globally:",text:"**index.html:**\n\n```jsr\n\n \n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"Example – jQuery loaded as module:",text:"**index.html:**\n\n```jsr\n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nvar $ = require('jquery'); // Load jQuery as a module\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"Example – JsRender without jQuery:",text:"**index.html:**\n\n```jsr\n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\nvar tmpl = jsrender.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\ndocument.querySelector('#container').innerHTML = html;\n```\n\n**command line:**\n\n```bash\nbrowserify ./source.js > ./bundle.js\n```"},{_type:"para",title:"JsViews as a Browserify module",text:"JsViews can also be included in the Browserify client-script bundle, and loaded in the browser.\n\nAfter installing on the server (using `$ npm install jsviews`), call:\n\n```js\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\n```\n\nor -- if also loading jQuery as a Browserify module, use:\n\n```js\nvar $ = require('jquery');\n...\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as a parameter)\n```",anchor:"jsviews"},{_type:"para",title:"Loading templates as Browserify modules",text:"JsRender includes a Browserify transform: `jsrender/tmplify` (see [below](#node/browserify@clientbundle)) which allows you also to include your server [file-based templates](#node/filetmpls) in the client-script bundle generated by Browserify. \n\nYou can then access the compiled templates in the browser, as modules.\n\nThe exact syntax depends on whether jQuery is loaded globally, loaded as a Browserify module, or not loaded at all.\n\n- If jQuery is loaded globally then use:\n ```js\n var tmpl = require('./templates/myTemplate.html'); // Load template (jQuery \n // is loaded globally)\n var html = tmpl.render(myData);\n ...\n ```\n- If jQuery is loaded as a module, use:\n ```js\n var $ = require('jquery');\n ...\n var tmpl = require('./templates/myTemplate.html')($); // Load template (local\n // jQuery as parameter)\n var html = tmpl.render(myData);\n ...\n ```\n- If loading JsRender as a module, without jQuery, use:\n ```js\n var jsrender = require('jsrender')(); // function call -- no parameter\n ...\n var tmpl = require('./templates/myTemplate.html')(jsrender); // Load template (jsrender\n // namespace as parameter)\n var html = tmpl.render(myData);\n ...\n ```\n\n**Note on relative paths:** The `./...` paths used to identify bundled templates are always interpreted as relative paths *relative to the location of your calling script*, which in this case is the Browserify script that created the client bundle. (Note that declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths)."},{_type:"para",title:"Nested templates",text:'Template inclusion in the bundle can be recursive, so for example if you call `require("./templates/myTemplate.html");` and *myTemplate.html* includes a nested reference to another template, such as `{{include tmpl="./another/tmpl2.html"/}}`, then the client-script bundle will include that template too.\n'},{_type:"para",title:"Generating the client bundle",text:"If *source.js* includes template references such as: `var tmpl=require('./some/path/myTemplate.html')`, then Browserify generates a client script bundle which will include the referenced templates.\n\n[Browserify](http://browserify.org/) provides three different ways of generating a *bundle.js* script from a *source.js* script, and calling a transform:\n\n**Command line:**\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\n**package.json:**\n\n```bash\n\"browserify\": {\n \"transform\": [\n [\"jsrender/tmplify\"]\n ]\n}\n```\n\n**API:**\n\n```bash\nbrowserify('./source.js')\n .transform(require('jsrender/tmplify'))\n .bundle()\n .pipe(fs.createWriteStream('./bundle.js'));\n```",anchor:"clientbundle"},{_type:"para",title:"Option: extensions",text:"The `jsrender/tmplify` Browserify transform uses a white-space-separated list of extensions: `\"html jsrender jsr\"`, by default. This means that when you generate a client-script bundle using the `tmplify` transform, it will treat any `.html`, `.jsrender` or `.jsr` file as a template, and will include the compiled template in the client-script bundle for rendering in the browser. \n\nYou can instead specify a different list of file extensions for templates, by using the `--extensions` or `-e` option, as in the following examples:\n\n```bash \nbrowserify -t [jsrender/tmplify --extensions 'htm jsrender'] ./source.js > ./bundle.js\n```\n\n```bash \nbrowserify -t [jsrender/tmplify -e 'htm jsrender'] ./source.js > ./bundle.js\n```\n\n```bash \n\"browserify\": {\n \"transform\": [\n [\"jsrender/tmplify\", {\n \"extensions\": \"htm jsrender\"\n }]\n ]\n}\n```\n\n```bash \nbrowserify('./source.js')\n .transform(require('jsrender/tmplify'), {extensions: 'htm jsrender'})\n .bundle()\n .pipe(fs.createWriteStream('./bundle.js'));\n```"},{_type:"para",title:"Including jQuery and/or JsRender/JsViews in the client-script bundle",text:"When using Browserify with JsRender on Node.js, you will generally need jQuery and JsRender/JsViews in the client, to render (and optionally data-link) the templates.\n\njQuery, JsRender and JsViews are all available as npm/Browserify modules, so you can choose whether to load them globally, using a script block, or as a module. Here are three examples following alternative strategies:\n\n**Load jQuery and JsRender/JsViews globally**\n\n`$` is defined as a global variable (`window.$`, or `window.jQuery`).
            \nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n\n\n...\n\n```\n\n*source.js:*\n\n```js\nvar myTmpl = require('./templates/myTemplate.html'); // Include compiled template in client-script bundle\nvar html = myTmpl(data); // Render using compiled template\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\nSee the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project for complete examples:\n- [clientcode-hello.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-hello.js) and [layout-hello.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello.html) using JsRender\n- [clientcode-movies.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-movies.js) and [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) using JsViews.\n \n**Load jQuery and JsRender/JsViews as Browserify modules**\n\nUse `var $ = require('jquery')` to load jQuery, and `require('jsrender')($)` or `require('jsviews')($)` to load JsRender/JsViews.
            \nUse `require(templatePath)($)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n...\n\n```\n\n*source.js:*\n\n```js\nvar $ = require('jquery');\nrequire('jsrender')($);\nvar myTmpl = require('./templates/myTemplate.html')($)\nvar html = myTmpl(data);\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\nSee:\n- [clientcode-hello-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify.js) and [layout-hello-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify.html) for an example loading jQuery and JsRender as modules\n- [clientcode-hello-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-hello-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading JsRender as a module (without jQuery)\n- [clientcode-movies-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-movies-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading jQuery and JsViews as modules\n\n**Mixed approach: Load jQuery globally, and JsRender/JsViews as a Browserify module**\n\n`$` is defined as a global variable (`window.$` or `window.jQuery`).
            \nUse `require('jsrender')` or `require('jsviews')` to load JsRender/JsViews.
            \nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\n\n*index.html:*\n\n```jsr\n\n...\n\n```\n\n*source.js:*\n\n```js\nrequire('jsrender');\nvar myTmpl = require('./templates/myTemplate.html');\nvar html = myTmpl(data);\n$('#result').html(html);\n```\n\n*command line:*\n\n```bash\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\n```\n\nSee [clientcode-movies-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-movies-browserify.js) and [layout-movies-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies-browserify.html) for an example using JsViews.",anchor:"clientscript"},{_type:"para",title:"Sample code",text:"For running code examples using JsRender, Browserify, and the `tmplify` transform, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project."},{_type:"para",title:"See also:",text:"*[Webpack support](#node/webpack)*"}]},"node/renderfile":{title:"renderFile() method",path:"",sections:[{_type:"para",title:"",text:"JsRender on Node.js provides a shortcut `renderFile` method, for convenience, to compile and render in one step:\n\n```js\nvar jsrender = require('jsrender');\n\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n// result: Name: Jim
            \n```\n"}]},"node/filetmpls":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## File-based templates"},{_type:"para",title:"Defining templates as .html files",text:"On Node.js, JsRender templates can be stored directly in the file system (e.g. as `.html`, `.jsr.` or `.jsrender` files) -- for example:\n\n**Template:** *./templates/myTemplate.html* -- with contents:\n\n```jsr\nName: {{:name}}
            \n```\n\n**Code:** JsRender recognizes file paths (for valid relative file paths starting with `'./'`), so you can write:\n\n```js\nvar jsrender = require('jsrender');\n\nvar tmpl = jsrender.templates('./templates/myTemplate.html'); // Compile the template\n\nvar html = tmpl({name: \"Jim\"}); // Render\n// result: Name: Jim
            \n```\n\n**Note:** The `./...` paths are always interpreted as relative paths *relative to the location of your calling script*. Declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths."},{_type:"para",title:"renderFile() method",text:"JsRender on Node.js provides a shortcut `renderFile()` method, for convenience, to compile and render in one step:\n\n```js\nvar jsrender = require('jsrender');\n\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n// result: Name: Jim
            \n```"},{_type:"api",typeLabel:"API:",title:"jsrender.renderFile(filepath, data)",name:"renderFile",object:"jsrender",method:!0,returns:"string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"filepath",type:"string",optional:!1,description:"Relative path to template file - starting with './'"},{_type:"param",name:"data",type:"object or array",optional:!0,description:"The data to render. This can be any JavaScript type, including Array or Object."}],args:[],sections:[],example:"var jsr = require('jsrender');\nvar html = jsr.renderFile('./.../tmpl.html', data);",description:"Load file-based template, compile and render against data"}],description:"Shortcut method – compile and render",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Nested calls to file-based templates (composition)",text:"JsRender's awareness of Node.js file paths (relative paths starting with `'./'`) means your templates can include recursive calls to other templates (partials). You don't need to register or compile those templates separately. (See also: [template composition](#tagsyntax@composition)).\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\nName: {{:name}}
            Address: {{include tmpl='./templates/other/addressTemplate.jsr'}}\n```\n\n**Template:** *./templates/other/addressTemplate.jsr*:\n```jsr\nStreet: {{:street}}\n```\n\n**Code:** Compile and render, recursively:\n\n```js\nvar jsrender = require('jsrender');\n\nvar tmpl = jsrender.templates('./templates/personTemplate.html');\n// Compile template - and also any recursively called templates\n\nvar html = tmpl({name: \"Jim\", street: \"Main St\"});\n// result: Name: Jim
            Address: Main St\n```",anchor:"composition"},{_type:"para",title:"Register a file-based template by name – and render it",text:'For convenience you can register file-based templates by name, just as you can for [templates from strings](#d.templates@namedfromstring).\n\n```js\n// Register named template - "myTmpl1\n$.templates("myTmpl1", "./templates/myTemplate.html");\n\n// Render named template\nvar html = $.templates.myTmpl1(person);\n\n// Alternative syntax: var html = $.render.myTmpl1(person);\n```\n' +},{_type:"para",title:"Automatic caching of file-based templates",text:"The first time `jsrender.templates('./templates/myTemplate.html')` is called, JsRender will:\n\n - load the template file from the file system\n - compile the template\n - cache the template\n - return the compiled template\n\nThe cached template can be accessed directly as `jsrender.templates['./templates/myTemplate.html']` - and can also be deleted by calling `delete jsrender.templates['./templates/myTemplate.html']`, or `jsrender.templates('./templates/myTemplate.html', null)`\n\nOn subsequent calls, JsRender will simply:\n - return the compiled template\n\nThe caching means you can load and compile the template during server initialization, and avoid the cost of reading the file or compiling during HTTP requests:\n\n```js\njsrender.templates('./templates/myTemplate.html'); // Cache the compiled template\n\napp.get('/...', function(req, res) {\n res.render('myTemplate', {name: \"Jim\"}); // Render previously cached template, using Express\n});\n```\n\nSimilarly when using the alternative forms for rendering templates:\n\n```js\napp.get('/...', function(req, res) {\n var tmpl = jsrender.templates('./templates/myTemplate.html'); // Get previously cached template\n var html = tmpl.render({name: \"Jim\"});\n res.send(html);\n});\n```\n\nor \n\n```js\napp.get('/...', function(req, res) {\n // Render previously cached template\n var html = jsrender.renderFile('./templates/myTemplate.html', {name: \"Jim\"});\n res.send(html);\n});\n```"},{_type:"para",title:"Using the same template on the server and in the browser",text:"JsRender lets you easily use the same templates for both server and browser rendering. See *[server/browser templates](#node/server-browser)* for details on two alternative approaches, one with the `{{clientTemplate}}` tag, and the other using *Browserify*."}]},jsrnode:{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"Quickstart",text:"See the [JsRender Node.js Quickstart](#jsr-node-quickstart) for an overview of JsRender support in Node.js"},{_type:"links",title:"Detail topics:",links:[],topics:[{hash:"node/install",label:"Installation and usage"},{hash:"node/filetmpls",label:"File-based templates"},{hash:"node/express-hapi",label:"Express and Hapi integration"},{hash:"node/server-browser",label:"Server/browser shared templates"},{hash:"node/browserify",label:"Browserify support"}]}]},"node/install":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Installation\n\nOn Node.js from the command line, install jsrender:\n\n```bash\n$ npm install jsrender\n```\n\n## Usage\n\nLoad the jsrender module:\n\n```js\nvar jsrender = require('jsrender');\n```\n\nNow call JsRender APIs, or use [Express](#node/express-hapi@express) or [Hapi](#node/express-hapi@hapi) integration, for server-rendering of JsRender templates.\n\n(For loading JsRender in the browser using Browserify or webpack, see *[JsRender as a Browserify module](#node/browserify@jsrender)* and *[JsRender as a webpack module](#node/webpack@jsrender)*)\n"},{_type:"para",title:"JsRender APIs on the server – same as in the browser!",text:"In the browser, when jQuery is present, JsRender loads as a jQuery plugin and adds APIs to the jQuery namespace object, as:\n\n`$.views`, `$.templates` and `$.render` \n\nOn the server exactly the same APIs are provided, associated instead with the `jsrender` namespace:\n\n`jsrender.views`, `jsrender.templates` and `jsrender.render`.\n\nFor convenience you can call the namespace `$` and then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy from the regular browser examples/samples -- as if in the browser with jQuery.\n\nFor example:\n\n```js\nvar $ = require('jsrender'); // Returns the jsrender namespace object - referenced for convenience as var $\n\nvar tmpl = $.templates('Name: {{:first}} {{upper:last}}'); // Compile template from string\n\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\n \nvar data = {first: 'Jo', last: 'Ryan'};\n\nvar html = tmpl(data); // Or alternative syntax: var html = tmpl.render(data);\n// result: \"Name: Jo RYAN\" \n```",anchor:"apis"},{_type:"para",title:"Using helpers, converters, custom tags...",text:'On Node.js you can use the full set of JsRender features, template tags and APIs, just as you would in the browser -- by simply using the `jsrender` namespace object returned from `require(\'jsrender\')`, instead of the jQuery object, `$`. In addition you can take advantage of [file-based templates](#node/filetmpls).\n\n**Custom Tags example:** -- For example, here is the JsRender Quickstart *[Custom Tags Sample](#jsr-quickstart@customtags)*, as you might write it on Node.js:\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\nName: {{fullName person/}}\n```\n\n**Code:**\n\n```js\nvar jsrender = require(\'jsrender\');\n\njsrender.views.tags("fullName", "{{:first}} {{:last}}"); // Register custom tag\n\nvar tmpl = jsrender.templates(\'./templates/personTemplate.html\'); // Compile template\n\nvar html = tmpl({person: {first: "Jim", last: "Varsov"}}); // Render\n// result: "Jim Varsov"\n```\n\n**Helpers example:** -- And here is the JsRender Quickstart *[Helpers](#jsr-quickstart@helpers)* example, in a version for Node.js:\n\n**Template:** *./templates/personTemplate.html*:\n\n```jsr\n{{:~title}} {{:first}} {{:~upper(last)}}\n```\n\n**Code:**\n\n```js\nvar jsrender = require(\'jsrender\');\n\nvar myHelpers = {\n upper: function(val) { return val.toUpperCase(); },\n title: "Sir"\n};\n\nvar tmpl = $.templates(\'./templates/personTemplate.html\');\n\nvar data = {first: "Jim", last: "Varsov"};\n\nvar html = tmpl(data, myHelpers);\n// result: "Sir Jim VARSOV"\n```\n\nOr we can register helpers globally:\n\n```js\njsrender.views.helpers(myHelpers);\n\nvar data = {first: "Jim", last: "Varsov"};\nvar html = tmpl(data);\n// result: "Sir Jim VARSOV"\n```'},{_type:"para",title:"Additional API: jsrender.compile()",text:"On NodeJS, an additional `jsrender.compile(...)` API is available, as an alternative to `jsrender.templates(...)`. This is provided for compatibility with standard APIs, and for better integration with platforms such as Hapi:\n\nThe following:\n\n```js\n// Compile template from file\nvar tmpl1 = jsrender.compile('./templates/mytmpl.html');\n\n// Compile template from markup string\nvar tmpl2 = jsrender.compile('Name: {{name}}');\n```\n\nis equivalent to:\n\n```js\n// Compile template from file\nvar tmpl1 = jsrender.templates('./templates/mytmpl.html');\n\n// Compile template from markup string\nvar tmpl2 = jsrender.templates('Name: {{name}}');\n```\n\n**Note:** both the above APIs allow [passing in additional template options](#d.templates@resources), such as associated converter resources:\n\n```js\n// Compile template from markup string, and provide options\nvar tmpl3 = jsrender.compile('Name: {{upper:name}}', {\n converters: {upper: ...}\n});\n```\n\nor equivalently:\n\n```js\n// Compile template from markup string, and provide options\nvar tmpl3 = jsrender.templates({\n markup: 'Name: {{upper:name}}',\n converters: {upper: ...}\n});\n```",anchor:"compile"}]},"node/express-hapi":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Express and Hapi integration"},{_type:"para",title:"Using Express to render templates",text:"In Express you can use JsRender APIs to render the template, as in the examples above, then return the html in the HTTP response:\n\n```js\napp.get('/...', function(req, res) {\n res.send(html);\n});\n```\n\nBut alternatively you can register JsRender as template engine for Express:\n\n```js\nvar jsrender = require('jsrender');\n\napp.engine('html', jsrender.__express); // Set JsRender as template engine for .html files\napp.set('view engine', 'html'); \napp.set('views', __dirname + '/templates'); // Folder location for JsRender templates for Express\n```\n\nRender template *./templates/myTemplate.html* -- content: `Name: {{:name}}
            `:\n\n```js\napp.get('/...', function(req, res) {\n res.render('myTemplate', {name: \"Jim\"}); \n // result: Name: Jim
            \n});\n```",anchor:"express"},{_type:"para",title:"Using Hapi to render templates",text:"JsRender also has built-in support as template engine for [Hapi](http://hapijs.com/):\n\nSet JsRender as the template engine for Hapi:\n\n```js\nvar jsrender = require('jsrender');\n\nserver.register(vision, function (err) {\n ...\n server.views({\n engines: { html: jsrender },\n relativeTo: __dirname,\n path: 'templates'\n });\n```\n\nUse Hapi to render a template:\n\n```js\nserver.route({\n method: 'GET',\n path: '/',\n handler: function (request, reply) {\n return reply.view('myTemplate', myData);\n }\n});\n```",anchor:"hapi"}]},"node/server-browser":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Sharing the same templates between server and browser\n\nJsRender lets you share templates between server and client, using either of the *Browserify* or *{{clientTemplate}}* approaches shown below."},{_type:"para",title:"Browserify",text:"Using Browserify with the `jsrender/tmplify` transform allows you to include your server [file-based templates](#node/filetmpls) in the Browserify client-script bundle. \n\nYou can then access the compiled templates in the browser, as modules, using:\n\n```js\nvar tmpl = require('./.../myTemplate.html)`\nvar html = tmpl.render(myData);\n...\n```\n\nFor details, see the *[Browserify](#node/browserify)* topic.\n\nFor complete running samples, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project."},{_type:"para",title:"Rendering file-based templates in the browser: {{clientTemplate}}",text:'JsRender also provides a `{{clientTemplate}}` tag that makes file-based templates available for rendering in the browser without needing to use Browserify.\n\nSimply include `{{clientTemplate "templateFilePath..."}}` in the layout template, for any template you want to expose in the browser:\n\n```jsr\n\n {{clientTemplate "./templates/myTemplate.html" /}}\n\n\n
            \n\n\n```\n\nSee the *index-express.js* and *index-hapi.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.'},{_type:"para",title:"JsRender on the server, JsRender or JsViews in the browser...",text:'Both the *Browserify* and the *{{clientTemplate}}* approach to sharing templates between server and browser let you then render or link those templates in the browser, using JsRender or JsViews.\n\nIn the browser, you reference the templates using the same `./file/path/template.html` syntax as on the server. \n\nFor example, in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* samples, the [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) template contains the following:\n\n```html\n\n {{include tmpl="./templates/movie-list.html"/}}\n\n```\n\nHere, the `{{include ...}}` is used on the server to do initial rendering of the movies list using the *movie-list.html* template. Then in the browser, the `data-link="{include ...}` causes JsViews to access the same template in the browser, and provide dynamic data-binding of the list...\n'},{_type:"para",title:"Single Page Apps with initial rendering on server",text:'An important scenario is a *single page app* using JsRender or JsViews in the client to create dynamic UI, combined with initial rendering of the content on the server by JsRender using the same template.\n\nThis can bring many advantages, including SEO, and eliminating flicker when the page is refreshed with a new server request.\n\n*Note:* To completely eliminate flicker on data-linked content which has already been rendered on the server, it is sometimes useful to use the syntax `data-link="...^{...}"` -- which data-links without doing the initial render. Here is an example from [movie-detail.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/movie-detail.html) in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)*:\n\n```html\n
            \n```\n'}]},tagsyntax:{title:"Tag syntax",path:"",sections:[{_type:"para",title:"",text:'Template tags in JsRender use the Mustache style: `{{...}}`.
            \n(You can choose different delimiters, such as `<%...%>`, using `$.views.settings.delimiters("<%", "%>")`.\n'},{_type:"para",title:"Tags without content",text:"The most common JsRender tags are [`{{: pathOrExpr}}`](#assigntag) -- which inserts the value of the path or expression, and [`{{> pathOrExpr}}`](#htmltag) which inserts the *HTML-encoded* value of the path or expression. \n\nThose tags, along with the *allow code* tag [`{{* ...}}`](#allowcodetag) and *comment tag* [`{{!-- ... --}}`](#commenttag), are self-contained tags which do not wrap other content:\n\n**Built-in tags without content:**\n\n```jsr\n{{: pathOrExpr}} (value)\n{{> pathOrExpr}} (HTML-encoded value)\n{{* mycode}} (using code)\n{{!-- this is a comment --}} \n```"},{_type:"para",title:"Block tags – tags with content: ",text:"**All other built-in tags, as well as all custom tags, use the block tag syntax:**\n\n```jsr\n{{include ...}}...{{/include}} or {{include .../}}\n{{for}}...{{/for}} or {{for.../}}\n{{props}}...{{/props}} or {{props .../}}\n{{if}}...{{/if}} or {{if .../}}\n{{myCustomTag}}...{{/myCustomTag}} or {{myCustomTag .../}}\n```\n\nTags using the *block tag syntax* have *open* and *close* tags, with content, or else they use the self-closing syntax, without content:\n\n**Block tag with content**\n\n```jsr\n{{sometag ...}}\n content\n{{/sometag}}\n```\n\n**Self-closing block tag (empty tag) -- no content:**\n\n```jsr\n{{sometag .../}}\n```\n\n",anchor:"blocktag"},{_type:"para",title:"Using tmpl=... to reference content as an external template",text:"A particular case of self-closing syntax is when any block tag uses the named property `tmpl=...` to reference an external template, which then replaces what would have been the block content.\n\nThis is a very useful technique for encapsulation and reuse of tag content. The content becomes a *'partial'* -- and is included thanks to template composition:\n\n**Self-closing block tag referencing an external template:**\n\n```jsr\n{{sometag ... tmpl=.../}}\n```\n\n(See for example `{{for languages tmpl=\"#columnTemplate\"/}}` in [this sample](#samples/jsr/composition/tmpl).)\n",anchor:"tmplref"},{_type:"para",title:"Template composition (partials)",text:"The most common way of composing templates is to have a layout template, and to use `{{include tmpl=... /}}`:\n\n```jsr\ntop level content\n{{include tmpl='myInnerTemplate' /}}\n```\n\nBut in fact template composition can be done by adding references to external templates using `tmpl=...` on ***any*** tag, as shown in the previous section.\n\n**Dynamic composition**\n\nNote that the `tmpl=...` can use any expression, so you can assign different nested templates dynamically based on data or context. For example you might write `{{include tmpl=~getTemplate(type) /}}` -- where `~getTemplate(...)` is a helper which returns a different template based in this case on the `type` property of the current data item.\n\nIn fact when setting `tmpl=...` dynamically, the returned template can be in any if the following forms:\n- a compiled template\n- a markup string\n- the name of a registered template\n- a selector\n- (on Node.js) a file path to a template",anchor:"composition"},{_type:"para",title:"Tag arguments and named properties",text:'Tags can take both unnamed arguments and named properties:\n\n```jsr\n{{sometag argument1 param1=...}}\n content\n{{/sometag}}\n```\nAn example of a named property is the `tmpl=...` property mentioned above:\n\n```jsr\n{{for languages tmpl="#columnTemplate"/}}\n```\n\nArguments and named properties can be assigned values from simple data-paths such as:\n\n```jsr\n{{formattedAddress address.street format=~util.formats.upper /}}\n```\n\nor from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\n\n```jsr\n{{productValue product.quantity*3.1/4.5 description=name.toUpperCase() /}}\n```\n',anchor:"tagparams"},{_type:"para",title:"Wrapping content ",text:'If a tag has an external `tmpl=...` reference, ***and*** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (one or more times), thanks to the [`view.content`](#viewobject@content) or `#content` property:\n\n```jsr\n{{sometag ... tmpl="externalTmpl"}}\n inline block content\n{{/sometag}}\n```\n\n```js\n$.templates("externalTmpl", "before {{include tmpl=#content /}} after";\n```\n\nSimilarly, a custom tag can use a built-in template which wraps the inline content:\n\n \n```jsr\n{{mytag}}\n inline block content\n{{/mytag}}\n```\n\n```js\n$.view.tags("mytag", {\n ...\n template: "before {{include tmpl=#content /}} after"),\n ...\n});\n```',anchor:"wrap"},{_type:"para",title:"Block tags with {{else}}",text:'Some block tags provide features which involve using alternative content blocks. Block tag syntax supports this by allowing the content to be separated into two or more alternative content blocks, using `{{else}}` tags as separators:\n\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\n\n```jsr\n{{if firstExpression}}\n render this if the firstExpression is true\n{{else secondExpression}}\n else render this if the secondExpression is true\n{{else}}\n else render this\n{{/if}}\n```\n\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\n\n```jsr\n{{for members}}\n Member Name: {{:name}}\n{{else}}\n There are currently no members...\n{{/for}}\n```\n\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\n\n```jsr\n{{tabs caption="First Tab"}}\n first tab content\n{{else caption="Second Tab"}}\n second tab content\n{{/tabs}}\n```'},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsrtags",label:"Template tags"},{_type:"topic",hash:"paths",label:"Paths and expressions"}]}]},views:{title:"JsRender view hierarchy",path:"",sections:[{_type:"para",title:"A view is a rendered template/block tag",text:'Each instance of a rendered template or a template [block tag](#tagsyntax@blocktag) is associated with a JsViews [*"view"* object](#viewobject).\n\nFor example, if the following template is rendered, and inserted into the page --\n\n```jsr\n\n```\n\n```js\nvar team = {title: "The A team", members: [{name: "Jeff"}, {name: "Maria"}]};\n\nvar html = $("#teamTemplate").render(team);\n```\n\n-- then the rendered result will have the following *view structure*:\n\n
            \n— teamView                (Team: The A team)\n   — ifView               (The team has members!)\n
            \n\n\nEach view is associated with a [`view`](#viewobject) object, which provides APIs for accessing properties of that view, as well as for accessing parent or child views in the view hierarchy.'},{_type:"para",title:"The data context of a view",text:'In particular, a [`view`](#viewobject) has a [`data`](#viewobject@data) property, which is the *current data context* used for rendering that *view* (rendering that template, or inline block content):\n\n
            \n— teamView                data: team\n   — ifView               data: team\n
            \n',anchor:"datacontext"},{_type:"para",title:"Inline block content / external 'tmpl=...' reference: same view hierarchy...",text:'A view corresponds to an instance of a *[block tag](#tagsyntax@blocktag)* ***or*** a *rendered template* -- so if we replace the inline content of a tag by an external reference: `tmpl=...`, the rendered result will be unchanged, and *the view structure will also be identical*:\n\n```jsr\n\n\n\n```\n\nSame view structure as before:\n \n
            \n— teamView                data: team\n   — ifView               data: team\n
            ',anchor:"nestedtmpl"},{_type:"para",title:"Stepping into a block tag – what is the new data context?",text:'Let\'s add a custom tag `{{mytag}}` to our template:\n\n```jsr\nMy team\n{{mytag members/}}\n...\n```\n\nWe\'ll define the custom tag, with a built-in template:\n\n```js\n $.views.tags("mytag", "{{:length}} member(s)");\n```\n\n`{{mytag members/}}` will render block content (with an associated view) using its tag template `"{{:length}} members"`. \n\n*What will the data context be for the `mytag` view?*\n\nBy default:\n\n- a block tag with no argument `{{sometag}}` will stay on the current data context\n- a block tag with an argument `{{sometag expr ...}}` will move the data context to `expr`.\n\nSo `{{mytag members}}` (just like `{{include members}}`) *will move the data context to `members`*.',anchor:"innerdata"},{_type:"para",title:"",text:'However a block tag may be designed to simply stay on the same data context as the parent block -- and that is the case for the `{{if}}` tag:\n\n- `{{if expr}}` does not move the data context.\n\nSo our template\n\n```jsr\n\n```\n\nwill have this view structure:\n\n
            \n— teamView                data: team\n   — mytagView            data: team.members\n   — ifView               data: team (same as parent – teamView)\n
            \n'},{_type:"para",title:"Array views and item views – {{for array}}",text:'Now let\'s add a `{{for members}}` tag to iterate over the `members`, inside the `{{if}}` block:\n\n```jsr\nTeam\n{{mytag members/}}\n\n{{if members.length}}\n Members:\n {{for members}}\n {{:name}}\n {{/for}}\n{{/if}}\n```\n\nWhen a [`{{for ...}}`](#propstag) tag is used with an array it creates:\n\n- an *"array" view*, whose `data` property is the array -- and under the "array" view:\n- an *"item" view* for each item in the array -- with as `data` property the item, and as [`index`](#getindex) property the index in the array:\n\n(Similarly, any tag which derives from the `{{for}}` tag -- such as the [`{{props}}`](#propstag) tag -- will also add an "array" view and "item" views...)\n\nSo our view structure with the `{{for}}` tag included will now be :\n\n
            \n— teamView                data: team                 type: "data"\n   — mytagView            data: team.members         type: "mytag"\n   — ifView               data: team                 type: "if"\n      — arrayView         data: team.members         type: "array"\n         — itemView       data: team.members[0]      type: "item"\n         — itemView       data: team.members[1]      type: "item"\n
            \n\n-- where we show also the [`type`](#viewobject@type) property of each `view`.',anchor:"itemview"},{_type:"para",title:"Array views and item views – tmpl.render(array)",text:'Suppose now we have an array of teams -- and we pass the `teams` array to the `render()` method:\n\n```js\nvar teams = [\n {title: "A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n```\n\nJsRender will render the `teamTemplate` once for each team -- and just like with the `{{for}}` it will create an *"item" view* for each item in the `teams` array -- with the two *"item" views* as children of an *"array" view*.\n\nHere it is as a working sample:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var html = $("#teamTemplate").render(teams);\n'}],markup:"",html:'\n\n
            ',code:'// mytag: custom tag to output "1 member" or "n members"\n$.views.tags("mytag", "{{:length == 1 ? \'1 member\' : length + \' members\'}}
            ");\n// Alternative version of mytag:\n// $.views.tags("mytag", "{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
            ");\n\nvar teams = [\n {title: "The A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "The B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"86"},{_type:"para",title:"",text:'And here is the resulting view structure:\n\n
            \n— arrayView               data: teams\n   — itemView             data: teams[0]               (Team: The A Team - )\n      — mytagView         data: team.members           (2 members)\n      — ifView            data: teams[0]               (Members:)\n         — arrayView      data: teams[0].members\n            — itemView    data: teams[0].members[0]    (Jeff)\n            — itemView    data: teams[0].members[1]    (Maria)\n   — itemView             data: teams[1]               (Team: The B Team - )\n      — mytagView         data: team.members           (1 members)\n      — ifView            data: teams[1]               (Members:)\n         — arrayView      data: teams[1].members\n            — itemView    data: teams[1].members[0]    (Francis)\n
            \n'},{_type:"para",title:"The default argument for a tag is the current data – #data",text:"For all built-in tags (and custom tags if you don't use the [argDefault](#tagsapi@argdefault) option), you can pass the current data to the tag by writing it without an argument.\n\nSo the following:\n\n```jsr\n{{:}} {{!--Render value of current data (string)--}}\n{{>}} {{!--Render value of current data (string)--}}\n{{for}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\n{{if}}...{{/if}} {{!--Render block if current data is truthy--}}\n{{props}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\n```\n\nare equivalent to:\n\n```jsr\n{{:#data}} {{!--Render value of current data (string)--}}\n{{>#data}} {{!--Render value of current data (string)--}}\n{{for #data}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\n{{if #data}}...{{/if}} {{!--Render block if current data is truey--}}\n{{props #data}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\n```"},{_type:"para",title:"In JsViews: From UI back to data:",text:"***Note:*** One of the features provided by JsViews data-linking (when you use the JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method) is the [`$.view(elem)`](#$view) method. This method provides a *reverse mapping* and lets you get from a rendered DOM element back to the corresponding view object in the view hierarchy. From the view you can get to the underlying data, the index, etc.\n\nSo in effect in JsViews, *the mapping from the view hierarchy to the UI becomes a two-way mapping...* \n\nSee [*Using $.view() to get from the rendered UI back to the data*](#jsv.d.view)",anchor:"#$view"},{_type:"links",title:"See also:",links:[],topics:[{hash:"getindex",label:"getIndex()"},{hash:"contextualparams",label:"Contextual parameters"},{hash:"parentdata",label:"Accessing parent data"}]}]},paths:{title:"Paths and expressions",path:"",sections:[{_type:"para",title:"",text:'JsRender tags can take [unamed arguments, or named properties](#tagsyntax@tagparams):\n\n```jsr\n{{:arg0}}\n\n{{sometag arg1 arg2 param_a=param1 param_b=param2}}\n content\n{{/sometag}}\n```\n\nThe values of the arguments or properties (such as `arg0`... `param1` ... above) must be valid JsRender paths or expressions.\n\nJsRender expressions are regular Javascript expressions, but with *no access to global variables*.\n\nInstead of global Javascript variables, JsRender expressions use *data paths*, *helper paths* and *view paths*, to access data values, values provided by helpers, and values obtained from the [view hierarchy](#views), such as the `#getIndex()`.\n\n***Data paths*** are of the form `dataProperty.bb.cc`, and they step through the data hierarchy, starting from the current data item (the [data context](#views@datacontext) for the current view). They can include array access, such as `team.members[id]`\n\n***View paths*** are of the form `#viewProperty.bb.cc`, and they start from the current [view](#views). So for example, `#data` is short for `#view.data` -- where `#view` is the current view.\n\n***Helper paths*** are of the form `~myHelper.bb.cc`, and they start from the named [helper](#helpers) `"myHelper"`. In addition they can be used to access *[contextual parameters](#contextualparams)*, or the built-in [`~root`](#contextualparams@root) \n\nHere are some examples of JsRender paths and values:\n\n*Data paths*:\n\n```jsr\n{{:name}}\n{{for address.street}}...{{/for}}\n{{>team.members[0].lastName}}\n{{:name.toUpperCase()}}\n```\n\n*Helper paths*:\n\n```jsr\n{{>~utilities.errorMessages.msg1}}\n{{if ~settings.show}}...{{/if}}\n{{:~root.selectedName}} {{!--Accessing root data--}}\n```\n\n*View paths*:\n\n```jsr\n{{:#getIndex()}}\n{{include #content /}}\n{{if #parent.parent.data.isLead}}...{{/if}}\n{{>~getDescription(#data)}}\n```\n\n*A primitive value of type string, number, boolean, null ...*:\n\n```jsr\n{{if isOpen tmpl=\'It is open\' /}}\n{{for address tmpl="#addressTemplate"}}...{{/for}}\n{{for members start=1 end=5 /}}\n{{for members reverse=true /}}\n```\n\nJsRender expressions can combine values in more complex expressions, using functions, parens, operators such as `+` `-` `*` `/` `!` `===` `==` `>` `!==` `||` `&&`, as well as ternary expressions: `...?...:...`, array and object accessors: `[...]` etc.\n\n*Here are some examples of expressions*: \n\n```jsr\n{{if book.author === "Jim Boyd"}}...{{/if}}\n{{:~utilities.format(book.title, \'upper\', true)}}\n{{for ~sort(~root.getMembers()}}}...{{/for}}\n{{:person.firstName + \' \' + person.lastName.toUpperCase()}}\n{{for #parent.data.members()/}}\n{{:(~addRebate(book.price) + 23.2)*3.5/2.1}}\n{{:~mode === "useTitle" ? book.title : book.name}}\n{{if error}}...{{else !utilities.valid(book.description)}}...{{else}}...{{/if}}\n{{:~books[id].title}}\n{{:people[~currentIndex].name}}\n```\n\nExpressions can include white space. The following two examples are equivalent:\n\n```jsr\n{{averageValue product.quantity*3.1/4.5 description=~getDescription(#data) /}}\n{{averageValue product.quantity * 3.1 / 4.5 description = ~getDescription( #data ) /}}\n```\n\nThe `{{averageValue}}` tag is being assigned one argument, and one named "description" parameter. The two expressions differ only in white space, and both are syntactically valid. However, removing optional white space -– as in the first example -– makes it easier to see the distinct arguments and parameters of the tag.\n' +},{_type:"para",title:"Chained paths: Stepping through object properties (or functions)",text:"All of the paths above (whether *Data/Helper/View paths*) involve starting from an initial value (a *current data item property/helper/view property*) -- and then, if it is an object, perhaps stepping through one or more chained properties.\n\nFor example `team.manager.address.street` starts from a `team` object and steps through the `manager` property -- which is itself a 'person' object with an `address` property, etc. \n\n(See also *[Data-linked paths](#linked-paths)*.)",anchor:"paths"},{_type:"para",title:"Computed properties",text:"In some cases a property may be of type *function* (possibly taking parameters), so you might have:\n\n`team.manager().getAddress('home').street`\n\n-- where the manager property is in fact a *'getter'* function which returns a `person` object, which has a `getAddress()` parameterized accessor (taking `'home'` or `'work'` -- or maybe a Boolean `isHomeAddress`). Similarly a path can include an array accessor such as `team.members['id'].address`.\n\nProperties of type function -- returning a value -- are referred to as a *computed properties*, or *getter properties*, and
            \n`team.manager().getAddress('home').street` is an example of chained computed properties.\n\n(See also *[Computed properties and computed observables](#computed)* -- for using computed properties with JsViews and data-linking.)\n\nA computed value can also use JavaScript methods, such `toFixed()` to format a number:\n\n```jsr\n{{:price.toFixed(2)}} \n{{:(+price).toFixed(2)}} \n```",anchor:"computed"},{_type:"para",title:"Getter properties and computed properties",text:"A common pattern using computed 'getter' functions would be to provide a `person.firstName()` 'getter' property which returns a value: `person._firstName`, considered as 'private'.\n\nIn addition, there may be computed properties which depend on other properties, such as a `person.fullName()` which concatenates first and last name.\n\nHere is a sample showing both types of computed property:\n"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Data:*\n\n```js\nfunction firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nvar data = {\n person: {\n _firstName: "Jo",\n _lastName: "Blow",\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n }\n};\n```\n\n*Template:*\n\n```jsr\n First name: {{:person.firstName()}}\n Last name: {{:person.lastName()}}\n Full name: {{:person.fullName()}}\n```'}],code:'function firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nvar data = {\n person: {\n _firstName: "Jo",\n _lastName: "Blow",\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n }\n};\n\nvar html = $("#personTmpl").render(data);\n\n$("#result").html(html);',html:'
            \n\n',height:"72",jsrJsvJqui:"jsr",title:"Getter properties with plain objects",anchor:"getter-plain-sample"},{_type:"para",title:"Getter properties on a View Model",text:"Rather than using plain JavaScript objects with getter functions, as above, a more common pattern (providing better encapsulation) would be to define a *'View Model'* class -- with getter properties defined in the class -- and to instantiate that class to provide data instances.\n\n(See *[Plain objects or View Model](#explore/objectsorvm)* for details.)\n\nThe following sample uses that approach:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Data:*\n\n```js\nfunction firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nfunction Person(first, last) {\n this._firstName = first;\n this._lastName = last;\n}\n\nPerson.prototype = {\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n};\n\nvar data = {\n person: new Person("Jo", "Blow")\n};\n```\n\n*Template:*\n\n```jsr\n First name: {{:person.firstName()}}\n Last name: {{:person.lastName()}}\n Full name: {{:person.fullName()}}\n```'}],html:'
            \n\n',jsrJsvJqui:"jsr",height:"72",code:'function firstName() { return this._firstName; }\nfunction lastName() { return this._lastName; }\nfunction fullName() { return this._firstName + " " + this._lastName; }\n\nfunction Person(first, last) {\n this._firstName = first;\n this._lastName = last;\n}\n\nPerson.prototype = {\n firstName: firstName,\n lastName: lastName,\n fullName: fullName\n};\n\nvar data = {\n person: new Person("Jo", "Blow")\n};\n\nvar html = $("#personTmpl").render(data);\n\n$("#result").html(html);',title:"Getter properties with a View Model",anchor:"getter-vm-sample"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"tagsyntax",label:"Tag syntax"},{_type:"topic",hash:"settings/allowcode@security",label:"Expressions and security"}]}]},tmplsyntax:{title:"Template syntax and structure",path:"",sections:[{_type:"para",title:"",text:"The following topics provide information on JsRender template syntax:"},{_type:"links",title:"",links:[],topics:[{hash:"tagsyntax",label:"Tag syntax"},{hash:"paths",label:"Paths and expressions"},{hash:"views",label:"View hierarchy"}]}]},settings:{title:"Settings",path:"",sections:[{_type:"para",title:"",text:"JsRender provides the following APIs for modifying settings:"},{_type:"links",title:"",links:[],topics:[{hash:"settings/delimiters",label:"Delimiters"},{hash:"settings/debugmode",label:"Debug mode"},{hash:"settings/allowcode",label:"Allow code"}]}]},"settings/delimiters":{title:"Setting tag delimiters for JsRender",path:"",sections:[{_type:"para",title:"",text:"See also *[Setting tag delimiters for JsViews](#jsvsettings/delimiters)*"},{_type:"para",title:"JsRender default tag delimiters",text:"Template tags in JsRender use the Mustache style: `{{...}}`\n\n(JsRender also accepts the data-linked tag syntax used in in JsViews: `{^{...}}`). "},{_type:"para",title:"Changing delimiters:",text:'Sometimes there can be a need to use different delimiters. For example there may be a conflict if the template is being rendered on the server using a declarative syntax such as *Django* with the same default delimiters `{{` and `}}`.\n\nThe following call:\n\n```js\n$.views.settings.delimiters("<%", "%>");\n```\n\nwill change the tag syntax to `<%...%>`.\n\nThe chosen delimiters must each consist of two non-alphanumeric characters. \n\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `["<%", "%>"]`, which can be useful for reverting to a previous set of delimiters -- as shown in the last sample [below](#settings/delimiters@tmpl-for-tmpl). )\n'},{_type:"para",title:"Verifying current setting for tag delimiters:",text:'```js\nvar delimiters = $.views.settings.delimiters();\n// Returns an array ["{{", "}}", "^"] - JsRender tag delimiters (and JsViews link character)\n```\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Markup:* \n\n```jsr\n\n```\n\n*Code*\n\n```js\n$.views.settings.delimiters("[%", "%]");\n\nvar tmpl = $.templates("#peopleTmpl");\n...\n```'}],html:'
            \n\n',code:'$.views.settings.delimiters("[%", "%]");\n\nvar tmpl = $.templates("#peopleTmpl");\n\nvar team = {\n title: "A team",\n members: [{name: "Jo"}]\n };\n\nvar html = tmpl.render(team);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"70",title:"Choosing alternative tag delimiters, with JsRender"},{_type:"para",title:"Using alternative delimiters to 'render a template with a template'",text:"In some scenarios you might want to use a template to generate a template, such as a template on the server to generate/render a template that will then be used in the browser.\n\nA good approach to achieving this is to use a different set of delimiters on the server.\n\nA similar scenario is to use a 'base' template to render different versions of a template for different languages/localities, as in this example:\n",anchor:"tmpl-for-tmpl"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n<%:hello%>, {{:name}}
            \n<%:welcome%> {{:place}}\n```\n\n```js\n// Get current delimiters array\nvar currentDelimiters = $.views.settings.delimiters();\n\n// Temporarily switch delimiters\n$.views.settings.delimiters("<%", "%>");\n\n// Translate to Spanish localized version\nvar localizedTemplate = $.templates("#baseTmpl").render(spanishTerms);\n\n// Revert to original delimiters (by passing in previous delimiters array)\n$.views.settings.delimiters(currentDelimiters);\n\n// Render data using localized template\nhtml = $.templates(localizedTemplate).render(data);\n```'}],html:'\n\n
            \n',code:'var spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Get current delimiters array\nvar currentDelimiters = $.views.settings.delimiters();\n\n// Temporarily switch delimiters\n$.views.settings.delimiters("<%", "%>");\n\n// Translate to Spanish localized version\nvar localizedTemplate = $.templates("#baseTmpl").render(spanishTerms);\n\n// Revert to original delimiters (passing in previous delimiters array)\n$.views.settings.delimiters(currentDelimiters);\n\n// Render data using localized template\nhtml = $.templates(localizedTemplate).render(data);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"54",title:"Template for a template"},{_type:"para",title:"",text:"Incidentally the above scenario of localized terms in a template can be achieved without the 'build step' of creating localized templates, simply by passing in the terms as helpers, distinct from the data itself."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Pass in localized terms as helpers\nvar html = $.templates("#tmpl").render(data, spanishTerms );\n```'}],html:'\n\n
            \n',code:'var spanishTerms = {\n hello: "Hola",\n welcome: "Bienvenido a"\n};\n\nvar data = {\n name: "John",\n place: "Madrid"\n};\n\n// Pass in localized terms as helpers\nvar html = $.templates("#tmpl").render(data, spanishTerms );\n\n$("#result").html(html);\n',height:"54",title:"Passing in terms as helpers",anchor:"passing",jsrJsvJqui:"jsr"}]},"settings/onerror":{title:"onError",path:"",sections:[]},"settings/dbgmode":{title:"dbgMode",path:"",sections:[]},"settings/debugmode":{title:"Setting debug mode",path:"",sections:[{_type:"para",title:"",text:'JsRender has a *\'debug mode\'* setting which determines whether error messages encountered during rendering are displayed.\n\n***To get current debug mode:***\n\n```js\nvar isDebugMode = $.views.settings.debugMode(); // false by default\n```\n\n***To set debug mode:***\n\n```js\n$.views.settings.debugMode(...);\n```\n\nDebug mode can be set to any of the following:\n\n- `false` -- *errors during rendering will not be rendered* (but an exception will be thrown)\n- `true` -- no exception will be thrown, but *the error message will be rendered*, in place of the template tag or block\n- `"some string"` -- no exception. *The string `"some string"` will be rendered* in place of the tag or block\n- `""` (empty string) -- no exception. The tag or block will simply be *replaced by the empty string*\n- a function (to be used as an error handler) -- no exception. The handler will run, and *the error string will be rendered, or else, if the function returns a string, that string will be rendered*\n\nSee *[Error handling and debugging](#onerror)* for a full discussion of alternative approaches, together with [details and working examples](#onerror@debugmode) of `$.views.settings.debugMode(...)`.\n\n '}]},"settings/allowcode":{title:"Allow code",path:"",sections:[{_type:"para",title:"",text:"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\n\n```jsr\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\n```\n\n\n\nNevertheless, in order to improve encapsulation, security and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \n\nIf you want complete freedom to insert any code into a compiled template, you can set **allowCode** to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the [`{{* ...}}`](#allowcodetag) tag, or you can return (render into the template output) the result of evaluating any expression, using the [`{{*: ...}}`](#allowcodetag) tag.\n\n(*Note:* it is not recommended to set `allowCode` to true within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\n\n"},{_type:"para",title:"User-defined templates and security",text:"For most purposes there is no need to set `allowCode` to true, since the built-in template expressions provide rich functionality which is sufficient for most scenarios.\n\nJsRender can be used to render templates either on the server or in the browser -- and is often used for applications which allow users to create their own templates, or to insert markup and expressions into templates. With `allowCode` false, JsRender is designed to *make it impossible for such user-defined templates to run arbitrary code*.\n\nUsers can include rich template expressions in the template, but they won't be able to insert code that accesses any variables (or runs any methods) that are outside of the template scope. (They can only access the contextual data/model, use the standard operators, and use any helper methods and variables which the author decides to provide.)",anchor:"security"},{_type:"para",title:"To set allowCode to true, globally",text:"```js\n$.views.settings.allowCode(true);\n```\n(See samples for [`{{* ...}}` and `{{*: ...}}`](#allowcodetag@sample))\n \n"},{_type:"para",title:"To set allowCode back to false, globally",text:"```js\n$.views.settings.allowCode(false);\n```\n",anchor:""},{_type:"para",title:"To get current global allowCode setting",text:"```js\nvar allowCodeIsTrue = $.views.settings.allowCode(); // false by default\n```"},{_type:"para",title:"To set allowCode to true for a specific template",text:"```js\n$.templates(..., {\n markup: ...,\n allowCode: true,\n ...\n})\n```\n\n(See `{{* ...}}` and `{{*: ...}}` sample: *[allowCode for template](#allowcodetag@tmpl)*)."}]},onerror:{title:"Error handling and debugging",path:"",sections:[{_type:"para",title:"",text:"Sometimes when rendering a JsRender template, a JavaScript error is encountered. For example `{{:address.street}}` in a template will render without error provided there is an `address` property on the current data object. But if there is no `address` property, then *there will be an error*: ***\"Cannot read property 'street' of undefined\"***.\n\nJsRender provides two features which provide powerful control over rendering behavior when errors are encountered.\n\n- The optional [`onError=...` property](#onerror@onerror) that can be set on any tag -- for controlling error handling behavior on that specific tag\n- The [`$.views.settings.debugMode(...)` setting](#onerror@debugmode) -- which provides global control over error handling during rendering\n\nIn addition, for advanced debugging of compiled templates, see:\n\n- *[Using debugging helpers](#onerror@dbg)*\n\n
            \n## Specifying onError fallback behavior on a tag"},{_type:"para",title:"Setting onError to a string",text:'All JsRender tags (including custom tags) such as `{{address.street}}` or `{{for getItems()}}` allow you to provide a `onError` tag property, with a fallback string to render in the case of errors:\n\n```jsr\n{{:address.street onError="Address unavailable"}}\n```\n\n```jsr\n{{for phones() onError="No phones"}}\n```\n\n```jsr\n{{myCustomTag ... onError=""}}\n```\n\nThe `onError` fallback string will be rendered whenever there an error (or exception) is encountered during the tag rendering.\n\nSetting to the empty string ensures that errors are simply ignored, and the tag renders as the empty string.',anchor:"onerror"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'In this sample, if a `member` object has no `address` property, the `address.street` expression will lead to a JavaScript error, and the `{{:address.street onError="Address unavailable"}}` will render the fallback string: `"Address unavailable"`.\n\nSimilarly, `{{for phones() onError="..."}}`, if `phones()` produces an error... \n\n*Template:*\n\n```jsr\n{{for phones() onError="No phones"}} ...\n{{:address.street onError="Address unavailable"}}\n```\n\n*Code:*\n\n```js\nfunction phones() { if (!this._phones) { throw new Error("phones() error"); } ... }\n```\n\n*Data:*\n\n```js\nmembers: [\n {address: {street: "1st Ave"}, _phones: ["888", "456"], ...\n {address: undefined, _phones: ["987", "111"], ... // No address\n {address: {street: "Main St"}, _phones: undefined, ... // _No phones\n]\n```\n'}],html:'
            \n\n\n',markup:"",jsrJsvJqui:"jsr",data:[],code:'function phones() {\n if (!this._phones) {\n throw new Error("phones() error");\n }\n return this._phones;\n}\n\nvar team = {\n members: [\n {address: {street: "1st Ave"}, _phones: ["888", "456"],\n phones: phones},\n {address: undefined, _phones: ["987", "111"], // No address\n phones: phones},\n {address: {street: "Main St"}, _phones: undefined, // _No phones\n phones: phones}\n ]\n};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);',title:'onError="fallback string..." ',height:"164"},{_type:"para",title:"Setting onError to an expression",text:"More specific or powerful behavior can be obtained by setting onError to an expression, such as:\n\n```jsr\n{{:address.street onError=name + \" has no address\"}}\n```\n\n```jsr\n{{:address.street onError=~errorMessages(1, name, 'address')}}\n```"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{{for phones() onError=name + " has no phones"}} ...\n```\n\n```jsr\n{{:address.street onError=~errorMessages(1, name, "address")}}\n```\n\n```js\n$.views.helpers("errorMessages", function(id, param1, param2) {\n if (id === 1) { return param1 + " has no " + param2; } ...\n});\n```\n'}],html:'
            \n\n',code:'function phones() {\n if (!this._phones) {\n throw new Error("phones() error");\n }\n return this._phones;\n}\n\nvar team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}, _phones: ["888", "456"],\n phones: phones},\n {name: "Jane", address: undefined, _phones: ["987", "111"], // No address\n phones: phones},\n {name: "Ava", address: {street: "Main St"}, _phones: undefined, // _No phones\n phones: phones}\n ]\n};\n\n$.views.helpers("errorMessages", function(id, param1, param2) {\n if (id === 1) {\n return param1 + " has no " + param2;\n } \n});\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',height:"210",jsrJsvJqui:"jsr",title:"onError=someExpression..."},{_type:"para",title:"Setting onError to a function",text:'If `onError=myOnErrorHandler` is set to a function, then the function will be called when there is an error.\n\n- If the function returns a string, then that string will be rendered, replacing the output of the tag\n- If the function has no return value, then the error message will be rendered\n\nFor example, you can provide a `person.error()` error handler method on a person object, and set `onError=error`. Or you can use global helper (or a helper passed to the render function), and set `onError=~myErrorHandler`, such as the following to log the error and display just the empty string:\n\n```js\nfunction myErrorHandler(e, view) {\n console.log(...); // Log the error \n return ""; // Display the empty string \n}\n```\n\nThe parameters of the onError handler function -- `myHandler(e, view)` -- will be:\n\n- `e` -- the `error` object\n- `view` -- the current `view` object\n- The `this` pointer will be the current data item, `view.data`'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{{:address.street onError=~myOnError}}\n```\n```js\nfunction onErrorHandler(e, view) {\n console.log(e.message);\n if (!this.address) {\n return this.name + " has no address (" + e.message + ")";\n }\n}\n\nvar html = $("#teamTmpl").render(team, {myOnError: onErrorHandler});\n```'}],code:'var team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}},\n {name: "Jane", address: undefined} // No address\n ]\n};\n\nfunction onErrorHandler(e, view) {\n console.log(e.message);\n if (!this.address) {\n return this.name + " has no address (" + e.message + ")";\n }\n}\n\nvar html = $("#teamTmpl").render(team, {myOnError: onErrorHandler});\n\n$("#result").html(html);\n',html:'
            \n\n\n',height:"126",jsrJsvJqui:"jsr",title:"onError=~myOnError"},{_type:"para",title:"",text:"
            \n## Setting debug mode",anchor:""},{_type:"para",title:"",text:"The `$.views.settings.debugMode(...)` setting provides control of error handling during rendering, similar to the `onError` feature [above](#onerror@onerror), but operating at a global level rather than on individual tags.\n\nThese two approaches are complementary and can be used together. "},{_type:"para",title:"Setting debug mode to true",text:"- By default *debug mode* is **false** -- and *an exception will be thrown if a JavaScript error is encountered while rendering a tag or template*\n- If *debug mode* is set to **true** -- any error message encountered while rendering a tag *will replace the rendered content of that tag*\n\n***To set debug mode to true:***\n\n```js\n$.views.settings.debugMode(true);\n```\n\n***To set debug mode back to false:***\n\n```js\n$.views.settings.debugMode(false);\n```\n\n***To get current debug mode:***\n\n```js\nvar isDebugMode = $.views.settings.debugMode(); // false by default\n```\n\nIn the following example *debug mode* is set to `true`. The error message is rendered, replacing the rendered tag.\n\n(Choose *Try it* and change *debug mode* to `false`, to see the difference.)\n",anchor:"debugmode"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Code:*\n\n```js\n$.views.settings.debugMode(true);\n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by the error message.\n\n```js\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n...\n```\n\n*Template:*\n\n```jsr\n{{for members}}\n
            {{:name}} - {{:address.street}}
            \n{{/for}}\n```'}],code:'$.views.settings.debugMode(true); \n// Change to $.views.settings.debugMode(false); - The error\n// will not be displayed, but an exception will be thrown.\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',html:'
            \n\n\n',jsrJsvJqui:"jsr",height:"74",title:"Debug mode set to true"},{_type:"para",title:"",text:"The following example also illustrates setting *debug mode* to `true`, but this time it is used with JsViews, and the `link(...)` method, rather than JsRender and `render(...)`.\n\nThe error conditions can arise both in expressions within tags, such as `{^{:manager.name}}` and data-link expressions such as `\n {{if owner}}\n Owner: {^{:manager.name}}\n {{/if}}\n
            \nEdit: \n```\n\n*Code:*\n\n```js\n$.views.settings.debugMode(true);\n// Debug mode is set to true, so error messages are rendered in place of the corresponding tag or data-link expression.\n\nvar team = {owner:\n {name:"Jo"}\n}; // team.manager is undefined...\n...\ntmpl.link("#result", team); // Error...\n```\n\nIf you choose *Try it* and change to `$.views.settings.debugMode(false);`, the error will instead be thrown as an exception.\n'}],html:'\n
            \n\n\n\n',code:'$.views.settings.debugMode(true);\n\nvar team = {owner:\n {name:"Jo"}\n}; // team.manager is undefined...\n\nvar tmpl = $.templates("#teamTmpl");\n\ntmpl.link("#result", {team: team}); // Error...',height:"80",title:"Debug mode set to true – JsViews",anchor:"datalink"},{_type:"para",title:"Setting debug mode to a string",text:'By setting debug mode to a string rather than to `true`, no exception will be thrown, and the chosen string will be rendered, replacing the rendered tag. \n\n```js\n$.views.settings.debugMode("Error!");\n``` '},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.settings.debugMode("Error!"); \n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by `"Error!"`.'}],html:'
            \n\n\n',code:'$.views.settings.debugMode("Error!"); // Do not throw exception - render "Error!"\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',title:"Debug mode set to a default string",jsrJsvJqui:"jsr",height:"74"},{_type:"para",title:"",text:'In some scenarios the desired behavior may be to ignore errors during rendering, by skipping any tag with an error, rendering it as an empty string. This is achieved very easily, by simply writing:\n\n```js\n$.views.settings.debugMode("");\n``` '},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n$.views.settings.debugMode("");\n```\n\nThe `{{:address.street}}` tag for Bill (who has no address) is skipped.'}],title:"Debug mode set to empty string",code:'$.views.settings.debugMode(""); // Do not throw exception - render ""\n\nvar team = {members: [\n {name:"Jo", address: {street: "1st Ave"}},\n {name:"Bill"}, // Bill does not have an address!!\n {name:"Ava", address: {street: "Main St"}}\n]};\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',html:'
            \n\n\n',jsrJsvJqui:"jsr",height:"74"},{_type:"para",title:"Providing a debug mode handler (function)",text:'If debug mode is set to a function, the function will be called each time an error is encountered during rendering. \n\n- If the function returns a string, then that string will be rendered, replacing the rendered tag\n- If the function has no return value, then the error message will be rendered\n\n```js\n$.views.settings.debugMode(myOnErrorHandler);\n\nfunction myOnErrorHandler(e, fallback, view) {\n // This handler will log the error, and then display the empty string\n console.log(...);\n return ""; \n}\n```\n\nThe parameters of the debug mode error handler function -- `myHandler(e, fallback, view)` -- will be:\n\n- `e` -- the error object\n- `fallback` -- the fallback error string, provided by the *[onError fallback](#onerror@onerror)* specified on the tag, if there is one\n- `view` -- the current view object\n- The `this` pointer will be the current data item, `view.data`\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{:address.street onError='address'}}\n```\n\n```js\nfunction onErrorHandler(e, fallback, view) {\n console.log(e.message);\n if (fallback === \"address\") {\n return 'Address error for ' + this.name + '. (\"' + e.message + '\")';\n }\n}\n```\n\n```js\n$.views.settings.debugMode(onErrorHandler);\n```\n"}],html:'
            \n\n\n', +code:'var team = {\n members: [\n {name: "Bill", address: {street: "1st Ave"}},\n {name: "Jane", address: undefined} // No address\n ]\n};\n\nfunction onErrorHandler(e, fallback, view) {\n console.log(e.message);\n if (fallback === "address") {\n return \'Address error for \' + this.name + \'. ("\' + e.message + \'")\';\n }\n}\n\n$.views.settings.debugMode(onErrorHandler);\n\nvar html = $("#teamTmpl").render(team);\n\n$("#result").html(html);\n',title:"Debug mode – onError handler",jsrJsvJqui:"jsr",height:"116"},{_type:"para",title:"Advanced debugging, using debugging helpers",text:'***Inserting breakpoints during rendering:***\n\nJsRender (and JsViews) provide some helpers for debugging code within compiled templates:\n\n- The `{{dbg expression/}}` tag\n- The `{{dbg: expression}}` converter\n- The `~dbg(expression)` helper function\n\nEach of the above will\n- evaluate the expression\n- output a `console.log(...)` call\n- throw and catch an exception -- which you can use as a break point by *stopping on caught exceptions*\n- render the evaluated expression\n\nThis is done by inserting code into the compiled template which calls into the built-in *dbgBreak* code:\n\n```js\nfunction dbgBreak(val) {\n try {\n console.log("JsRender dbg breakpoint: " + val);\n throw "dbg breakpoint"; // To break here, stop on caught exceptions.\n }\n catch (e) {}\n```\n\n`val` will be the result of evaluating `expression`.\n\nWhen rendering execution breaks at the above code, you can then step up through the call stack to the compiled template code, for further debugging.\n\nUsage examples: `{{dbg:...}}`, `{{:~dbg(...)}}`, `{{dbg .../}}` etc.\n\n***Breakpoints during data linking:***\n\nIn JsViews, a breakpoint can also be inserted during template data-linking, as in `{^{for ... onAfterLink=~dbg}}`.\n\n___Using {{*debugger}}:___\n\nAn alternative (but similar) debugging technique is to use `allowCode` to insert a `debugger;` statement directly into the compiled template code, as follows:\n\n*Code:*\n\n```js\nvar tmpl = $.templates({\n markup: "#myTmpl",\n allowCode: true // Alternatively use global setting: $.views.settings.allowCode(true)\n});\n```\n\n*Template:*\n\n```jsr\n...\n{{*debugger}}\n...\n```',anchor:"dbg"}]},advanced:{title:"JsRender – advanced topics",path:"",sections:[{_type:"links",title:"",links:[],topics:[{hash:"onerror",label:"Error handling"},{hash:"settings/advanced",label:"Advanced settings"},{hash:"jsrobjects",label:"JsRender objects"}]}]},apps:{title:"Building apps",path:"",sections:[{_type:"para",title:"Apps using JsRender",text:"*JsRender* is a simple light-weight templating engine. It can be used in the browser within simple web pages, or within complex single-page apps, or in conjunction with other frameworks. It can also be used on the server, using *Node.js*.\n\nIt is highly flexible, expressive, and 'unopinionated' -- so it leaves you free to work within your own choice of overall application architecture (including architectures based on *MVVM*, *MVP* or *MVC* -- optionally with server/client integration), and lets you use your own flavor of data/model layer -- whether simple plain JavaScript objects, hand-coded *View Model* instances, or *[compiled View Models](#viewmodelsapi)*.\n\n\n"},{_type:"para",title:"Components of an app using JsRender",text:"Any app or web page using JsRender templates will generally involve defining or registering the following elements:\n\n- one or more **templates** -- see *[Templates](#compiletmpl)*\n- a **'data Layer'** -- see *[JsRender: Data or View Model](#jsrmodel)*\n- optionally, **helpers** -- in the form of metadata, helper functions and converter functions, see *[Helpers](#helpers)* and *[Converters](#converters)*\n- optionally, **reusable components** for use within your templates -- see *[Custom tags](#tags)*"},{_type:"para",title:"Apps using JsViews",text:"*JsRender* also provides optional integration with *JsViews*. *JsViews* is much more of a framework than *JsRender*. It does much more than just templating -- providing also data-binding, *MVVM* support, observability of the *data/View Model* layer, support for interactive encapsulated components (*JsViews tag controls*), and more. Nevertheless, it can also interoperate with other frameworks and components. See *[Building apps in JsViews](#jsvapps)* for more information."}]},getindex:{title:"Iterating over arrays: accessing the array index",path:"",sections:[{_type:"para",title:"",text:"If you pass an array to the JsRender [`.render(myArray)`](#rendertmpl) method, or if you use [`{{for myArray}}`](#propstag), in a template, JsRender will iterate over the array, and render an [*item view*](#views@itemview) for each item in the array.\n\nWithin an item view you can access the array-index of the current item, using `{{:#index}}`:\n\n- *Getting item index within a top-level item view (from `.render(myArray)`)*:\n\n ```jsr\n ...\n {{:#index}}\n ...\n ```\n\n- *Getting item index within a `{{for myArray}}` block*:\n\n ```jsr\n {{for myArray}}\n ...\n {{:#index}}\n ...\n {{/for}}\n ```\n\nIf there are additional nested tags, then from within the nested tags you can still access the index, by using `{{:#getIndex()}}`:\n\n- *Getting item index from nested tags within an item view*:\n\n ```jsr\n {{for myArray}}\n ...\n {{if ...}}\n ...\n {{:#getIndex()}}\n ...\n {{/if}}\n ...\n {{/for}}\n ```\n\nSee [`index`](#viewobject@index) and [`getIndex()`](#viewobject@getIndex) for additional details.\n"},{_type:"links",title:"See also",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"}]}]},contextualparams:{title:"Contextual parameters",path:"",sections:[{_type:"para",title:"Defining contextual parameters",text:'*Contextual parameters* provide a very convenient way of passing values in to nested tag contexts. (See *[View hierarchy](#views)*.)\n\nA contextual parameter is defined by simply writing `~myValue=...` (for any expression) on any block tag, such as `{{if}}` or `{{for}}`.\n\nThe resulting `~myValue` parameter can then be accessed within the block tag -- or deeper down within nested tag contexts, at any depth. \n\nFor example, the following template defines three contextual parameters, and uses them in nested contexts:\n\n```jsr\n...\n{{if isActive ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\n {{for members}}\n {{if ~teamIndex>2}}\n {{:~teamTitle}} {{:~teamData.description}}\n ...\n```\n\n*Note:* You can also set contextual parameters on `{{else}}` blocks, such as in the following example which uses the same template for the `{{if}}` and `{{else}}` blocks, but assigns different values to the `~teamTitle` parameter in each case:\n\n```jsr\n{{if isActive ~teamTitle=activeTitle tmpl="teamTmpl"}}\n{{else ~teamTitle=inactiveTitle tmpl="teamTmpl"}}\n{{/if}}\n```\n'},{_type:"para",title:"itemVar – contextual parameter for data 'item' of block",text:"The *itemVar* feature lets you set up a contextual parameter for the current data 'item' of a block. It is in effect an 'alias' for `#data` within the block.\n\nTo define an *itemVar* contextual parameter for a block tag, simply write `itemVar=~someName`. The parameter `~someName` can then be accessed like any other helper variable or contextual parameter, within nested contexts to any depth.\n\n```jsr\n...\n{{for teams itemVar=\"~team\"}}\n ...\n {{for members itemVar=\"~member\"}}\n ...\n {{if isActive}}\n {{:~team.title}} {{:~member.name}}\n```\n\nSee also [this sample](#fortag@itemvar).",anchor:"itemvar"},{_type:"para",title:"Accessing root data: the built-in '~root' contextual parameter",text:"The built-in contextual parameter `~root` provides direct access to the *root data* which was passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews). It can be accessed from anywhere within a template, at an level of nested tags.\n\n*Note:* If an array is passed to `render()` or `link()` then `~root` will be the array (so you can render `{{:root.length}}` for example).",anchor:"root"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"},{_type:"topic",hash:"tagsapi@ctxparams",label:"Accessing contextual parameters and helpers"}]}]},parentdata:{title:"Accessing parent data",path:"",sections:[{_type:"para",title:'Accessing "parent" data, from nested views. Passing in template variables',text:'When a template (containing nested template tags) is rendered, the result is a [view hierarchy](#views) -- where the views provide information on how the underlying data objects map to the rendered UI.\n\nOften it is helpful to be able to access the data for a *parent view* from a [*nested* template](#views@nestedtmpl) or [block](#tagsyntax@blocktag) (*nested view*).\n\nThere are several ways to get to *parent data*:\n\n- Create a *[contextual parameter](#contextualparams)* to pass a value to nested views.\n\n Here are three examples:\n\n ```jsr\n ...\n {{if ... ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\n ...\n {{for ...}}\n ...\n {{:~teamTitle}} {{:~teamData.title}} {{:~teamIndex}}\n ```\n\n- Use [`itemVar`](#contextualparams@itemvar) to provide a contextual parameter for the current data \'item\' of a block, to be passed in to deeper nested contexts \n\n ```jsr\n ...\n {{for members itemVar="~member"}}\n ...\n {{props}}\n ...\n {{:~member.name}}\n ```\n\n- Use the [`view.parent`](#viewobject@parent) property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\n\n ```jsr\n ...\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#parent.parent.data.title}}\n ```\n\n- Use the [`view.get(type)`](#viewobject@get) method to get to a parent view of a given `type`:\n\n ```jsr\n ...\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#get("if").data.title}}\n\n ```\n\n- Use the [`view.getIndex()`](#viewobject@getIndex) method to get to the index of a parent *"item"* view:\n\n ```jsr\n {{if ...}}\n ...\n {{for ...}}\n ...\n {{:#parent.getIndex()}}\n {{:#getIndex()}}\n ```\n\nHere is a sample showing all of these methods:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"This sample shows all the ways to get to *parent data* described in the section above:\n\n- Create a *contextual parameter* to pass a value to nested views.
            \n- Use `itemVar` to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \n- Use the `view.parent` property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\n- Use the `view.get(type)` method to get to a parent view of a given `type`:\n- Use the `view.getIndex()` method to get to the index of a parent *\"item\"* view:\n"}],html:'\n\n
            ',code:'// mytag: custom tag to output "1 member" or "n members"\n$.views.tags("mytag", "{{:length == 1 ? \'1 member\' : length + \' members\'}}
            ");\n// Alternative version of mytag:\n// $.views.tags("mytag", "{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
            ");\n\nvar teams = [\n {title: "The A Team", members: [{name: "Jeff"}, {name: "Maria"}]},\n {title: "The B Team", members: [{name: "Francis"}]}\n];\n\nvar html = $("#teamTemplate").render(teams);\n\n$("#result").html(html);',jsrJsvJqui:"jsr",height:"290"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"views",label:"View hierarchy"}]}]},jsrmodel:{title:"JsRender: Data / View Model",path:"",sections:[{_type:"para",title:"",text:"*JsRender* is designed to work well with either plain JavaScript objects and arrays, or with instances of JavaScript classes, such as *View Model* classes.\n\nSo, for example, if you are using data obtained from a JSON request, you can choose between:\n- rendering your templates directly against the objects and arrays returned from the JSON request\n- passing the data through a 'mapping' process to create a hierarchy of *View Model* instances, and rendering your templates against those objects\n\nThe *plain objects* [approach](#jsrmodel@plain) is convenient and simple for getting rapidly up and running with templates. But for more complex projects the *View Model* approach is better for creating clean well-designed modular code, where each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state.\n"},{_type:"para",title:"Using JsRender built-in compiled View Models",text:"*JsRender* will work well with your own 'hand-coded' *View Model* classes (see [below](#jsrmodel@vm)).\n\nBut in most cases it is simpler and better to use the [`$.views.viewModels(...)`](#jsrmodel@compilevm) API. This API lets you very easily and rapidly compile *View Model* classes for your own needs, following a standard pattern, and with some additional powerful features:\n\n- It provides a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\n- It also provides a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server.\n"},{_type:"para",title:"Data / View Model with JsViews",text:"All of the alternatives mentioned above (plain object hierarchies, hand-coded *View Model* classes, or JsRender *compiled View Model* classes) can also be used with *JsViews* data-binding and observable data. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)"},{_type:"para",title:"Example: JsRender with plain objects and arrays",text:" "},{_type:"code",title:"Suppose this is our data from a JSON request:",code:'var person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n'},{_type:"template",title:"We'll render using a template structured like this:",markup:"... \n{{:name}}\n...\n{{:address.street}}\n...\n{{for phones}}\n ... \n {{:number}}\n ...\n{{/for}}\n..."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name}} ..."},{_type:"code",title:"Render template against person (plain object)",code:'$("#result").html(tmpl.render(person));\n'}],html:'
            \n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Data: hierarchy of plain objects and arrays\nvar person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n\n// Render template against plain object hierarchy\n$("#result").html(tmpl.render(person));\n\n',height:"140",jsrJsvJqui:"jsr",title:"Render template directly against plain objects..."},{_type:"para",title:"",text:"Now we'll convert the above sample to use *View Model* classes."},{_type:"para",title:"Example: JsRender with 'hand-coded' View Model objects",text:"We'll convert the data to a corresponding hierarchy of simple 'hand-coded' *View Model* class instances. In each case we will replace properties by simple *getters*, and corresponding 'private' properties. ",anchor:"vm"},{_type:"para",title:"View Model classes:",text:"Here is the class definition for Person:\n\n```js\n// Constructor\nfunction Person(name, address, phones) {\n // Initialize private properties\n this._name = name;\n this._address = address;\n this._phones = phones;\n}\n\n// Prototype\nvar personProto = {\n // Define a getter for each property \n name: function() {\n return this._name;\n },\n address: function() {\n return this._address;\n },\n phones: function() {\n return this._phones;\n }\n};\n...\n```\n\nWe define exactly similar classes for our Address and Phone objects too.\n\nThe above pattern for *View Model* classes will work well with *JsRender*. (It will also work seamlessly with *JsViews* data-binding, if at some point you choose to upgrade to use *JsViews* features).\n\n*Note:* The standard JsRender *View Model* pattern provided by `$.views.viewModels` is similar, but provides also setters (along with optional *'observability'* for two-way binding in *JsViews*).",anchor:"handvm"},{_type:"para",title:"Getter functions",text:"Note that properties are now getter functions, which return the appropriate value (which may be of any type, including objects or arrays -- such as `address` and `phones` above).\n\nIn fact they are particular case of *[computed properties](#paths@computed)* -- a concept that can be used quite generally within *JsRender* and *JsViews*, not only for *View Model* properties.\n"},{_type:"para",title:"Template",text:"To convert our template from using plain objects to using *View Model* objects, the only change we need to make is to add parens for our properties, which are now getter functions:\n\n```jsr\n... \n{{:name()}}\n...\n{{:address().street()}}\n...\n{{for phones()}}\n ... \n {{:number()}}\n ...\n{{/for}}\n...\n```"},{_type:"para",title:"Instantiate and render:",text:"Now all we need to do is to construct our root `person` object (with its underlying hierarchy of *View Model* instance objects) and render the template against that object in the usual way."},{_type:"sample",typeLabel:"Sample:",codetabs:[{_type:"codetab",name:"",url:"samples/mvvm/person-view-models-jsr.js",label:"person-view-models-jsr.js"}],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n... {{:name()}} ...\n```"},{_type:"code",title:"Instantiate View Model hierarchy",code:'// Use previously defined View Model classes: Person, Address, Phone\nvar person = new Person(\n "Pete",\n new Address(\n "1st Ave"),\n [\n new Phone("111 111 1111"),\n new Phone("222 222 2222")\n ]\n );\n'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'}],html:'\n\n
            \n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Instantiate View Model hierarchy\nvar person = new Person(\n "Pete",\n new Address("1st Ave"),\n [\n new Phone("111 111 1111"),\n new Phone("222 222 2222")\n ]\n );\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));',height:"140",jsrJsvJqui:"jsr",title:"Render template against a View Model object hierarchy",anchor:"vmsample"},{_type:"para",title:"Using the same function as both getter and setter",text:'For properties which are read-write, the above *getter* functions can be replaced by a corresponding *getter/setter*, as follows: \n\n```js\nname: function(val) {\n if (!arguments.length) {\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is a value argument, treat as a setter\n},\n```\n\nNote that when *JsRender* renders a template using a *get/set* property `{{:name()}}` it will *always call the function as a getter, not as a setter*. However the *setter* feature lets you modify the value of `name()` from code, using:\n\n```js\nsomePerson.name("newName"); // setter\n```\n\nAlso, if you use the same *View Model* class with *JsViews* then the *setter* will be called:\n\n- when the user modifies a value with two-way data-binding such as ``\n- when using `$.observable(person).setProperty("name", "newName")` from code
            \n(See [JsViews Data/View Model](#jsvmodel) for details, and alternative *setter* patterns.)'},{_type:"para",title:"Adding methods and computed properties to the View Model ",text:"Typically a *View Model* does not only provide *getter* (or *get/set*) properties -- but also other methods or computed properties corresponding to the appropriate logic at that point in the application. For example, a *View Model* for a *Person* might include a `selectPhone(...)` method or a `fullName()` computed property.\n\n"},{_type:"para",title:"Example: Using JsRender compiled View Models, with $.view.viewModels(...)",text:"The built-in support in both *JsRender* and *JsViews* for compiled *View Models* makes it extremely easy to define *View Model* classes that include *get/set* properties using the pattern described above, along with any desired additional methods and computed properties. Simple calls to `$.views.viewModels(...)` allow you to compile *View Model* classes conforming to these patterns without having to manually write repetitive code for multiple such *get/set* properties.\n \nAnother advantage of the compiled *View Model* classes is when working with (or migrating to) *JsViews*. In that context the classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates.\n\nFor details on `$.views.viewModels` see: *[Compiled View Models](#viewmodelsapi)*.\n\nTo illustrate, let's convert our [sample above](#jsrmodel@vm) to use compiled *View Models*. At the same time we will add a `person.addPhone(...)` custom method to the `Person` *View Model* class, and we'll illustrate calling a setter -- `name(...)`:",anchor:"compilevm"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name()}} ..."},{_type:"code",title:"Compile View Model classes",code:'...\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"], // get/set properties\n extend: {addPhone: addPhone} // Additional methods or properties\n});\n...'},{_type:"code",title:"Instantiate View Model hierarchy using constructors",code:'var person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'},{_type:"code",title:"Call setter, call method...",code:'...\nperson.name("newName"); // Use the name(...) setter\n\n...\nperson.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method'}],html:'\n\n\n\n\n
            \n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(Phone(phoneNo));\n}\n\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"],\n extend: {addPhone: addPhone}\n});\n\n// Compile Address View Model\nvar Address = $.views.viewModels({getters: ["street"]});\n\n// Compile Phone View Model\nvar Phone = $.views.viewModels({getters: ["number"]});\n\n// Instantiate View Model hierarchy using constructors\nvar person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});',height:"190",jsrJsvJqui:"jsr",title:"Render template against a hierarchy of compiled View Model objects",anchor:"compilevmsample"},{_type:"para",title:"",text:"See also the [corresponding sample](#jsvviewmodelsapi@compilevmsample) with JsViews and data-linking (and [this version](#jsvmodel@compilevmsample) with two-way binding)."},{_type:"links",title:"For additional details and scenarios for compiled View Models, see:",links:[],topics:[{hash:"viewmodelsapi",label:"Compiled View Models"}]},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsv-model",label:"JsViews: Data/View Model"},{_type:"topic",hash:"computed",label:"Computed Observables"}]}]},helpersapi:{title:"Registering helpers: $.views.helpers()",path:"",sections:[{_type:"para",title:"",text:"`$.views.helpers()` is used to register helpers, accessed within templates using the syntax `~myhelper`. See *[Using helpers](#helpers)* for information about what *helpers* are, and some additional ways of providing them to templates.\n\nThis topic provides more details.\n\nWith `$.views.helpers(...)` you can:\n- register one or more helpers globally, to be used in any template\n- add one or more helpers as [private resources](#helpersapi@private) for a parent template"},{_type:"para",title:"Registering one or more helpers",text:""},{_type:"api",typeLabel:"API:",title:"$.views.helpers(...)",name:"helpers",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of helper - to be used in template path expressions as ~name..."},{_type:"param",name:"helper",type:"any type",optional:!1,description:"the helper - a function, object, or value"}],args:[],sections:[],example:'$.views.helpers("format", myFormatFunction);',description:"Register a helper, for use in any template with the syntax:
            ~name"},{_type:"signature",title:"",params:[{_type:"param",name:"namedHelpers",type:"object",optional:!1,description:"Object (hash) of keys (name of helper) and values (function, object, or value)"}],args:[],sections:[],example:'$.views.helpers({\n format: myFormatFunction,\n utilities: {},\n mode: "filtered"\n});',description:"Register multiple helpers"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:"Here is an example using a 'hierarchy' of helpers..."},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'Here is an example using a \'hierarchy\' of helpers...\n\n```js\n$.views.helpers({\n ...\n utilities: {\n maxCount: 23,\n subtractMax: function(val) {\n return val - this.maxCount;\n },\n errorMessages: {\n msg1: "not available"\n }\n },\n ...\n});\n```\n\n```jsr\n{{:~utilities.subtractMax(sold) > 0\n ? ~utilities.errorMessages.msg1\n : "immediate"\n}}\n```'}],code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\n$.views.helpers({\n format: myFormatFunction,\n utilities: {\n maxCount: 23,\n subtractMax: function(val) {\n return val - this.maxCount;\n },\n errorMessages: {\n msg1: "not available"\n }\n },\n mode: "filtered"\n});\n\nvar html = $("#myTemplate").render({title: "gizmo", sold: 27});\n\n$("#result").html(html);',html:'
            \n\n',title:"Register multiple helpers, including objects, etc.",height:"40",jsrJsvJqui:"jsr"},{_type:"para",title:"Adding helpers as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.helpers(...)`.\n\nIn that way the helper you are registering becomes a 'private helper resource' for the `parentTemplate`, rather than being registered globally:",anchor:"private"},{_type:"api",typeLabel:"API:",title:"$.views.helpers(namedHelpers[, parentTemplate])",name:"",object:"",method:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"namedHelpers",type:"object",optional:!1,description:"Object (hash) of keys (name of helper) and values (function, object, or value)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these helper(s) are being added as private resources"}],args:[],sections:[],example:"$.views.helpers({\n format: myFormatFunction,\n ...\n}, parentTemplate);",description:"Add one or more helpers as private resources for a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"links",title:"See also:",links:[],topics:[{hash:"helpers",label:"Using helpers"},{_type:"topic",hash:"samples/jsr/helpers",label:"Sample: Passing helpers to template.render()"}]}]},helpers:{title:"Using helpers",path:"",sections:[{_type:"para",title:"",text:"(See also *[Registering helpers](#helpersapi): The `$.views.helpers()` API*.)"},{_type:"para",title:"What are helpers?",text:'JsRender templates are made up of HTML markup, text, and *template tags*. *Template tags* are used to evaluate data-paths or computed expressions, and insert those values into the rendered output.\n\nBut often the values you will want to insert are not actually taken from the data, but rather from other parameters or *metadata* which you want to use. And often you will want to process the values, using helper functions or other code, e.g. for converting values to other formats, or for computed values.\n\n*Helpers*, in JsRender, refers to any functions, objects, parameters or metadata which you want to provide, in addition to the actual data you passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews).\n\nHelpers can also be objects, arrays, etc.\n\nYou access helpers by prepending the `~` character. Here are some examples:\n\n```jsr\n{{:~myHelperValue}}\n{{:~myHelperFunction(name, title)}}\n{{for ~myHelperObject.mySortFunction(people, "increasing")}} ... {{/for}}\n```' +},{_type:"para",title:"Passing in helpers",text:'There are three ways to provide helpers:\n\n- Global helpers -- registered using [`$.views.helpers(myHelpers)`](#helpersapi)\n- Helpers registered for a specific template -- [`$.templates("mytmpl", {markup: ..., helpers: myHelpers}`](#d.templates@resources)\n- Helpers passed in on a specific render call -- [`tmpl.render(data, myHelpers)`](#tmplrender@helpers)
            \n(Similarly you can [pass helpers](#jsvhelpers-converters) to JsViews `link()` calls)\n'},{_type:"para",title:"Contextual parameters",text:"In addition to providing helpers as above, you can also define *[contextual parameters](#contextualparams)* within a template, which you access using the same `~someName` syntax as for regular helpers. "},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```js\nvar myHelpers = {format: myFormatFunction};\n\n$.views.helpers(myHelpers);\n```\n\n```jsr\n{{:~format(name, true)}}\n```"}],title:"Global helper: $.views.helpers(...)",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar myHelpers = {format: myFormatFunction};\n\n$.views.helpers(myHelpers);\n\nvar html = $("#personTemplate").render({name: "Robert"});\n\n$("#person").html(html);',html:'
            \n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar myHelpers = {format: myFormatFunction};\n\n$.templates({\n mytmpl: {\n markup: "#personTemplate",\n helpers: myHelpers\n }\n});\n```\n\n```jsr\n{{:~format(name)}}\n{{:~format(name, true)}}\n```'}],title:"Helper resource for a specific template",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar myHelpers = {format: myFormatFunction};\n\n$.templates({\n mytmpl: {\n markup: "#personTemplate",\n helpers: myHelpers\n }\n});\n\nvar html = $.render.mytmpl({name: "Robert"});\n\n$("#person").html(html);',html:'
            \n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\nvar myHelpers = {format: myFormatFunction};\n\nvar html = $("#personTemplate").render(data, myHelpers); \n```\n\n```jsr\n{{:~format(name, true)}}\n{{:~format(name)}}\n```\n\nSee [`template.render(...)`](#rendertmpl)'}],title:"Passing helpers with a render() call",code:'function myFormatFunction(value, upper) {\n return upper ? value.toUpperCase() : value.toLowerCase();\n}\n\nvar data = {name: "Robert"};\n\nvar myHelpers = {format: myFormatFunction};\n\nvar html = $("#personTemplate").render(data, myHelpers); \n\n$("#person").html(html);',html:'
            \n\n',jsrJsvJqui:"jsr",height:"40"},{_type:"para",title:"For additional details and scenarios see:",text:"[Registering helpers](#helpersapi): The `$.views.helpers()` API"},{_type:"links",title:"See also:",links:[],topics:[{hash:"rendertmpl",label:"Render a template"},{_type:"topic",hash:"samples/jsr/helpers",label:"Sample: Passing helpers to template.render()"},{_type:"topic",hash:"settings/delimiters@passing",label:"Sample: Passing in terms as helpers"}]}]},convertersapi:{title:"Registering converters: $.views.converters()",path:"",sections:[{_type:"para",title:"",text:"See *[Using converters](#converters)* for an overview of what *converters* are, and some examples.\n\nThis topic provided more details.\n"},{_type:"para",title:"Using custom or built-in converters",text:"In JsRender, a converter is a convenient way of processing or formatting a data-value, or the result of expression evaluation.\n\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \n\n```jsr\n{{html:movie.description}} - This data is HTML encoded\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\n\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\n```\n\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\n\n```jsr\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \n{{upper:name}} - This uses my 'upper' converter \n```\n\n(See: [sample](#converters@simple).)\n\nYou can also use converters with any JsRender tag, not just the `{{: ...}}` tag, using the following syntax:\n\n```jsr\n{{sometag convert='myconverter' ...}}\n```\n\n(See: [sample](#converters@fortag).)\n\n***Note:*** With JsViews, you can use converters with two-way data-binding, and you will have a convert and a convertBack converter -- one for each direction."},{_type:"para",title:"Registering converters",text:"`$.views.converters()` is used to register converters.\n\nWith `$.views.converters(...)` you can:\n- register one or more converters globally, to be used in any template\n- add one or more converters as [private resources](#convertersapi@private) for a parent template"},{_type:"para",title:"Registering one or more converters",text:"A simple sample of registering a converter is shown [here](#converters@simple)."},{_type:"api",typeLabel:"API:",title:"$.views.converters(...)",name:"converters",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of converter - to be used in template markup: {{name: ...}}"},{_type:"param",name:"converterFn",type:"function",optional:!1,description:"Converter function. Takes val parameter and returns converted value"}],args:[],sections:[],example:'$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n\n{{upper: "upper case: " + nickname}}',description:"Register a converter"},{_type:"signature",title:"",params:[{_type:"param",name:"namedConverters",type:"object",optional:!1,description:"Object (hash) of keys (name of converter) and values (converter functions)"}],args:[],sections:[],example:"$.views.converters({\n upper: function(val) {...},\n lower: function(val) {...}\n});",description:"Register multiple converters"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Adding converters as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.converters(...)`.\n\nIn that way the converter you are registering becomes a 'private converter resource' for the `parentTemplate`, rather than being registered globally:",anchor:"private"},{_type:"api",typeLabel:"API:",title:"$.views.converters(...) — adding to parent template",name:"converters",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of converter - to be used in template markup: {{name: ...}}"},{_type:"param",name:"converterFn",type:"function",optional:!1,description:"Converter function. Takes val parameter and returns converted value (See API: function converterFn below for details)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this converter is being added as private resource"}],args:[],sections:[],example:'$.views.converters(\n "upper",\n function(val) { ... },\n parentTemplate\n);',description:"Register a converter as private resources for a parent template"},{_type:"signature",title:"",params:[{_type:"param",name:"namedConverters",type:"object",optional:!1,description:"Object (hash) of keys (name of converter) and values (converter functions)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template - to which this/these converter(s) are being added as private resources"}],args:[],sections:[],example:"$.views.converters({\n upper: function(val) {...},\n lower: function(val) {...}\n}, parentTemplate);",description:"Add one or more converters as private resources for a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Unregister a named converter",text:'To unregister a previously registered converter, pass `null` to `$.views.converters()`:\n\n```js\n$.views.converters("myCvt", null);\n// Named converter "myCvt" is no longer registered\n```'},{_type:"para",title:"Converter functions",text:"In most cases a converter function will return a computed value based on the input parameter `val`:\n\n```js\nfunction myConverter(val) {\n ... \n return computedVal; // converted/encoded/formatted value for 'val'\n}\n```\n\nwhere `val` comes from the data value or expression passed to the tag `{{myconverter: someExpression}}`. \n\n(See: [sample](#converters@simple).)\n",anchor:""},{_type:"para",title:"Converter function signature",text:"However a converter can access multiple [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag. (See for example `{{fullname: first last ...}}`, in the [fullname sample](#converters@fullname).)\n\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag properties](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\n\n```js\nfunction myConverter(arg1, arg2, arg3 ...) {\n var tag = this;\n var namedTagParameters = tag.tagCtx.props; \n ...\n return computedArg1; // converted value for 'arg1' passed to tag\n}\n```\n\nHere is the *converterFn* API definition:",anchor:"signature"},{_type:"api",typeLabel:"API:",title:"function converterFn(val, ...) {...}",name:"",object:"",method:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"val1",type:"object or string",optional:!1,description:"first tag argument"},{_type:"param",name:"val2",type:"object or string",optional:!0,description:"additional tag arguments"}],args:[],sections:[],example:'function myConverterFn(val1, val2, ...) {\n var tag = this;\n var tagProperties = tag.tagCtx.props;\n ...\n return ...;\n}\n\n$.views.converters("myconverter", myConverterFn);',description:"Converter function:
            • parameters: one or more tag arguments
            • this pointer: the tag instance
            • computes return value: which is passed to tag as first argument
            "}],description:"A converter function registered using $.views.converters(...)",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Using converters with other tags",text:"A converter can be used on any tag, thanks to the syntax\n\n```jsr\n{{sometag ... convert=...}}\n```\n\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}` or `{{for}}`.\n\nSee the [sample](#converters@fortag) using `{{for people convert='extraItems'}}`, where the converter adds additional items to the array. \n\n(***Note:*** This syntax can actually be used with the `{{: ...}}` tag too -- by writing `{{:name convert='upper'}}`...)"},{_type:"para",title:"Example: a converter for {{if}}",text:'Here is an advanced sample: an `"inlist"` converter for `{{if}}`.\n\n- It accepts an `item` argument and a `list` argument, and an optional `field` *named property*\n- It returns `true` if the `item` is found in the `list`\n- If there is a `field` specified, it takes the value of that field (property) on the `item` and searches for it in the `list`\n\nNote that the converter gets called once for the first `{{if}}` tag block and once for each subsequent `{{else}}` block.\n\n'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{for people}}\n ...\n {{if #data ~root.team convert='inlist'}}\n ...\n {{else #data ~root.reserve field=\"name\"}}\n ...\n {{else}}\n ...\n{{/for}}\n```\n\n```js\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}.\n ... // Return true\n\n // If the tag has a 'field' property, look for the value of that field among the list items\n ... // Return true if found\n\n // If no field property, look for the item among the list items\n ... // Return true if found\n\n return false; // Not found\n}\n\n// Register 'inlist' converter just for the 'teamTmpl' template \n$.views.converters({inlist: inlistConverter}, teamTmpl);\n```"}],title:"'inlist' converter for {{if}} tag",html:'
            \n\n',code:'var teamTmpl = $.templates("#teamTmpl");\n\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}\n if (!list) {\n return true; // Final else, so return true\n }\n\n var field = this.tagCtx.props.field;\n var l = list.length;\n\n // If the tag has a \'field\' property, look for the value of that field among the list items\n if (field) {\n while (l--) {\n if (item[field] === list[l]) {\n return true; // Return true if found\n }\n }\n }\n\n // If no field property, look for the item among the list items\n else {\n while (l--) {\n if (item === list[l]) {\n return true; // Return true if found\n }\n }\n }\n return false; // Not found\n}\n\n// Register \'inlist\' converter just for the \'teamTmpl\' template \n$.views.converters({inlist: inlistConverter}, teamTmpl);\n\n// Define model \nvar model= {people: [\n {name: "Jo"},\n {name: "Liza"},\n {name: "Eli"},\n {name: "Pete"},\n {name: "Zoey"}\n ],\n // Specify list of reserves, by name\n reserve: ["Eli", "Liza"]\n};\n\n// Specify array of team members\nmodel.team = [model.people[0], model.people[3]];\n\n$("#result").html(teamTmpl.render(model));\n',jsrJsvJqui:"jsr",height:"114",anchor:"iftag"},{_type:"para",title:"Using helper functions, or dynamically assigning converters",text:"The `convert=...` syntax allows you to assign a converter function without it being registered by name. For example it can be a data method or a helper function -- such as `{{sometag ... convert=~myConverterHelper}}`.\n\n(You can do this with the `{{: ...}}` tag too -- by writing `{{: ... convert=~myConverterHelper}}`...)\n\nYou can even assign a converter dynamically. For example you can write: `{{sometag ... convert=~getConverter(...)}}`, where the `getConverter()` helper might return either a string (for a converter registered by name) or a function to be used as converter.\n\nTo illustrate, here is a modified version of the previous sample, using `{{if ... convert=~getConverter()}}`:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```js\n// Converter function\nfunction inlistConverter(item, list) { ... }\n\n// Helper to dynamically assign converters\nfunction getConverter() {\n return inlistConverter; // For this sample just return `inlistConverter` every time\n}\n\n// Register 'getConverter' helper just for the 'teamTmpl' template \n$.views.helpers(\"getConverter\", getConverter, teamTmpl);\n```\n\n```jsr\n{{if #data ~root.team convert=~getConverter()}}\n ...\n{{/if}}\n```"}],html:'
            \n\n',code:'var teamTmpl = $.templates("#teamTmpl");\n\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\nfunction inlistConverter(item, list) {\n // If no arguments, this is the final {{else}}\n if (!list) {\n return true; // Final else, so return true\n }\n\n var field = this.tagCtx.props.field;\n var l = list.length;\n\n // If the tag has a \'field\' property, look for the value of that field among the list items\n if (field) {\n while (l--) {\n if (item[field] === list[l]) {\n return true; // Return true if found\n }\n }\n }\n\n // If no field property, look for the item among the list items\n else {\n while (l--) {\n if (item === list[l]) {\n return true; // Return true if found\n }\n }\n }\n return false; // Not found\n}\n\n// Helper to dynamically assign converters\nfunction getConverter() {\n return inlistConverter; // For this sample just return `inlistConverter` every time\n}\n\n// Register \'getConverter\' helper just for the \'teamTmpl\' template \n$.views.helpers("getConverter", getConverter, teamTmpl);\n\n// Define model \nvar model= {people: [\n {name: "Jo"},\n {name: "Liza"},\n {name: "Eli"},\n {name: "Pete"},\n {name: "Zoey"}\n ],\n // Specify list of reserves, by name\n reserve: ["Eli", "Liza"]\n};\n\n// Specify array of team members\nmodel.team = [model.people[0], model.people[3]];\n\n$("#result").html(teamTmpl.render(model));\n',jsrJsvJqui:"jsr",height:"114",title:"Dynamically assigning a converter"},{_type:"para",title:"Built-in converters:",text:"JsRender has the following built-in converters/encoders:\n\n- Built-in HTML encoder: [`{{html: ...}}`](#convertersapi@html) -- accessed programmatically as [`$.views.converters.html()`](#convertersapi@html)\n- Built-in attribute encoder: [`{{attr: ...}}`](#convertersapi@attr) -- accessed programmatically as [`$.views.converters.attr()`](#convertersapi@attr)\n- Built-in URL encoder: [`{{url: ...}}`](#convertersapi@url) -- accessed programmatically as [`$.views.converters.url()`](#convertersapi@url)\n- Basic [encode/unencode converters](#convertersapi@encode)\n"},{_type:"para",title:"Built-in HTML encoder",text:"JsRender includes an HTML encoder, which you can use programmatically as follows:\n\n```js\nvar myHtmlEncodedString = $.views.converters.html(myString);\n```\n\nThe same encoder is accessed declaratively as a converter, as in the following two examples:\n\n```jsr\n{{html:myExpression}}\n\n{{>myExpression}}\n```\n\nIn fact [`{{>...}}`](#htmltag) is exactly equivalent to `{{html:...}}` and is provided as a simpler syntax for HTML encoding values taken from data or from expressions and rendered within HTML content. \n\n(***Note:*** the [`{{> ...}}`](#htmltag) tag should be used in place of the [`{{: ...}}`](#assigntag) tag whenever the data being rendered is not full trusted -- in order to prevent HTML injection attacks.)",anchor:"html"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "< > \' \\" &";\n\nvar result = $.views.converters.html(value);\n\nalert(result);'}],code:'var value = "< > \' \\" &";\nvar result = $.views.converters.html(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the HTML encoder"},{_type:"api",typeLabel:"API:",title:"HTML encoder",name:"html",object:"$.views.converters",method:!0,returns:"HTML-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be HTML-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Encodes according to the following scheme:\n

            \n`&` → `&`
            \n`<` → `<`
            \n`>` → `>`
            \n`\\x00` → `�`
            \n`'` → `'`
            \n`\"` → `"`
            \n\\` → ```
            \n`=` → `=`\n"}],example:"var encoder = $.views.converters.html;\nvar encodedString = encoder(myString);",description:"Returns the HTML-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Built-in attribute encoder",text:'JsRender includes an encoder intended for use when attribute encoding is needed. You can use it programmatically as follows:\n\n```js\nvar myAttributeEncodedString = $.views.converters.attr(myString);\n```\n\nThe same encoder is accessed by declaratively as a converter:\n\n```jsr\n{{attr:myExpression}}\n```\n\nA typical use case would be to encode an HTML attribute value in a template:\n\n```jsr\n
            ...
            \n```',anchor:"attr"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "< > \' \\" &";\n\nvar result = $.views.converters.attr(value);\n\nalert(result);'}],code:'var value = "< > \' \\" & =";\nvar result = $.views.converters.attr(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the 'attribute' encoder"},{_type:"api",typeLabel:"API:",title:"Attribute encoder",name:"attr",object:"$.views.converters",method:!0,returns:"Attribute-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be attribute-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Encodes according to the following scheme:\n

            \n`&` → `&`
            \n`<` → `<`
            \n`>` → `>`
            \n`\\x00` → `�`
            \n`'` → `'`
            \n`\"` → `"`
            \n\\` → ```
            \n`=` → `=`"},{_type:"para",title:"",text:"Note that this scheme encodes more characters than is sometimes the case for attribute encoding. In fact currently `{{attr: ...}}` and `{{html: ...}}` are equivalent. This ensures that using attribute encoding when HTML encoding should have been used will not expose an injection attack risk from untrusted data."}],example:"var encoder = $.views.converters.attr;\nvar encodedString = encoder(myString);",description:"Returns the attribute-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Built-in URL encoder",text:'JsRender includes a URL encoder, which you can use programmatically as follows:\n\n```js\nvar myUrlEncodedString = $.views.converters.url(myString);\n```\n\nThe same encoder is accessed by declaratively as a converter:\n\n```jsr\n{{url:myExpression}}\n```\n\nA typical use case would be to encode a HTML URL attribute value in a template:\n\n```jsr\n\n```',anchor:"url"},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var value = "<_>_\\"_ ";\n\nvar result = $.views.converters.url(value);\n\nalert(result);'}],code:'var value = "<_>_\\"_ ";\nvar result = $.views.converters.url(value);\n\n$("#show").on("click", function() {\n alert(result);\n});',html:'\n',height:"46",jsrJsvJqui:"jsr",title:"Calling the 'url' encoder"},{_type:"api",typeLabel:"API:",title:"URL encoder",name:"url",object:"$.views.converters",method:!0,returns:"URL-encoded string",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"valueToEncode",type:"string",optional:!1,description:"input string to be URL-encoded"}],args:[],sections:[{_type:"para",title:"",text:"Internally encodes by calling the JavaScript function `encodeURI`."}],example:"var encoder = $.views.converters.url;\nvar encodedString = encoder(myString);",description:"Returns the URL-encoded string"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Minimalist HTML encode/unencode converters",text:"\nIn addition JsRender and JsViews provide encode/unencode converters for minimal encoding to prevent HTML injection (see the JsViews topic: [*Encoding to avoid XSS*](#link2way@encode)), by encoding just `<` `>` and `&` by the corresponding HTML entities, and for unencoding back from entities to characters:\n\n`&` ↔ `&`
            \n`<` ↔ `<`
            \n`>` ↔ `>`
            \n\n*Usage:*\n\n```js\nencodedValue = $.views.converters.encode(unencodedValue);\nunencodedValue = $.views.converters.unencode(encodedValue);\n```\n\n*Declarative usage:*\n\n```jsr\n{{encode:myExpression}}\n```",anchor:"encode"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"converters",label:"Using converters"},{_type:"topic",hash:"samples/jsr/converters",label:"Converters and encoding sample"},{_type:"topic",hash:"tagsapi@bindto",label:"Custom tags: The bindTo / bindFrom options and converters"}]}]},converters:{title:"Using converters",path:"",sections:[{_type:"para",title:"What are converters?",text:"In JsRender, a converter is a convenient way of processing or formatting data-value, or the result of expression evaluation.\n\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \n\n```jsr\n{{html:movie.description}} - This data is HTML encoded\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\n\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\n```\n\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\n\n```jsr\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \n{{upper:name}} - This uses my 'upper' converter \n```"},{_type:"para",title:"Built-in converters",text:"JsRender has the following built-in converters -- based on encoders:\n\n- Built-in HTML encoder: [`{{> ...}}`](#convertersapi@html)\n- Built-in attribute encoder: [`{{attr ...}}`](#convertersapi@attr)\n- Built-in URL encoder: [`{{url ...}}`](#convertersapi@url)"},{_type:"para",title:"Registering a converter",text:'You can register your own custom converters, using [`$.views.converters()`](#convertersapi) as in:\n\n```js\n$.views.converters("upper", function(val) {\n // Convert data-value or expression to upper case\n return val.toUpperCase();\n});\n```\n\nTo use the `"upper"` converter with the [`{{:...}}`](#assigntag) tag, you write:\n\n```jsr\n{{upper:...}}\n```\n\nHere it is in a sample:'},{_type:"sample",typeLabel:"Sample:",sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n```\n\n```jsr\nName: {{:name}}. Upper case nickname: {{upper:nickname}}\n...\n{{upper: "This will be upper case too"}} \n```'}],code:'$.views.converters("upper", function(val) {\n return val.toUpperCase();\n});\n\nvar person = {name: "Robert", nickname: "Bob"};\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',html:'
            \n\n',height:"80",title:"A simple converter",jsrJsvJqui:"jsr",anchor:"simple"},{_type:"para",title:"Converter arguments",text:'A converter can access any number of [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag:\n\n```js\n$.views.converters("myConverter", function(arg1, arg2, arg3 ...) {\n```\n\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag properties](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\n\nThe following sample shows a `"fullname"` converter, which provides a computed ***full name*** based on the first two tag arguments (*first* and *last*) and an optional named tag parameter `reverse=true`:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters("fullname", function(first, last) {\n var reverse = this.tagCtx.props.reverse; \n if (reverse) {\n return last.toUpperCase() + " " + first;\n }\n return first + " " + last;\n});\n```\n\n```jsr\n... {{fullname:first last}}\n... {{fullname:first last reverse=true}}\n```'}],html:'
            \n\n',code:'$.views.converters("fullname", function(first, last) {\n var reverse = this.tagCtx.props.reverse; \n if (reverse) {\n return last.toUpperCase() + " " + first;\n }\n return first + " " + last;\n});\n\nvar person = {first: "Xavier", last: "Prieto"};\n\nvar html = $("#personTemplate").render(person);\n\n$("#person").html(html);',jsrJsvJqui:"jsr",height:"80",title:"Full name converter – accessing multiple arguments",anchor:"fullname"},{_type:"para",title:"Using converters with other tags",text:"A converter can be used on any tag, thanks to the syntax\n\n```jsr\n{{sometag ... convert=...}}\n```\n\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}`.\n\n(*Note:* When using JsViews [two-way binding](#link2way@converters), similar syntax is available for *convertBack*: `convertBack=...`.)\n\nFor example, you could register an `\"inList\"` converter which returns true if `item` is found in `itemList` (see [sample](#convertersapi@iftag)):\n\n```jsr\n{{if convert='inList' item itemList}}...{{/if}}\n``` \n\nThe following sample shows the `{{for ...}}` tag used with a named converter which returns the array with additional appended and prepended items:",anchor:"othertags"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.converters({\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n});\n```\n\n```jsr\n{{for people convert=\'extraItems\'}}\n ...\n```\n\n\n'}],html:'
            \n\n',code:'$.views.converters({\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n});\n\nvar model= {people: [\n {name: "Jo1"},\n {name: "Jo2"},\n {name: "Jo3"}\n]};\n\nvar html = $("#myTmpl").render(model);\n\n$("#result").html(html);', +title:"Using converters with the {{for}} tag",jsrJsvJqui:"jsr",height:"114",anchor:"fortag"},{_type:"para",title:"Using helper functions or data methods as converters",text:"The `convert=...` syntax not only works on any tag, but also allows you to use not only registered converters, by name, as in\n\n```jsr\n{{for people convert='odd'}}\n```\n\nbut alternatively to use helpers, or data methods as in\n\n```jsr\n{{for people convert=utility.extraItems}} // Using data method\n```\n\nYou can also use that approach on `{{:..}}` tags as in\n\n```jsr\n{{:name convert=~hlp.bold}} // Using a helper\n```\n\nNote that the one tag which does not support this syntax is `{{>...}}` -- for which you would need instead to write:\n\n```jsr\n{{>~hlp.bold(name)}} // Using helper \n```\n\nHere is a modified version of the sample above, using helpers and data methods:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n...\n{{for people convert=utility.extraItems}} {{!-- using data method --}}\n
          • \n {{:name convert=~hlp.bold}} {{!-- using helper --}}\n...\n```"}],code:'var helpers = {\n hlp: {\n bold: function(val) {\n return "" + val + "";\n }\n }\n};\n\nvar model= {people: [\n {name: "Jo1"},\n {name: "Jo2"},\n {name: "Jo3"}\n ],\n utility: {\n extraItems: function(arr) {\n // return array with additional items\n return [{name: "Prepended"}].concat(arr, {name: "Appended"});\n }\n }\n};\n\nvar html = $("#myTmpl").render(model, helpers);\n\n$("#result").html(html);',html:'
            \n\n',jsrJsvJqui:"jsr",height:"114"},{_type:"links",title:"For additional details and scenarios see:",links:[],topics:[{hash:"convertersapi",label:"Registering converters"},{_type:"topic",hash:"link2way",label:"Two-way binding (JsViews)"}]},{_type:"para",title:"See also the following sample:",text:"[Converters and encoding](#samples/jsr/converters)\n"}]},nojqueryapi:{title:"JsRender without jQuery",path:"",sections:[{_type:"para",title:"",text:"JsRender can be loaded in the browser with or without jQuery, as in these example pages:\n\n- [JsRender with jQuery](#download/pages-jsr-jq)\n- [JsRender without jQuery](#download/pages-jsr)\n\nWhen jQuery is present:\n\n- JsRender loads as a jQuery plugin and adds APIs to the `jQuery` global namespace object -- usually aliased as `var $ = jQuery;`\n- The JsRender APIs are\n - `$.views...`\n - `$.templates(...)`\n - `$.render...`. \n\nIf jQuery is not present:\n\n- JsRender automatically creates its own `jsrender` global namespace variable \n- JsRender APIs are the same as above, but they are now associated with the `jsrender` namespace variable: \n - `jsrender.views...`\n - `jsrender.templates(...)`\n - `jsrender.render...`. \n\nFor convenience you can follow the jQuery approach of creating a global `$` -- set this time to `var $ = jsrender;`\n\nYou can then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy code from the regular browser examples/samples -- *as if* using JsRender with jQuery.\n\nFor example:\n\n```js\nvar $ = jsrender; // Alias for the jsrender namespace object - referenced for convenience as var $\n\nvar tmpl = $.templates('Name: {{:first}} {{upper:last}}'); // Compile template from string\n\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\n \nvar data = {first: 'Jo', last: 'Ryan'};\n\nvar html = tmpl.render(data);\n// result: \"Name: Jo RYAN\" \n```\n\n***Note:*** The same approach can be used when using [JsRender on the server](#node/install@apis) with Node.js, where JsRender is also being used without jQuery. "}]},"node/webpack":{title:"JsRender on Node.js",path:"",sections:[{_type:"para",title:"",text:"## Webpack support for JsRender and JsViews\n JsRender and JsViews can be loaded using [webpack](https://webpack.github.io/)."},{_type:"para",title:"JsRender as a webpack module",text:"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the webpack client script bundle, and loaded in the browser.\n\nThere are three options for loading JsRender in the browser as a webpack module:\n\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the webpack client script bundle:\n ```js\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\n ```\n- Load both jQuery and JsRender as modules in the webpack client script bundle:\n ```js\n var $ = require('jquery'); // Load jQuery as a module\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\n ```\n- Load JsRender as a module in the webpack client script bundle, without loading jQuery at all:\n ```js\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\n ```\n\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \n\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \n\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.",anchor:"jsrender"},{_type:"para",title:"Example – jQuery loaded globally:",text:"**index.html:**\n\n```jsr\n\n \n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"Example – jQuery loaded as module:",text:"**index.html:**\n\n```jsr\n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nvar $ = require('jquery'); // Load jQuery as a module\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\nvar tmpl = $.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\n$('#container').html(html);\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"Example – JsRender without jQuery:",text:"**index.html:**\n\n```jsr\n\n
            \n \n\n```\n\n**source.js:**\n\n```js\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\nvar tmpl = jsrender.templates('Name: {{:name}}');\nvar data = {name: 'Jo'};\nvar html = tmpl.render(data);\ndocument.querySelector('#container').innerHTML = html;\n```\n\n**command line:**\n\n```bash\nwebpack ./source.js bundle.js\n```"},{_type:"para",title:"JsViews as a webpack module",text:"JsViews can also be included in the webpack client-script bundle, and loaded in the browser.\n\nAfter installing on the server (using `$ npm install jsviews`), call:\n\n```js\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\n```\n\nor -- if also loading jQuery as a webpack module, use:\n\n```js\nvar $ = require('jquery');\n...\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as parameter)\n```",anchor:"jsviews"},{_type:"para",title:"See also:",text:"*[Browserify support](#node/browserify)*"}]},viewmodelsapi:{title:"Compiled View Models, using $.views.viewModels()",path:"",sections:[{_type:"para",title:"",text:"This topic provides details on using `$.views.viewModels()` to register/compile *View Models*.\n\nThis is the third of the alternative approaches discussed in *[Data / View Models](#jsrmodel)* -- namely:\n- [using](#jsrmodel@plain) plain objects\n- [using](#jsrmodel@vm) 'hand-coded' View Models\n- [using](#jsrmodel@compilevm) `$.views.viewModels()` to compile and register View Models with specific *get/set* properties and methods."},{_type:"para",title:"Advantages of compiled View Models",text:"Using `$.views.viewModels()` to compile *View Models* brings some important advantages over plain object hierarchies or 'hand-coded' *View Models*:\n\n- Simple calls to `$.views.viewModels(...)` allow you to compile these *View Model* classes without having to manually write repetitive code for multiple such *get/set* properties\n- Using compiled *View Models* rather than plain objects makes it easier to have clean well-designed modular code, since each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state\n- The compiled *View Models* provide a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\n- They also provide a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server\n- When working with (or migrating to) *JsViews* the compiled classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates. Updates to the *View Model* hierarchy, and calls to the *View Model* setters both trigger observable changes, with corresponding incremental updates to the *Views*. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)"},{_type:"para",title:"Using compiled View Models",text:"The basic *use scenarios* of compiled *View Models* are as follows:\n- Using `$.views.viewModels(...)` to [register/compile](#viewmodelsapi@compile) *View Models* (`myVM`)\n- Using a compiled View Model `myVM` as [constructor/factory](#viewmodelsapi@construct) method -- `MyVM(...)` -- to create View Model instances (`myVmInstance`)\n- Using `MyVM.map(...)` to [convert](#viewmodelsapi@map) a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances\n- Using `myVMInstance.merge(...)` to incrementally [update](#viewmodelsapi@merge) a *View Model* hierarchy, using updated plain data\n- Using `myVMInstance.unmap()` to [convert](#viewmodelsapi@unmap) a *View Model* hierarchy back to a plain object hierarchy\n\n"},{_type:"para",title:"API: $.views.viewModels(...)",text:'To register a *View Model*, you call the `$.views.viewModels(...)` API -- with four alternative signatures:\n- `var MyVM = $.views.viewModels(viewModelOptions);`
            returning a compiled *View Model* \n- `$.views.viewModels("MyVM", viewModelOptions);`
            registering a named *View Model*, accessible as `$.views.viewModels.MyVM`\n- `$.views.viewModels(namedViewModels);`
            where `namedViewModels` is a hash, declaring multiple *View Models*\n- `$.views.viewModels(namedViewModels, myViewModels);`
            where `namedViewModels` is a hash, declaring multiple *View Models* and `myViewModels` is a *View Models* collection (hash) which will provide access to the compiled *View Models*, as `myViewModels.MyVM`\n\nIn each case, the compiled *View Model* is specified by a `viewModelOptions` object, with a `getters: gettersArray` (specifying an array of *get/set* properties), and/or an `extend: extendObject` (specifying additional methods or properties).\n\nExample:\n\n```js\nvar Book = $.views.viewModels({ // Compile a Book View Model\n getters: ["title", "price"], // getters array - signature of constructor\n extend: { // extend object - additional methods \n placeOrder: function() { ... }\n }\n});\n\nvar book1 = Book("Hope", "1.50"); // Construct a Book View Model instance\nbook.price("2.50"); // Modify price\nbook.placeOrder(); // Call method\n```\n',anchor:"compile"},{_type:"api",typeLabel:"API:",title:"$.views.viewModels(...)",name:"viewModels",object:"$.views",method:!0,tag:!1,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"viewModelOptions",type:"object",optional:!1,description:"A viewModelOptions object which can include:
            • a 'getters' array (details below)
            • an 'extend' hash - with additional methods or properties
            • an 'id' specifier
            "}],sections:[],example:'var Book = $.views.viewModels({\n getters: ["title", "price"]\n});\n\nvar bk1 = Book("Hope", "$1.50");',description:"Return a compiled View Model (constructor/factory method) with specific get/set properties and methods",returns:"View Model constructor"},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!0,description:"Name for the registered View Model"},{_type:"param",name:"viewModelOptions",type:"object",optional:!1,description:"A viewModelOptions object which can include:
            • a 'getters' array (details below)
            • an 'extend' hash - with additional methods or properties
            • an 'id' specifier
            "}],args:[],sections:[],example:'$.views.viewModels("Book", {\n getters: ["title", "price"]\n});\n\nvar bk1 = $.views.viewModels.Book("Hope", "$1.50");\n',description:"Register (and return) a named View Model",returns:"View Model constructor"},{_type:"signature",title:"",params:[{_type:"param",name:"namedViewModels",type:"object",optional:!1,description:"hash of viewModelOptions objects - each of which can include:
            • a 'getters' array (details below)
            • an 'extend' hash - with additional methods or properties
            • an 'id' specifier
            "}],args:[],sections:[],example:'$.views.viewModels({\n Book: {getters: ["title", "price"]},\n ...\n});\n\nvar bk1 = $.views.viewModels.Book("Hope", "$1.50");\n',description:"Register multiple named View Models"},{_type:"signature",title:"",params:[{_type:"param",name:"namedViewModels",type:"object",optional:!1,description:"hash of viewModelOptions objects - each of which can include:
            • a 'getters' array (details below)
            • an 'extend' hash - with additional methods or properties
            • an 'id' specifier
            "},{_type:"param",name:"viewModels",type:"object",optional:!1,description:"View Model collection object (hash)"}],args:[],sections:[{_type:"para",title:"",text:"*Specifying **viewModelOptions** – details:*\n\n- The (optional) `getters` array.
            -- Each item in the array corresponds to a *get/set* property (and also a constructor argument, which initializes that *get/set* property).
            -- It must be either\n - a string -- the `getterName`, or\n - an object, which must have a *getter* property: `{getter: getterName}`.

            If an object, it can additionally specify:

            \n - a *type* property: `type: viewModelName` -- specifying the name of another *View Model* type (declared in the same View Model collection). In this case then when using `map()` to map from data to a generated *View Model* hierarchy (see below), data values for the *get/set* property will be mapped to instances of that *View Model*.\n - a *defaultVal* property -- specifying the value to be used at initialization if `undefined` -- such as\n - `defaultVal: null` (a value) or,\n - `defaultVal: function() { return ...; }` (a function, to return a computed value. The this pointer is the data item.) \n- The (optional) `extend` hash has additional members (methods or properties) to be included in the View Model prototype. The prototype will extend this object\n- The (optional) `id` is either a string (the name of a *View Model* property to be treated as **id**) or\na function. The specified *id* or the function call will be used for determining identity when `merge(...)` updates a *View Model* hierarchy (see below)"}],example:'var myVms = {};\n\n$.views.viewModels({\n Book: {getters: ["title", "price"]},\n ...\n}, myVms);\n\nvar bk1 = myVms.Book("Hope", "$1.50");\n',description:"Add one or more named View Models to a View Model collection (hash)",returns:"View Model collection (hash)"}],description:"Register one or more View Models",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Creating View Model instances, using the View Model constructor",text:'*View Models* compiled/registered/returned by `$.view.viewModels(...)` are in fact constructors for instances of the *View Model* class.\n\n```js\nvar Book = $.views.viewModels({ // Constructor\n getters: ["title", "price"] // getters array - signature of constructor\n ...\n});\n\nvar book1 = Book("Hope", "$1.50"); // Create Book instance\n```\n\nNote that:\n- The `new` keyword is not necessary when calling the constructor. (It is in effect a factory method, that calls `new` internally.)\n- The signature of the constructor call (parameters used to initialize the instance) corresponds to the array of getters specified in the `viewModelOptions` - in this case `["title", "price"]`',anchor:"construct"},{_type:"para",title:"View Model hierarchies",text:'The `Book` View Model example above has simple *get/set* properties `["title", "price"]` which are simple primitive types (string in this case).\n\nBut consider the `Person` *View Model*, used in the overview topic *[Data / View Model](#jsrmodel)*. Here a `person` object (whether a plain object or a *View Model* instance) is in fact a hierarchy of objects, since the `address` and `phones` properties of a `Person` are themselves objects (an `Address` object and a `Phone` array)\n\nHere is a `person` plain object/hierarchy (obtained perhaps by \'evaluating\' JSON data from the server): \n\n```js\nvar person = {\n name: "Pete",\n address: {\n street: "1st Ave"\n },\n phones: [{number: "111 111 1111"}, {number:"222 222 2222"}] \n};\n```\n\nTo map this object hierarchy to the corresponding *View Model* hierarchy we need to define three *View Models*:\n\n```js\n// Compile Person View Model, with addPhone method\nvar Person = $.views.viewModels({\n getters: ["name", "address", "phones"],\n extend: {addPhone: addPhone}\n});\n\n// Compile Address View Model\nvar Address = $.views.viewModels({getters: ["street"]});\n\n// Compile Phone View Model\nvar Phone = $.views.viewModels({getters: ["number"]});\n```\n\nWe can then instanciate the corresponding *View Model* hierarchy, using constructors:\n\n```js\nvar person = Person(\n "Pete",\n Address("1st Ave"),\n [Phone("111 111 1111"), Phone("222 222 2222")]\n);\n```\n\nSee the [sample](#jsrmodel@compilevmsample) in the *[Data / View Model](#jsrmodel)* topic.'},{_type:"para",title:"Creating View Model instances by mapping from data",text:"The process of manually writing code to map from JSON data to a corresponding *View Model* hierarchy, as above, can be complex and inconvenient. It requires traversing the data hierarchy and using appropriate *View Model* constructors to instantiate corresponding *View Model* instances. \n\nFortunately *JsRender/JsViews* compiled *View Models* provide a `map(data)` feature which when used together with *View Model* typed hierarchies makes this process quite trivial.\n",anchor:"map"},{_type:"para",title:"API: MyViewModel.map(...)",text:"Any compiled *View Model*, `MyViewModel`, provides a `MyViewModel.map(...)` method, which can be used to convert a plain object or an array of plain objects (or the equivalent JSON string) to the corresponding *View Model* instance (or array of *View Model* instances)."},{_type:"api",typeLabel:"API:",title:"MyViewModel.map(...)",name:"map",object:"MyViewModel",method:!0,returns:"View Model instance or array or instances",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object, array of objects, or JSON string",optional:!1,description:"The data (typically from JSON request)"}],args:[],sections:[],example:"// View Model\nvar Person = $.views.viewModels.Person;\n\n// View Model instance\nvar person = Person.map(personData);",description:"Generate a View Model instance/hierarchy/array by mapping from data (a plain object instance/hierarchy/array, or JSON string)"}],description:"Generate a View Model hierarchy from data",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:'Example:\n\n```js\nvar Book = $.views.viewModels({ // Constructor\n getters: ["title", "price"]\n});\n```\n\nMap from `bookData` plain object to `book` View Model instance:\n\n```js\nvar bookData1 = {title: "Hope", price: "$1.50"}; // book (plain object)\nvar book1 = Book.map(bookData1); // book (instance of Book View Model)\n```\n \nMap from `bookDataArray` array of plain objects to `bookArray` array of View Model instances:\n\n```js\nvar bookDataArray1 = [ // book array (plain objects)\n {title: "Hope", price: "$1.50"},\n {title: "Courage", price: "$2.50"}\n];\nvar booksArray1 = Book.map(bookDataArray1); // book array (instances of Book View Model)\n```'},{_type:"para",title:"View Model typed hierarchies",text:"When specifying `getters` in the `$.views.viewModels(...)` call, you can declare the type of a *get/set* property. For example an `address` *get/set* property can be specified as being of type `Address` -- where `Address` is another *View Model* declared on the same collection.\n\nBy specifying View Model types for properties (and declaring those View Models in the same collection) you obtain a *'View Model typed hierarchy'*.\n\n"},{_type:"para",title:"Using MyViewModel.map(...) to map a whole object hierarchy to a View Model instance hierarchy",text:'In the case of a *\'View Model typed hierarchy\'*, simply pass the top-level plain object to the `map()` method for the top-level *View Model* class, and all *View Model* instances in the hierarchy will be correctly instantiated:\n\n*Compile View Model classes (typed hierarchy):* \n\n```js\n$.views.viewModels({\n Person: {\n getters: [\n "name", // Declare \'name\' as being a primitive type (string)\n {getter: "address", type: "Address"}, // Declare \'address\' as being an Address (View Model) type\n {getter: "phones", type: "Phone"} // Declare \'phones\' as being (an array) of Phone (View Model) types\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone: ...\n});\n```\n\n*Person data (plain object hierarchy, or JSON string):*\n\n```js\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, ...]\n };\n```\n\n*Use map() to convert from `personData` plain object hierarchy (or JSON string) to `person` *View Model* hierarchy:*\n\n```js\nvar person = $.views.viewModels.Person.map(personData);\n```\n\nThe getter properties then let you traverse the hierarchy, call methods, etc.\n\n```\nperson.name("newName"); // Use setter: change name\nperson.addPhone(...); // Call method: add phone\nvar phone2 = person.phones()[1].number(); // Traverse and use getter: get number\n```\n\nLet\'s modify the [sample](#jsrmodel@compilevmsample) in *[Data / View Model](#jsrmodel)* to use the `map(...)` approach:'},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"template",title:"",markup:"... {{:name()}} ..."},{_type:"code",title:"Compile View Model classes",code:'...\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: ...\n Phone: ...\n});\n'},{_type:"code",title:"Instantiate View Model hierarchy using Person.map(data)",code:'var personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\nvar person = vmCollection.Person.map(personData);'},{_type:"code",title:"Render template against person object (instance of Person)",code:'$("#result").html(tmpl.render(person));'},{_type:"code",title:"Call setter, call method...",code:'...\nperson.name("newName"); // Use the name(...) setter\n\n...\nperson.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method'}],html:'\n\n\n\n\n
            \n\n',code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone:{\n getters: ["number"]\n }\n});\n\nvar vmCollection = $.views.viewModels;\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(vmCollection.Phone(phoneNo));\n}\n\n// person plain object hierarchy:\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\n// Instantiate View Model hierarchy using map()\nvar person = vmCollection.Person.map(personData);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});',height:"190",jsrJsvJqui:"jsr",title:"Using map() to convert from a plain object hierarchy to a View Model hierarchy",anchor:"mapsample"},{_type:"para",title:"",text:"(See also the [corresponding sample](#jsvviewmodelsapi@mapsample) with JsViews and data-linking.)"},{_type:"para",title:"Along with the map() feature – merge() and unmap()",text:"When working with View Model typed hierarchies, there are two additional features that can be used together with the `map()` feature:\n\n- If later you obtain updated JSON data, `personData2`, you can use `merge()` ([below](#viewmodelsapi@merge)) to trigger an incremental update to the *View Model* hierarchy:\n ```js\n person.merge(personData2);\n ```\n- If values are modified (using setters, or methods) you can at any time can use `unmap()` ([below](#viewmodelsapi@unmap)) to convert back to plain data, but with updated values:\n ```js\n var updatedPersonData = person.unmap();\n ```"},{_type:"para",title:"Using myVMobjectOrArray.merge(...) to update a View Model hierarchy",text:"If a *View Model* hierarchy (or array of *View Model* instances) was created using the `map()` feature above to map from data, then the *View Model* instances (and arrays) will each have a `merge()` method available:\n\n```js\nvar person = Person.map(personData1);\nperson.merge(personData2); // Incrementally update person (hierarchy)\n```\n\nor for an array:\n\n```js\nvar peopleArray = Person.map(peopleDataArray1);\npeopleArray.merge(peopleDataArray2); // Incrementally update people array\n```\n\nOr, deeper in the hierarchy:\n\n```js\nvar person = Person.map(personData1);\nperson.phones.merge(phonesDataArray2); // Update just the person.phones array\n```",anchor:"merge"},{_type:"para",title:"Updating with merge() makes minimal incremental changes, and preserves state",text:"Note that the `merge()` update process does not replace the whole hierarchy of *View Model* instances, but works incrementally to add/remove/modify instances as appropriate. So if most of the data in `personData2` is the same as `personData1`, calling `merge(personData2)` will make only minimal changes to the hierarchy. \n\nThis means that if *View Model* instances have state (such as additional properties that were set programmatically and are not driven by data) then that state can be maintained across the `merge()` update. "},{_type:"api",typeLabel:"API:",title:"myVMobjectOrArray.merge(...)",name:"merge",object:"myVMobjectOrArray",method:!0,returns:"View Model instance or array",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"data",type:"object, array of objects, or JSON string",optional:!1,description:"The updated data (typically from JSON request)"}],args:[],sections:[],example:"person.merge(personData2);\n// person (View Model hierarchy) has now\n// been updated, with modified data...",description:"Update a previously generated View Model instance/hierarchy/array by mapping from updated data"}],description:"Update a View Model hierarchy, from modified data",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Using myVMobjectOrArray.unmap() to convert back to a plain object hierarchy",text:"If a *View Model* hierarchy (or array of *View Model* instances) was created by mapping from data, using the `map()` feature above, then the View Model instances (and arrays) will each have an `unmap()` method (in addition to the `merge()` method mentioned above):\n\n```js\nvar person = Person.map(personData1);\nperson.addPhone(newPhone);\nperson.name(newName)\nvar modifiedPersonData = person.unmap(); // Convert back to a plain object hierarchy\n```\n\nor for an array:\n\n```js\nvar peopleArray = Person.map(peopleDataArray1);\npeopleArray[1].address.street(newStreet) // Make changes anywhere in the peopleArray\nvar modifiedPeopleDataArray = people.unmap(); // Convert back to a plain object array\n```\n\nOr, deeper in the hierarchy:\n\n```js\nvar person = Person.map(personData1);\nperson.addPhone(newPhone);\nvar modifiedPhonesArray = person.phones.unmap(); // Get a plain object array for person.phones\n```",anchor:"unmap"},{_type:"api",typeLabel:"API:",title:"myVMobjectOrArray.unmap()",name:"unmap",object:"myVMobjectOrArray",method:!0,returns:"object or array",signatures:[{_type:"signature",title:"",params:[],args:[],sections:[],example:"// Convert back to a plain object hierarchy\nvar modifiedPersonData = person.unmap();\n",description:"Obtain an updated plain object instance/hierarchy/array, from a previously generated View Model instance/hierarchy/array"}],description:"Get a plain object hierarchy from a View Model hierarchy",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"", +text:"Here is an updated version of our [previous](#viewmodelsapi@mapsample) sample, where now we have added the use of `merge()` and `unmap()`"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"Compile View Model classes",code:'...\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: ...\n Phone: ...\n});\n'},{_type:"code",title:"Instantiate View Model hierarchy, using map()",code:'var personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\nvar person = vmCollection.Person.map(personData);'},{_type:"code",title:"Update View Model hierarchy, using merge()",code:'$("#update").on("click", function() {\n person.merge(personData2); // Update person View Model hierarchy\n $("#result").html(tmpl.render(person));\n});\n'},{_type:"code",title:"Get current data, using unmap()",code:'$("#getData").on("click", function() {\n var updatedPersonData = person.unmap(); // Get plain object hierarchy from current View Model hierarchy\n window.alert(JSON.stringify(updatedPersonData));\n});'}],jsrJsvJqui:"jsr",code:'// Compiled template\nvar tmpl = $.templates("#personTmpl");\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n "name", // name is a primitive type (string)\n {getter: "address", type: "Address"}, // address is of type Address (View Model)\n {getter: "phones", type: "Phone"} // Each phone is of type Phone (View Model)\n ],\n extend: {addPhone: addPhone}\n },\n Address: {\n getters: ["street"]\n },\n Phone:{\n getters: ["number"]\n }\n});\n\nvar vmCollection = $.views.viewModels;\n\n// Method for Person class\nfunction addPhone(phoneNo) {\n // Uses Phone() View Model constructor to create Phone instance\n this.phones().push(vmCollection.Phone(phoneNo));\n}\n\n// First version of data (e.g. from JSON request):\nvar personData = {\n name: "Pete",\n address: {street: "1st Ave"},\n phones: [{number: "111 111 1111"}, {number: "222 222 2222"}]\n};\n\n// Second version of data (e.g. new JSON request):\nvar personData2 = {\n name: "Peter",\n address: {street: "2nd Ave"},\n phones: [{number: "111 111 9999"},{number: "333 333 9999"}]\n};\n\n// Instantiate View Model hierarchy, using map()\nvar person = vmCollection.Person.map(personData);\n\n// Render template against person object (instance of Person)\n$("#result").html(tmpl.render(person));\n\n// Button handlers\n$("#update").on("click", function() {\n // Update View Model hierarchy, using merge()\n person.merge(personData2);\n $("#result").html(tmpl.render(person));\n});\n\n$("#revert").on("click", function() {\n // Revert View Model hierarchy, using merge()\n person.merge(personData);\n $("#result").html(tmpl.render(person));\n});\n\n$("#changeName").on("click", function() {\n person.name("newName"); // Use the name(...) setter\n $("#result").html(tmpl.render(person));\n});\n\n$("#addPhone").on("click", function() {\n person.addPhone("xxx xxx xxxx"); // Call the addPhone(...) method\n $("#result").html(tmpl.render(person));\n});\n\n$("#getData").on("click", function() {\n // Get current data, using unmap()\n var updatedPersonData = person.unmap();\n window.alert(JSON.stringify(updatedPersonData));\n});',html:'\n\n\n\n
            \n\n\n\n
            \n\n',height:"230",title:"Using merge() to update View Models, and unmap() to return to plain objects",anchor:"mergesample"},{_type:"para",title:"",text:"(See also the [corresponding sample](#jsvviewmodelsapi@mergesample) using JsViews and data-linking.)"},{_type:"para",title:"Overriding generated get/set functions",text:'To override a generated get/set property provided by a compiled View Model you can provide an implementation in the `extend` hash, with the same name as the *get/set* in the `getters` array:\n\n```js\n// Define a myNameGetSet(...)function, to override the compiled name(...) get/set function\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Declare a Person View Model with an overridden name() get/set property\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", ...}, // Compiled name() get/set\n ...\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n ...\n }\n ...\n },\n ...\n});\n```\n\nThe above is equivalent to the generated version except that it adds custom logging to the getter/setter function.\n\n**Note:** In the context of JsViews, the View Model get/set properties can be data-linked (one-way or two-way data-binding) -- and will then be invoked automatically during observable changes to the property. (This applies also to overridden properties -- using a variant of the above pattern, described in [the corresponding JsViews topic](#jsvviewmodelsapi@override)).',anchor:"override"},{_type:"para",title:"Sample showing some of the advanced View Model features",text:"The next sample is similar to the [previous](#viewmodelsapi@mergesample) one, but specifically highlights some of the advanced features of compiled *View Models*.\n\n- It stores compiled *View Models* on a `myVmCollection` hash, as a *View Model typed collection*, rather than on
            `$.views.viewModels`\n- It maps from an array of 'people' rather than a single person:
            \n `var people = Person.map(peopleData);`\n- It specifies an `id` key for `Person`. When updating the `phones` array the `id` value is treated as 'primary key', and used to map 'identity':
            \n `id: \"id\"`\n- It provides an `id()` callback on `Person`, for determining identity -- allowing identification of corresponding *View Model* instances within the people array, and hence preventing unnecessary disposal and re-instantiation (which would destroy state, such as the `comment` value).\n- It has a `comment()` get/set property that is added as part of the `extend` definition, not the `getters`, so it is not initialized from data, in the constructor. Note therefore that if you set a *comment* on each `person` instance, then click *Update*, then *Revert*, one *comment* is conserved (since that instance is never disposed -- based on the 'identity' determination) but the other is lost since the instance is disposed and then re-created by *Revert*:
            \n `extend: {...comment: comment...}`\n- It has `defaultVal` specified for `name`, `address` and `phones`, either as 'static' values or computed by a callback function:
            \n `address: {type: \"Address\", defaultVal: defaultStreet}`\n- It overrides the generated `person.name()` *get/set* by a `myNameGetSet` function which includes logging\n- It passes a JSON string to `merge()` or `map()`\n(See also the [same sample](#jsvviewmodelsapi@mergesampleadv) using JsViews and data-linking.)",anchor:"mergesampleadv"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"code",title:"",code:'var myVmCollection = {};\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", defaultVal: "No name"}, // Compiled name() get/set\n {getter: "address", type: "Address", defaultVal: defaultAddress},\n {getter: "phones", type: "Phone", defaultVal: []}\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n addPhone: addPhone,\n comment: comment // Additional get/set property, not initialized by data)\n },\n id: function(vm, plain) { // Callback function to determine \'identity\'\n return vm.personId === plain.personId;\n }\n },\n ...\n Phone: {\n getters: ["number"],\n id: "phoneId" // Treat phoneId as \'primary key\', for identity\n }\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\n\n// Override generated name() get/set\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Method for Person class\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\n this.phones().push(myVmCollection.Phone(phoneNo));\n}\n\n// get/set for comment (state on View Model instance, not initialized from data)\nfunction comment(val) {\n if (!arguments.length) {\n return this._comment;\n }\n this._comment = val;\n}\n\nfunction defaultAddress() { // Function providing default address if undefined in data\n return {street: \'No street for "\' + this.name + \'"\'};\n}\n\n// First version of data - array of objects (e.g. from JSON request):\nvar peopleData = [{personId: "1", ...}, {personId: "2", name: "Pete",...}];\n\n// Second version of data - JSON string (e.g. new JSON request):\nvar peopleData2 = \'[{"personId":"2","name":"Peter","address":...}]\';\n\n// Instantiate View Model hierarchy using map()\nvar people = myVmCollection.Person.map(peopleData);\n\n// Render template against people (array of Person instances)\n$("#result").html(tmpl.render(people));\n...\n\n// Button handlers\n$("#update").on("click", function() {\n people.merge(peopleData2);\n ...\n});\n...'}],code:'var tmpl = $.templates("#personTmpl");\n\nvar myVmCollection = {};\n\n// Compile View Models\n$.views.viewModels({\n Person: {\n getters: [\n {getter: "name", defaultVal: "No name"}, // Compiled name() get/set\n {getter: "address", type: "Address", defaultVal: defaultAddress},\n {getter: "phones", type: "Phone", defaultVal: []}\n ],\n extend: {\n name: myNameGetSet, // Override name() get/set\n addPhone: addPhone,\n comment: comment // Additional get/set property, not initialized by data)\n },\n id: function(vm, plain) { // Callback function to determine \'identity\'\n return vm.personId === plain.personId;\n }\n },\n Address: {\n getters: ["street"]\n },\n Phone: {\n getters: ["number"],\n id: "phoneId" // Treat phoneId as \'primary key\', for identity\n }\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\n\n// Override generated name() get/set\nfunction myNameGetSet(val) {\n if (!arguments.length) { // This is standard compiled get/set code\n return this._name; // If there is no argument, use as a getter\n }\n this._name = val; // If there is an argument, use as a setter\n console.log("name set to " + val); // This is an additional line of code, for logging\n}\n\n// Method for Person class\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\n this.phones().push(myVmCollection.Phone(phoneNo));\n}\n\n// get/set for comment (state on View Model instance, not initialized from data)\nfunction comment(val) {\n if (!arguments.length) {\n return this._comment; // If there is no argument, use as a getter\n }\n this._comment = val;\n}\n\nfunction defaultAddress() { // Function providing default address if undefined in data\n return {street: \'No street for "\' + this.name + \'"\'};\n}\n\n// First version of data - array of objects (e.g. from JSON request):\nvar peopleData = [\n {\n personId: "1",\n address: {\n street: "2nd Ave"\n }\n },\n {\n personId: "2",\n name: "Pete",\n phones: [\n {number: "333 333 3333", phoneId: "2a"}\n ]\n }\n];\n\n// Second version of data - JSON string (e.g. new JSON request):\nvar peopleData2 = \'[{"personId":"2","name":"Peter","address":{"street":"11 1st Ave"},\'\n+ \'"phones":[{"number":"111 111 9999","phoneId":"1a"},{"number":"333 333 9999","phoneId":"2a"}]}]\';\n\n// Instantiate View Model hierarchy using map()\nvar people = myVmCollection.Person.map(peopleData);\n\n// Render template against people (array of Person instances)\n$("#result").html(tmpl.render(people));\n\n// Button handlers\n$("#update").on("click", function() {\n people.merge(peopleData2);\n $("#result").html(tmpl.render(people));\n});\n\n$("#revert").on("click", function() {\n people.merge(peopleData);\n $("#result").html(tmpl.render(people));\n});\n\n$("#changeName").on("click", function() {\n people[0].name("newName");\n $("#result").html(tmpl.render(people));\n});\n\n$("#addPhone").on("click", function() {\n people[0].addPhone("xxx xxx xxxx");\n $("#result").html(tmpl.render(people));\n});\n\n$("#result").on("change", ".comment", function(val) {\n // If comment is modified, update View Model state with new value\n people[this.getAttribute("data-index")].comment(this.value);\n});\n\n$("#getData").on("click", function() {\n var updatedPeopleData = people.unmap();\n window.alert(JSON.stringify(updatedPeopleData));\n});\n',html:'\n\n\n\n
            \n\n\n\n
            \n\n',height:"350",jsrJsvJqui:"jsr",anchor:"",title:"Mapping from JSON data to View Model hierarchy – further features"},{_type:"para",title:"Adding a custom get/set property to a compiled View Model ",text:"Finally, here is a sample which extends a compiled *View Model* with a custom `Person.isManager() `*get/set* property. The property is coupled to the `Team.manager()` property -- so setting `Person.isManager(...)` will update the `Team.manager()` correspondingly (and conversely when setting `Team.manager(...)`.\n\n`Person.isManager` is not included in the `getters` declaration, so that the constructor for `Person` will not expect an `isManager` parameter to be provided for initialization.\n\n(See also the [related sample](#jsvviewmodelsapi@ismanagersample) using JsViews and data-linking.)",anchor:"ismanagersample"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n// Custom function for Person.isManager get/set property\nfunction myIsManager(val) {\n if (!arguments.length) {\n return this === team.manager(); // If there is no argument, use as a getter\n }\n if (val) {\n // Make this team member manager\n team.manager(this);\n } else if (this.isManager()) {\n // Set team manager to null\n team.manager(null);\n }\n}\n\n// Compile View Models\n$.views.viewModels({\n Team: {...},\n Person: {\n getters: [\n "name",\n ...\n ],\n extend: {\n isManager: myIsManager // use custom function\n }\n },\n Address: {...}\n});\n\n...\n\n//Initialize second team member to be manager.\nvar manager = team.members()[1];\nmanager.isManager(true);\n\n...\n\n// Attach handler for checkbox\n$("#result")\n .on("change", ".isManager", function() {\n ...\n member.isManager(this.checked);\n renderTemplate(); // Refresh rendering, with modified data\n })\n ...\n```'}],html:'
            \n\n',code:'// Compile template\nvar tmpl = $.templates("#teamTmpl");\n\n// Custom function for Person.isManager get/set property\nfunction myIsManager(val) {\n if (!arguments.length) {\n return this === team.manager(); // If there is no argument, use as a getter\n }\n if (val) {\n // Setting this.isManager() to true\n // So make this team member manager\n team.manager(this);\n } else if (this.isManager()) {\n // Setting this.isManager to false, and this team member is currently manager.\n // So set team manager to null\n team.manager(null);\n }\n}\n\n// Compile View Models\n$.views.viewModels({\n Team: {\n getters: [\n {\n getter: "manager",\n type: "Person"\n },\n {\n getter: "members",\n type: "Person"\n }\n ]\n },\n Person: {\n getters: [\n "name",\n {\n getter: "address",\n type: "Address"\n }\n ],\n extend: {\n isManager: myIsManager // use custom function\n }\n },\n Address: {\n getters: ["street", "ZIP"]\n }\n});\n\n// Initial data \nvar teamData = {\n manager: null,\n members: [{\n name: "Pete",\n address: {\n street: "1st Ave",\n ZIP: "12345"\n }\n },{\n name: "Bess",\n address: {\n street: "Central Way",\n ZIP: "98765"\n }\n },\n {\n name: "Henry",\n address: {\n street: "Main St",\n ZIP: "54321"\n }\n }]\n };\n\n// Instantiate View Models\nvar team = $.views.viewModels.Team.map(teamData);\n\n//Initialize second team member to be manager.\nvar manager = team.members()[1];\nmanager.isManager(true);\n\nfunction renderTemplate() {\n // Refresh template rendering completely\n $("#result").html(tmpl.render(team));\n}\n\nrenderTemplate();\n\n// Attach handlers for checkbox and buttons\n$("#result")\n .on("change", ".isManager", function() {\n var memberIndex = $(this).data("index"),\n member = team.members()[memberIndex];\n member.isManager(this.checked);\n renderTemplate(); // Refresh rendering, with modified data\n })\n .on("click", ".changeManager", function() {\n var memberIndex = $(this).data("index"),\n member = team.members()[memberIndex];\n member.isManager(true);\n renderTemplate(); // Refresh rendering, with modified data\n })\n .on("click", ".noManager", function() {\n team.manager(null);\n renderTemplate(); // Refresh rendering, with modified data\n }\n);',title:"Sample: extending Person with an isManager property",height:"294",jsrJsvJqui:"jsr"},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"jsvviewmodelsapi",label:"Compiled View Models (JsViews)"}]}]},lifecycle:{title:"Life-cycle events",path:"",sections:[{_type:"para",title:"",text:"paragraph"}]},globals:{title:"Global jQuery extensions",path:"",sections:[{_type:"para",title:"",text:'*JsRender* adds the following extensions to the jQuery object, `$` (or to the `jsrender` namespace if using [JsRender without jQuery](#nojqueryapi)):\n\n- ***$.render:***\n - See [`$.render.myTmpl()`](#d.render)\n- ***$.templates:***\n - See [`$.templates()`](#d.templates)\n- ***$.views:***\n - See [`$.views`](#viewsobject)\n\nIt also adds the following \'plugin\' extension to jQuery instances:\n\n- ***$("#myTmpl").render(...):***\n - See [`$("#myTmpl").render()`](#db.render)\n\nSee also [JsViews globals](#jsvglobals)'}]},tagsapi:{title:"Registering custom tags: $.views.tags()",path:"",sections:[{_type:"para",title:"",text:"`$.views.tags()` is used to register custom tags. See *[Using custom tags](#tags)* for an overview, and simple examples.\n\nThis topic provides more details, including sections:\n\n- [Registering custom tags](#tagsapi@register)\n- [Custom tag options: Specifying init(), render(), template, baseTag](#tagsapi@options)\n- [Tag context](#tagsapi@context)\n- [Custom tag child views](#tagsapi@childviews)\n- [Rendering else blocks](#tagsapi@elseblocks)\n- [Custom tag hierarchy](#tagsapi@parents)\n- [Accessing contextual parameters and helpers](#tagsapi@ctxparams)\n- [Advanced options](#tagsapi@advanced)\n- [Methods and properties available on a custom tag instance](#tagsapi@instanceprops)\n- [Adding tags as private resources for a parent template](#tagsapi@privatetags)"},{_type:"para",title:"What is a custom tag?",text:"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\n\nA custom tag can optionally use arguments (*args*) and named properties (*props*), [as in](#tagsyntax@tagparams):\n\n```jsr\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\n```\n\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. "},{_type:"para",title:"Specifying tag options for a custom tag",text:'The following tag declaration registers a `{{mytag}}` custom tag:\n\n```js\n$.views.tags("mytag", tagOptions);\n```\n\nThe `tagOptions` object (hash) specifies the tag options and determines how the tag will function. It can include:\n\n- An [init()](#tagsapi@init) method: `init: tagInitFn`\n- A [render()](#tagsapi@render) method: `render: tagRenderFn`\n- A [template](#tagsapi@template): `template: tagTemplate`\n\nIn addition `tagOptions` can specify tag inheritance (so that the custom tag derives from a base tag):\n\n- [`baseTag: ...`](#tagsapi@basetag)\n\nIt can also specify the following more advanced options:\n\n- [`contentCtx: ...`](#tagsapi@contentctx)\n- [`convert: ...`](#tagsapi@convert)\n- [`argDefault: ...`](#tagsapi@argdefault)\n- [`bindTo: ...` / `bindFrom: ...`](#tagsapi@bindto)\n- [`flow: ...`](#tagsapi@flow)\n- [`ctx: ...`](#tagsapi@ctx)\n'},{_type:"para",title:"Registering custom tags: $.views.tags(...)",text:'To register a custom tag, you call the `$.views.tags(...)` API.\n\nThere are four alternative signatures:\n\n- `$.views.tags("mytag", tagOptions);` -- where the properties of the `tagOptions` object will typically include a `render: tagRenderFn` (specifying a render() method), and/or a `template: tagTemplate` (specifying a template to be rendered)\n- `$.views.tags("mytag", tagRenderFn);` -- simplified form, when the only option being specified is a render() method\n- `$.views.tags("mytag", tagTemplate);` -- simplified form, when the only option being specified is a tag template to be rendered\n- `$.views.tags(namedTags);` This version is for declaring multiple custom tags, and `namedTags` is a hash (with custom tag names as keys and `tagOption` objects as values)\n\nHere are the details:',anchor:"register"},{_type:"api",typeLabel:"API:",title:"$.views.tags(...)",name:"tags",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagOptions",type:"object",optional:!1,description:"A tagOptions object with a render() method and/or a template property, and optionally other properties or methods"}],args:[],sections:[],example:'$.views.tags("mytag", {\n render: function(...) {...},\n template: ...\n});\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a custom tag, specifying chosen tag options",returns:""},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagRenderFn",type:"function",optional:!1,description:"Tag render() method. Returns the rendered tag"}],args:[],sections:[],example:'$.views.tags("mytag", function(...) {\n ...return rendered content\n});\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a simple 'render' function as a custom tag",returns:""},{_type:"signature",title:"",params:[{_type:"param",name:"name",type:"string",optional:!1,description:"name of tag - to be used in template markup: {{name ...}}"},{_type:"param",name:"tagTemplate",type:"object or string",optional:!1,description:"A string containing template markup to be rendered by the tag (or a selector for a script block template definition, or a compiled template object)"}],args:[],sections:[],example:'$.views.tags("mytag", "templateMarkup...");\n\n{{mytag ...}} ... {{/mytag}}',description:"Register a template as a custom tag",returns:""},{_type:"signature",title:"",params:[{_type:"param",name:"namedTags",type:"object",optional:!1,description:"Object (hash) of keys (name of tag) and values (render function, template, or tagOptions object)"}],args:[],sections:[],example:"$.views.tags({\n mytag1: {\n render: function(val) {...},\n template: ...\n },\n mytag2: function(val) {...},\n mytag3: tag3TemplateString,\n});",description:"Register multiple custom tags",returns:""}],description:"Register one or more custom tags",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"",text:'For simple samples showing the above alternative `$.views.tags(...)` signatures, see the [*Using custom tags*](#tags) overview topic:\n\n- [A custom tag using just a render() method](#tags@render-sample)\n- [A custom tag using just a template](#tags@template-sample)\n- [Accessing context within the render() method](#tags@context-sample)\n- [Accessing context from the tag template](#tags@tmplcontext-sample)\n\nThe [*Using custom tags*](#tags) overview also provides samples of custom tags which render block content -- `{{mytag}}...{{/mytag}}`:\n\n- [Rendering block content from a custom tag render() method](#tags@renderblock-sample)\n- [Rendering block content from a custom tag template](#tags@tmplblock-sample)\n- [A {{runningTotal}} custom tag, using a render() method](#tags@runningtotal-sample)\n- [A {{runningTotal}} custom tag, with render() method and a template as "fallback"](#tags@renderplustmpl-sample)',anchor:""},{_type:"para",title:'Custom tag options: Specifying init(), render(), template, baseTag:',text:"A custom tag in JsRender has a very simple *'life-cyle'* consisting of two events for which you can optionally provide event handlers: the `init()` event, followed by the `render()` event. (If the custom tag is used in the context of JsViews, additional lifecycle events will also come into play, for data-binding, disposal, etc.)",anchor:"options"},{_type:"para",title:"Providing an init() method",text:'The *init()* method acts as a handler for the *init* event of the custom tag, and is called with the tag instance as `this` parameter.\n\n```js\n$.views.tags("mytag", {\n init: function(tagCtx, linkCtx, ctx) { ... },\n ...\n});\n``` \n\nThe *init()* method arguments are:\n- `tagCtx`: the [tagCtx object](#tagctxobject), also available as `this.tagCtx`\n- `linkCtx`: always 0 unless using [data-linked tags](#linked-tag-syntax) with *JsViews* (See [linkCtx object](#linkctxobject).)\n- `ctx`: [View context object](#ctxobject)\n\nThe following example uses the *init()* method to set the tag template based on the value of the `mode` prop:',anchor:"init"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Tag declaration:*\n\n```js\n$.views.tags("mytag", {\n init: function(tagCtx) {\n this.template = tagCtx.props.mode === "a"\n ? "template A ..."\n : "template B ...";\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{mytag name mode=\'a\' /}}\n{{mytag name mode=\'b\' /}}\n```'}],html:'\n\n
            \n\n',code:'$.views.tags("mytag", {\n init: function(tagCtx) {\n this.template = tagCtx.props.mode === "a"\n ? "template A: {{:}} aaa
            "\n : "template B: {{:}} bbb
            ";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render({name: "Jo"});\n\n$("#page").html(html);',jsrJsvJqui:"jsr",height:"60",anchor:"initsample",title:"Providing init()"},{_type:"para",title:"Providing a render() method",text:'The *render()* method acts as a handler for the *render* event of the custom tag, and is called with the tag instance as `this` parameter, and with arguments `arg1, arg2, ...`, corresponding to the unnamed arguments passed in the tag markup, `{{mytag expression1 expression2 ... }}`.\n\nIf no arguments are passed in the markup, then the `render()` method will be called with the current data context as argument (unless modified by the [argDefault](#tagsapi@argdefault) option.)\n\n```js\n$.views.tags("mytag", {\n render: function(value1, value2) { ... return ...; },\n ...\n});\n```\n\nThe *render()* method can optionally be used to define how the tag renders, by returning an HTML markup string.\n\nSee the example: [*A custom tag using just a render() method*](#tags@render-sample).\n',anchor:"render"},{_type:"para",title:"Providing a template",text:"The *template* option is used for declarative rendering, as an alternative to providing a *render()* method.\n\nSee the example: [*A custom tag using just a template*](#tags@template-sample).\n", +anchor:"template"},{_type:"para",title:"Data context of a tag template",text:"If the custom tag is called with an argument: `{{mytag someArgument ...}}` then the template will be rendered using the value of that argument as data context.\n\nOtherwise, the data context will be the same as the outer data context.\n\n(*Note:* This behavior can be changed using [contentCtx](#tagsapi@contentctx)) \n"},{_type:"para",title:"Using both a template and a render() method",text:'If the tag has both a *render()* method and a *template*, then the *render()* method is used to render the tag. But if *render()* returns `undefined` (or has no return value), then the *template* is used. \n\nSee example: [*A {{runningTotal}} custom tag, with render() method and a template as "fallback"*](#tags@renderplustmpl-sample).\n\nIt is also possible to provide both a *template* and a *render()* method, and to make use of the rendered template within the content returned by the render method. (In fact `this.tagCtx.render(...)` will return the rendered template). ',anchor:"tmpl-fallback"},{_type:"para",title:"Specifying tag inheritance: the baseTag option",text:'A custom tag can inherit from another tag (either built-in or custom).\n\nFor example the `{{runningTotal}}` sample, linked above, can be rewritten in a more powerful but compact form, by making it inherit from the `{{for}}` tag (since the functionality of iterating over an array is common to both).\n\nTo inherit from another tag, set the `baseTag` option to the name of the tag you want to derive from:\n\n```js\n$.views.tags("runningTotal", {\n baseTag: "for",\n ...\n});\n```\n\nCustom tag methods (*init()* or *render()*) can invoke the corresponding base tag method by calling one of the following API variants:\n\n```js\nthis.base(a, b, ...); // Pass chosen arguments\nthis.baseApply(arguments); // Pass on the calling arguments (or an array of args)\n```\n\nThis is illustrated in the following sample, which takes the *Providing init()* [sample](#tagsapi@initsample) above, and defines a derived `{{mytag2}}` which overrides *init()* and adds an error message when no valid `mode` was specified:\n',anchor:"basetag"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"*Tag declaration:*\n\n```js\n$.views.tags(\"mytag2\", {\n baseTag: \"mytag\",\n init: function() { // Override the init() method\n this.baseApply(arguments); // Call the base method\n this.template = this.template || \"Error: Specify mode 'a' or 'b'\"; // If no template was assigned, render error message\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{mytag2 name mode='a' /}}\n{{mytag2 name mode='b' /}}\n{{mytag2 name /}}\n```"}],html:'\n\n
            \n\n',code:'$.views.tags("mytag", {\n init: function(tagCtx) {\n this.templates = {\n a: "template A: {{:}} aaa
            ",\n b: "template B: {{:}} bbb
            "\n }; \n this.template = this.templates[tagCtx.props.mode];\n }\n});\n\n$.views.tags("mytag2", {\n baseTag: "mytag",\n init: function() { // Override the init() method\n this.baseApply(arguments); // Call the base method\n // If no template was assigned, render error message\n this.template = this.template || "Error: Specify mode \'a\' or \'b\'";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render({name: "Jo"});\n\n$("#page").html(html);',jsrJsvJqui:"jsr",height:"75",anchor:"basetagsample",title:"baseTag"},{_type:"para",title:"",text:"The previous `{{runningTotal}}` [sample](#tags@renderplustmpl-sample) was relatively complex. Here is an updated version rewritten to derive from `{{for}}`:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'This version is much simpler and supports sorting, filtering, etc. as well as `start=... end=... step=...`, without any additional code (thanks to the inherited features of `{{for}}`).\n\nAlso the fallback rendering for *No line items* is no longer hard-coded in the tag, but instead uses the `{{runningTotal}}...{{else}}...` pattern.\n\nNote that `~total()` is a function. The call to `~total()` increments the value and returns the running total.\n\n*Tag declaration:*\n\n```js\n$.views.tags("runningTotal", {\n baseTag: "for",\n ctx: {\n total: function() { // A ~total() helper (now a function)\n ...\n tag.totalVal += this.data[totalCol]; // Compute running total\n return tag.totalValue; // Return value from ~total()\n }\n },\n render: function() {\n this.totalVal = 0; // Initialize total before rendering\n return this.baseApply(arguments); // Render\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{runningTotal lineItems start=1 end=4 totalColumn="quantity"}} \n ...{{:~total()}}...\n{{else}}\n ...No line items...\n{{/runningTotal}}\n```\n'}],jsrJsvJqui:"jsr",height:"244",title:"A {{runningTotal}} custom tag derived from {{for}}",header:"",action:"append",html:'
            \n\n',code:'$.views.tags("runningTotal", {\n baseTag: "for",\n ctx: {\n total: function() { // A ~total() helper (now a function)\n var tag = this.ctx.tag,\n totalCol = tag.tagCtx.props.totalColumn\n tag.totalVal += this.data[totalCol]; // Compute running total\n return tag.totalVal; // Return value from ~total()\n }\n },\n render: function() {\n this.totalVal = 0; // Initialize total before rendering\n return this.baseApply(arguments); // Render\n }\n});\n\nvar data = {\n lineItems: [\n {category: "book", quantity: 2, price: 3.40},\n {category: "grocery", quantity: 5, price: 1.01},\n {category: "grocery", quantity: 2, price: 13.10},\n {category: "book", quantity: 1, price: 12.50}\n ],\n lineItems2: []\n};\n\nvar html = $("#myTmpl").render(data, {\n category: function(item, index, items) {\n return item.category === this.props.category;\n }\n});\n\n$("#lineItems").html(html);',anchor:"derivedfor"},{_type:"para",title:"",text:"Our `{{runningTotal}}` [samples](#tagsapi@derivedfor) so far have initialized the running total to `0` in the render method, and then relied on the rendering process to do the incrementing of the running total. This approach would fail if the rendering sequence was changed for any reason.\n\nThe sample below takes the `{{runningTotal}}` tag above, and converts it to a more complete and more powerful \n `{{purchases}}` tag, again deriving from the `{{for}}` tag. The `{{purchases}}` tag, which is more flexible and more robust, and supports any number of running total columns.\n\nThe `~total(expression)` helper function now allows you to provide any expression as parameter. Here, running total values are recomputed for each line, separately, so no longer depend on the render processing sequence:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'The `~total(expr)` helper function now accepts an *expression* parameter for each running total -- to be used to compute the incremental amount for each row.\n\n*Tag declaration:*\n\n```js\n$.views.tags("purchases", {\n baseTag: "for",\n ctx: {\n total: function(expr) { // A ~total(expression) helper\n var tmpl = $.templates[expr] // Get named compiled template for expression, or else...\n || $.templates(expr, "{{:" + expr + "}}"), // ...if this is first call, create it\n\n runningTotal = 0,\n view = this, // The content view with the ~total(...) helper call\n items = view.get("array").data,\n rowIndex = view.getIndex();\n\n for (var i = 0; i <= rowIndex; i++) {\n runningTotal += +tmpl(items[i]); // Compute running total up to this row, using render function\n } // of compiled tmpl (either tmpl() or tmpl.render()...)\n return runningTotal; // Return value from ~total(...)\n }\n }\n});\n```\n\n*Tag usage:*\n\n```jsr\n{{purchases lineItems sort="category" ...}} \n ...{{:~total(\'quantity*price\')}}...\n{{else}}\n ...No items...\n{{/purchases}}\n```\n'}],header:"",action:"append",html:"",code:"",jsrJsvJqui:"jsr",height:"550",url:"samples/jsrender/tags/extend-for/sample",title:"A {{purchases}} tag supporting totals for any expression",anchor:"totals-expr"},{_type:"para",title:"",text:"The above `{{purchases}}` custom tag can be easily updated to support data-binding. See [purchases sample](#samples/tag-controls/purchases@jsv)."},{_type:"para",title:'Tag context',text:"When a custom tag is used in a template then the rendered template instance will be part of the [view hierarchy](#views).\n\nThe instance of the tag is an object with properties and methods:\n\n- [tag object](#tagobject)\n\nAssociated with the tag instance is a [tag context object](#tagctxobject), `tagCtx`, providing most of the useful context for a tag, in particular:\n\n- context passed down through the view hierarchy:\n\n - current view\n - current data\n - parent tags\n - [contextual parameters](#contextualparams)
            (see also [*Accessing contextual parameters and helpers*](#tagsapi@ctxparams))\n\n- additional context coming from the tag itself, or its markup:\n\n - arguments (*args*) and named properties (*props*)\n - rendered tag template\n - block content\n - content of else blocks\n",anchor:"context"},{_type:"para",title:"Accessing the tag instance object",text:"From a tag method (*init()* or *render()*), the `this` pointer is the instance of the tag (a [tag object](#tagobject).)\n\nFrom a tag template, the tag instance can be accessed as `~tag`.\n"},{_type:"para",title:"Accessing the tag context object: tagCtx",text:"From a tag method the `tagCtx` object is available as `this.tagCtx`.\n\nIn the [*init()*](#tagsapi@render) method it is also passed directly as an argument (`function(tagCtx ...)`).\n\nFrom a tag template, `tagCtx` can be accessed as `~tagCtx`.\n"},{_type:"para",title:"Accessing the tag arguments or named properties",text:'The values of arguments can be accessed as `tagCtx.args`, and named properties as `tagCtx.props`.\n\nFor example, if we have the following tag, which has two arguments and one named property:\n\n```jsr\n{{sometag title name mode="edit"}}\n```\n\nthen from within the *init()* or *render()* method of `sometag`, the arguments and named properties can be accessed as:\n\n```js\nvar title = this.tagCtx.args[0];\nvar name = this.tagCtx.args[1];\nvar mode = this.tagCtx.props.mode;\n```\n\nand from the tag template, the values can be accessed as `~tagCtx.args` or `~tagCtx.props`, and so might be rendered as: \n\n```jsr\n...title: {{>~tagCtx.args[0]}}
            name: {{>~tagCtx.args[1]}}
            mode: {{>~tagCtx.props.mode}}...\n```\n\nIn addition to being available as `tagCtx.args`, arguments are also passed directly as arguments to the *render()* method, so `sometag` might use the following *render()* method, rather than a template, to render similar content:\n\n```js\nfunction sometagRenderMethod(title, name) {\n return "...title: " + title + "
            name: " + name + "
            mode: " + this.tagCtx.props.mode ...;\n}\n```\n\nThe `tagCtx` object also provides access to the markup expression for arguments and named properties, as `tagCtx.params.args` and `tagCtx.params.props`.\n\n(*Note:* Tag property names can include `_` and `.` characters, as in `{{mytag some_.name=... /}}`. If the name includes `.` characters, use the syntax `tagCtx.props["some_.name"];` to access the value.)'},{_type:"para",title:"Accessing the parent view and the current data",text:"The contextual (parent) view for the tag instance is accessed as `tagCtx.view`. The corresponding (parent) data context is `tagCtx.view.data`."},{_type:"para",title:'Custom tag child views',text:" ",anchor:"childviews"},{_type:"para",title:'Custom tag rendering with template: "mytag" child view',text:'A custom tag template instance will be part of the [view hierarchy](#views), and the rendered tag may add additional child views to the view hierarchy.\n\nIf `{{mytag members}}` renders using its *template*, that template will render as a child view (of type `"mytag"`). The default data context within the *template* will be the first argument passed to the tag (`members` in this case) which will be the `view.data` property of the child view.\n\nIf the *template* markup includes template tags (other custom tags, or built-in tags) then there will be corresponding additional child views below the *mytag* view. \n\n',anchor:"tagview"},{_type:"para",title:"Rendering wrapped block content",text:'- Any tag can wrap [block content](#tagsyntax@blocktag), or use `tmpl=...` to reference external content:\n ```jsr\n {{mytag}}...{{/mytag}}\n\n {{mytag tmpl=... /}}\n ```\n- By default, a custom tag with no *render()* method or tag template will render its block content unchanged. A tag with an argument will move data context to the data passed in the argument: `{{mytag somedata ...}}`.\n- For a custom tag rendering using a *render()* method, wrapped block content can be included using `tagCtx.render()`.

            *Note:* To set the inner data context, pass in data as argument: `tagCtx.render(someData)`. Otherwise inner and outer data context are the same.\n ```js\n $.views.tags("mytag", {\n ...\n render: function() {\n return ... + this.tagCtx.render() + ...;\n },\n ...\n });\n ```\n See the sample: [*Rendering block content from a custom tag render() method*](#tags@renderblock-sample).

            \n (For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See the [template as fallback](#tags@tmpl-fallback) sample).

            \n- For a custom tag rendering using a tag template, wrapped block content can be included using:\n ```jsr\n {{include tmpl=#content/}}\n ```\n or equivalently:\n ```jsr\n {{include tmpl=~tagCtx.content/}}\n ```\n where in each case the inner data context can be modified by passing an argument, `{{include someData tmpl=... /}}`.\n See the sample: [*Rendering block content from a custom tag template*](#tags@tmplblock-sample).\n\nNote that if a custom tag has an external `tmpl=...` reference, **_and_** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (see: [*Wrapping content*](#tagsyntax@wrap)).\n\nThis can provide for cascading content, as in the following sample:\n\n```jsr',anchor:"wrapping"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```js\n$.views.tags("mytag", {\n template: "mytagStart...{{include tmpl=#content/}}.../mytagEnd"\n});\n```\n```jsr\n{{mytag tmpl=\'#external\'}}wrappedContent{{/mytag}}\n```\n\n```jsr\n\n\n```'}],jsrJsvJqui:"jsr",html:'\n\n\n\n
            \n',code:'$.views.tags("mytag", {\n template: "mytagStart
            {{include tmpl=#content/}}
            /mytagEnd"\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = {},\n html = myTmpl.render(data);\n\n$("#page").html(html);',height:"106",title:"Cascading content"},{_type:"para",title:'Rendering else blocks',text:"Any tag can use [`{{else}}`](#elsetag) blocks. We might for example create a custom tag for rendering lists:\n\n```jsr\n{{list}}\n First item\n{{else}}\n Second item\n{{else}}\n Last item\n{{/list}}\n```\n\nA custom tag can provide specific behavior/rendering for `{{else}}` blocks:\n\n- For a tag with a render method, *render()* will be called once for the initial block and once for each `{{else}}` block.\n- Similarly, for a custom tag with a tag template, the template will be rendered once for the initial block and once for each `{{else}}` block.\n- During rendering a custom tag can detect which block is being rendered, using `tagCtx.index` (see below), and can then output the content corresponding to the desired functionality.\n",anchor:"elseblocks"},{_type:"para",title:"Tag context objects for {{else}} blocks: the tagCtxs array",text:"A tag with multiple blocks (initial block plus 1 or more `{{else}}` blocks) will have a `tagCtxs` array of `tagCtx` objects, one for each block.\n\n- From a tag method the `tagCtxs` array is available as `this.tagCtxs`.\n- From a tag template, `tagCtxs` can be accessed as `~tag.tagCtxs`.\n\nEach `tagCtx` object in `tagCtxs` has an `index` property (`0` for the initial block), as well as the other properties (`args`, `props` etc.) corresponding to the markup (arguments, named properties...) on the corresponding tag (`{{mytag ...}}` or `{{else ...}}`).\n\n- Within a tag *render()* method, `this.tagCtx` will be the current tag context object for that block.\n- Similarly, during rendering of the tag template, `~tag.tagCtx` will be the current `tagCtx`.\n\nTo determine the index of the block being rendered, use `tagCtx.index`. \n\nThese features are illustrated in the following sample:",anchor:"tagctxs"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Custom `{{list}}` tag:*\n\n```js\n$.views.tags("list", function() {\n // render() method\n var ret = "", // Return value\n index = this.tagCtx.index, // block index\n listElem = this.tagCtxs[0].props.numbered ? "ol" : "ul"; // Wrapper
              or
                element, based on numbered=true property \n\n if (index===0) {\n ret += "<" + listElem + ">"; // First block: add opening wrapper\n }\n ret += "
              • " + this.tagCtx.render() + "
              • "; // Add li element and block content\n if (index===this.tagCtxs.length-1) {\n ret += ""; // Last block: add closing wrapper\n }\n return ret;\n});\n```\n\n*Usage*:\n\n```jsr\n{{list numbered=true}}First{{else}}Second{{else}}Last{{/list}}\n{{list}}first{{else}}last{{/list}}\n```'}],jsrJsvJqui:"jsr",code:'// Define custom {{list}} tag\n$.views.tags("list", function() {\n // render() method\n var ret = "", // Return value\n index = this.tagCtx.index, // block index\n listElem = this.tagCtxs[0].props.numbered ? "ol" : "ul"; // Wrapper
                  or
                    element, based on numbered=true property \n\n if (index===0) {\n ret += "<" + listElem + ">"; // First block: add opening wrapper\n }\n ret += "
                  • " + this.tagCtx.render() + "
                  • "; // Add li element and block content\n if (index===this.tagCtxs.length-1) {\n ret += ""; // Last block: add closing wrapper\n }\n return ret;\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render();\n\n$("#page").html(html);\n',html:'\n\n
                    \n\n',height:"130",title:"Custom {{list}} tag using {{else}} blocks"},{_type:"para",title:"",text:"And here is a version of the sample with the same tag implemented using a tag template, rather than a *render()* method.\n\nHere we use the *init()* method to assign a tag template dynamically, using a different wrapper (`ol` or `ul`) based on the `numbered` named property:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Custom `{{list}}` tag:*\n \n```js\n$.views.tags("list", {\n init: function() {\n var listElem = this.tagCtx.props.numbered ? \'ol\' : \'ul\'; // Wrapper ol or ul element\n this.template = \n // First block: add opening wrapper\n "{{if ~tagCtx.index===0}}<" + listElem + ">{{/if}}"\n // Add li element and block content\n + "
                  • {{include tmpl=#content/}}
                  • "\n // Last block: add closing wrapper\n + "{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}";\n }\n});\n```'}],jsrJsvJqui:"jsr",height:"130",title:"Custom {{list}} tag: Rendering {{else}} blocks from a tag template",html:'\n\n
                    \n\n',code:'// Define custom {{list}} tag\n$.views.tags("list", {\n init: function() {\n var listElem = this.tagCtx.props.numbered ? \'ol\' : \'ul\'; // Wrapper ol or ul element\n this.template = \n // First block: add opening wrapper\n "{{if ~tagCtx.index===0}}<" + listElem + ">{{/if}}"\n // Add li element and block content\n + "
                  • {{include tmpl=#content/}}
                  • "\n // Last block: add closing wrapper\n + "{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}";\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n html = myTmpl.render();\n\n$("#page").html(html);\n'},{_type:"para",title:"",text:"Custom tags with no *render()* method and no tag template can also render multiple blocks, using `{{else}}`. Here is an example:"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'Custom `{{mytag}}` which simply renders each block as is:\n\n```js\n$.views.tags("mytag", {});\n```\n\nThe default data context of each block is the value passed to the first argument.\n\n```jsr\n{{mytag last}}\n First: {{:}}...\n{{else first}}\n ...\n{{else phone}}\n ...\n{{/mytag}}\n```\n'}],jsrJsvJqui:"jsr",html:'\n\n
                    \n\n',code:'// Define custom {{mytag}} tag\n$.views.tags("mytag", {});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = {first: "Jo", last: "Blow", phone: "111-111-1111"},\n html = myTmpl.render(data);\n\n$("#page").html(html);\n\n',title:"Default behavior for custom tag with {{else}} blocks",height:"72"},{_type:"para",title:'Custom tag hierarchy – Accessing parent tags',text:"Custom tags form a hierarchy, and can be designed with functionality or rendering that is based on parent or child tags within that hierarchy, as in the following example where a `{{layout}}` tag determines the layout for child `{{cell}}` tags:\n",anchor:"parents"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{layout 'vertical'}}\n {{cell}}one{{/cell}}\n {{cell}}two{{/cell}}\n{{/layout}}\n
                    \n{{layout 'horizontal'}}\n {{cell}}one{{/cell}}\n {{cell}}two{{/cell}}\n{{/layout}}\n```\n"}],jsrJsvJqui:"jsr",html:'\n\n
                    ',code:'$.views.tags({\n layout: {\n render: function(mode) {\n if (mode === "vertical") {\n this.vertical = true;\n return "" + this.tagCtx.render() + "
                    ";\n } else {\n return "" + this.tagCtx.render() + "
                    ";\n }\n }\n },\n cell: {\n render: function() {\n return this.parents.layout.vertical\n ? "" + this.tagCtx.render() + ""\n : "" + this.tagCtx.render() + "";\n }\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = { name: "Jo" },\n html = myTmpl.render(data);\n\n$("#page").html(html);',height:"140",header:""},{_type:"para",title:"",text:'The following properties provide access to ancestor custom tags:\n\n**parents property:**\n\nThe [`parents`](#tagobject@parents) property is a hash of all the ancestor custom tags. In the above sample the `{{cell}}` instances have a `{{layout}}` ancestor tag, which can be accessed from the `this.parents` hash, as `this.parents.layout`. In the sample this is used to determine whether the assigned layout is vertical, and to render accordingly:\n\n```js\nrender: function() {\n return this.parents.layout.vertical\n ? "" + this.tagCtx.render() + ""\n : "" + this.tagCtx.render() + "";\n}\n```\n\n**parent property:**\n\nThe tag instance also has a [`parent`](#tagobject@parent) property -- which is the nearest ancestor custom tag. In the above sample, the `parent` of the `{{cell}}` instance is the `{{layout}} instance`, so we could have replaced `this.parents.layout...` by `this.parent...`, in the above code.\n\n**~parentTags contextual parameter:**\n\nThe `ctx` property of a tag instance also has a `parentTags` property, equivalent to the `parents` hash. This can be used in the following alternative implementation of the `{{cell}}` tag above, using a tag template rather than a *render()* method:\n\n```js\n$.view.tags("cell", {\n template:\n "{{if ~parentTags.layout.vertical}}{{include tmpl=#content/}}"\n + "{{else}}{{include tmpl=#content/}}{{/if}}"\n});\n```\n\nIn fact, in a tag template `~parentTags` and `~tag.parents` are equivalent.\n\n**Note:** The tag hierarchy accessed using the above properties such as `tag.parent` consists *__only__* of custom tags. More precisely, it is the hierarchy of [*non-flow tags*](#tagsapi@flow). The built-in tags (`{{for}}`, `{{if}}` etc.) are all flow tags (`flow: true`) whereas custom tags by default have `flow: false`.'},{_type:"para",title:'Accessing contextual parameters and helpers',text:'- From a tag template:\n - [Contextual parameters](#contextualparams) and helpers can be accessed using `~myParamOrHelper`\n- From a tag method:\n - Contextual parameters and helpers can be accessed using `this.ctxPrm("myParamOrHelper")`\n - (Note: contextual parameters can also be accessed using `this.ctx.myParamOrHelper`, and global helpers can be accessed using `$views.helpers("myHelper")`)\n\n(See also [*Tag Context*](#tagsapi@context))\n\nAs an advanced example of custom tag rendering based on contextual parameters, here is a modified version of the above *layout* sample, where instead of wrapping `{{cell}}` tags in a `{{layout}}` tag, we instead wrap in a simple `{{include}}` on which we set a contextual parameter specifying layout: `layout=\'vertical\'`:',anchor:"ctxparams"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:"```jsr\n{{include ~layout='vertical'}}\n {{cell}}one{{/cell}}\n {{cell last=true}}two{{/cell}}\n{{/include}}\n
                    \n{{include ~layout='horizontal'}}\n {{cell}}one{{/cell}}\n {{cell last=true}}two{{/cell}}\n{{/include}}\n```\n"}],jsrJsvJqui:"jsr",html:'\n\n
                    ',code:'$.views.tags({\n cell: {\n render: function() {\n var res = "",\n vertical = this.ctxPrm("layout") === "vertical",\n parentView = this.tagCtx.view.parent,\n cellIndex = parentView.cellIndex = parentView.cellIndex === undefined ? 0 : parentView.cellIndex +1;\n if (vertical) {\n if (cellIndex===0) {\n res += "";\n }\n res += "";\n if (this.tagCtx.props.last) {\n res += "
                    " + this.tagCtx.render() + "
                    ";\n }\n } else {\n if (cellIndex===0) {\n res += "
                    ";\n }\n res += "";\n if (this.tagCtx.props.last) {\n res += "
                    " + this.tagCtx.render() + "
                    ";\n }\n }\n return res;\n }\n }\n});\n\nvar myTmpl = $.templates("#myTmpl"),\n data = { name: "Jo" },\n html = myTmpl.render(data);\n\n$("#page").html(html);',header:"",height:"140"},{_type:"para",title:"",text:'(*Note:* Contextual parameter names can include `_` and `.` characters, as in `{{mytag ~some_.name=... /}}`. If the name includes `.` characters, use the syntax `ctx["some_.name"];` to access the value.)'},{_type:"para",title:'Advanced options',text:" ",anchor:"advanced"},{_type:"para",title:"Specifying data context within tag content: the contentCtx option",text:'*__Default behavior:__*\n\nBy default the data context within the tag is the value of the first argument. (See [View hierarchy -- inner data context](#views@innerdata)).\n\nSo if `{{mytag}}` uses a `template` then `{{mytag members/}}` will render the template with `members` as data context. \n\nSimilarly if `{{mytag}}` is used as a block tag, then the block content within `{{mytag members}}...{{/mytag}}` will render with `members` as data context.\n\n*__Modified behavior:__*\n\nTo make the data context for tag content the same as parent context, set the `contentCtx` option to `true`:\n\n```js\n$.views.tags("mytag", {\n ...\n contentCtx: true, // The data context inside {{mytag}} will be the same as the outer context\n ...\n});\n```\n\nTo specify a different data context for tag content, set the `contentCtx` option to a function returning the chosen data. (The `this` pointer of the `contentCtx` function is the tag instance. The default data context, `arg0` is passed to it as argument.) \n\nFor example, with the following tag option setting, the inner data context is given by the `dataCtx` named property:\n\n```js\n$.views.tags("mytag", {\n ...\n contentCtx: function(arg0) {\n return this.tagCtx.props.dataCtx; // The returned value will be the data context inside {{mytag}}\n },\n ...\n});\n```\n\nUsage:\n\n```jsr\n{{mytag ... dataCtx=.../}}\n``` ', +anchor:"contentctx"},{_type:"para",title:"Providing a default converter: the convert option",text:"On any tag, including custom tags, a converter can be specified directly on the tag (see [*Using converters with other tags*](#converters@othertags)):\n\n```jsr\n{{mytag name convert='toUpperCase'/}}\n```\n\nTo provide a default converter on a custom tag (used as fallback if no converter is specified on the tag), set the `convert` tag option to a function, or to a registered converter name:\n\n```js\n$.views.tags(\"mytag\", {\n ...\n convert: 'toLowerCase', // Default converter. (A function or a registered converter name)\n ...\n});\n```\n\n\n\n",anchor:"convert"},{_type:"para",title:"Specifying a default argument: the argDefault option",text:'If a custom tag uses a *render()* method, then the arguments of the tag are passed to the render method:\n\n```jsr\n{{mytag arg0 arg1/}}\n```\n\n```js\n$.views.tags("mytag", {\n render: function(arg0, arg1) {...}\n});\n```\n\nIf the tag is called without arguments, then the render method will be called with the current data context as first argument, so therefore writing `{{mytag/}}` is equivalent to writing `{{mytag #data/}}` \n\nTo override this behavior, set the `argDefault` option to `false`. The first argument will then not default to current data, and the render method will instead be called without arguments.\n\n```jsr\n{{mytag/}}\n```\n\n```js\n$.views.tags("mytag", {\n render: function() {\n // arguments.length is 0\n },\n argDefault: false\n});\n```\n',anchor:"argdefault"},{_type:"para",title:"Specifying bound arguments and properties: the bindTo and bindFrom options",text:'The `bindTo` and `bindFrom` options are designed primarily for use with data binding, with JsViews, and allow specifying which arguments/properties are data-bound for two-way binding.\n\nIn JsRender, the `bindTo` or `bindFrom` option can be used in conjunction with converters. Set the `bindFrom` option (or the `bindTo` option if there is no `bindFrom` setting) to an array, such as `[0, 1, 2]`, or `["title", 1]` -- where integers refer to arguments and strings to named properties -- to determine what values are passed to the converter. (If neither `bindFrom` nor `bindTo` are set, then the values of all the [arguments](#tagsyntax@tagparams) will be passed to the converter.)\n\nBy default the value returned by the converter will be passed as first argument to the *render()* method. However, if the converter returns an array, then the values will be used to convert each of the targeted arguments or properties specified in `bindTo`/`bindFrom`.\n\nSee also\n- [tag.bndArgs()](#tagobject@bndargs)\n- [*JsViews* `bindTo`](#tagoptions@bindto)\n',anchor:"bindto"},{_type:"para",title:"Specifying flow behavior: the flow option",text:"A 'flow' tag -- which has the `flow` option set to `true` -- is a tag that does not appear in the [parent tags](#tagsapi@parents) hierarchy, so is not accessed via [`this.parent`](#tagobject@parent), [`this.parents`](#tagobject@parents), `~tagParents` etc.\n\nThe built-in tags such as `{{for}}`, `{{props}}` and `{{if}}` are *flow tags* and do not show up in the *parent tags* hierarchy. Custom tags by default are non-flow, and do show up (unless you set the option to `flow: true`).",anchor:"flow"},{_type:"para",title:"Specifying default context: the ctx option",text:'The `ctx` option of a tag can be used to provide default values of [contextual parameters](#contextualparams):\n\n```js\n$.views.tags("mytag", {\n template: "{{:~mode}}",\n ctx: {mode: "readonly"}, // Specify default ~mode if not provided by a helper or as a contextual parameter, \n ...\n});\n```\n',anchor:"ctx"},{_type:"para",title:"Methods and properties available on a custom tag instance",text:"A custom tag instance can access the following methods and properties\n\n*Tag properties*\n- [tag.ctx](#tagobject@ctx)\n- [tag.parent](#tagobject@parent)\n- [tag.parents](#tagobject@parents)\n- [tag.tagCtx](#tagobject@tagctx)\n- [tag.tagCtxs](#tagobject@tagctxs)\n- [tag.tagName](#tagobject@tagname)\n- [rendering](#tagobject@rendering)\n\n*Tag methods*\n- [tag.ctxPrm()](#tagobject@ctxprm)\n- [tag.cvtArgs()](#tagobject@cvtargs)\n- [tag.bndArgs()](#tagobject@bndargs)\n- [tag.base()](#tagobject@base)\n",anchor:"instanceprops"},{_type:"para",title:"Adding tags as private resources for a parent template",text:"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.tags(...)`.\n\nIn that way the tag (or tags) you are registering become 'private tag resources' for the `parentTemplate`, rather than being registered globally:",anchor:"privatetags"},{_type:"api",typeLabel:"API:",title:"",name:"tags",object:"$.views",method:!0,returns:"",signatures:[{_type:"signature",title:"Add one or more tags as private resources for a parent template",params:[{_type:"param",name:"namedTags",type:"object",optional:!1,description:"Object (hash) of keys (name of tag) and values (render function or tagOptions)"},{_type:"param",name:"parentTemplate",type:"object or string",optional:!0,description:"Owner template – to which this/these tag(s) are being added as private resources"}],args:[],sections:[],example:"$.views.tags({\n mytag1: ...,\n mytag2: ...\n}, parentTemplate);",description:"Add multiple tags as resources, to a parent template"}],description:"",sectionTypes:{para:"para",data:"data",template:"template",code:"code",sample:"sample",links:"links"}},{_type:"para",title:"Unregistering tags",text:'To unregister a previously registered tag, pass `null` to `$.views.tags()`:\n\n```js\n$.views.tags("mytag", null);\n// Tag "mytag" is no longer registered\n```',anchor:"unregister"},{_type:"para",title:"Custom tags and 'tag controls'",text:"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern."},{_type:"links",title:"See also:",links:[],topics:[{_type:"topic",hash:"tags",label:"Using custom tags"},{_type:"topic",hash:"samples/jsr/tags",label:"Samples: JsRender custom tags"},{_type:"topic",hash:"samples/tag-controls",label:"Samples: JsViews tag controls"},{_type:"topic",hash:"jsvtagcontrols",label:"JsViews tag controls"}]}]}}; //# sourceMappingURL=contents-jsrapi.min.js.map diff --git a/documentation/contents-jsrapi.min.js.map b/documentation/contents-jsrapi.min.js.map index 52ed3e2c..17f65940 100644 --- a/documentation/contents-jsrapi.min.js.map +++ b/documentation/contents-jsrapi.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["contents-jsrapi.js"],"names":["content","$","views","documentation","jsrapi","useStorage","parseJSON","localStorage","getItem","title","path","sections","_type","text","links","topics","hash","label","jsrtags","assigntag","typeLabel","name","signatures","params","args","type","optional","description","example","variant","sectionTypes","para","data","template","code","markup","height","jsrJsvJqui","address","city","htmltag","includetag","propName","html","codetabs","friends","fortag","members","sample","manager","anchor","people","firstName","lastName","street","header","action","propstag","ZIP","country","p1","p2","p3","iftag","standby","elsetag","commenttag","allowcodetag","customtagsapi","rendertmpl","tmplrender","object","method","tag","returns","d.render","db.render","compiletmpl","url","d.templates","jsrregister","tags","jsrobjects","viewsobject","settingsobject","subobject","templateobject","viewobject","tagobject","viewcontextobject","tagcontextobject","node/browserify","node/renderfile","node/filetmpls","jsrnode","node/install","node/express-hapi","node/server-browser","tagsyntax","paths","tmplsyntax","settings","settings/delimiters","settings/onerror","settings/dbgmode","settings/debugmode","settings/allowcode","settings/advanced","onerror","advanced","apps","getindex","contextualparams","parentdata","jsrmodel","helpersapi","helpers","convertersapi","converters","nojqueryapi","node/webpack","viewmodelsapi","lifecycle","globals","tagsapi"],"mappings":"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","file":"contents-jsrapi.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.jsrapi = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocTopics/jsrapi\")) ||\r\n{\r\n \"jsrapi\": {\r\n \"title\": \"JsRender API topics\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See [*JsRender Quickstart*](#jsr-quickstart) for an introductory overview.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Topics:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tmplsyntax\",\r\n \"label\": \"Template syntax and structure\"\r\n },\r\n {\r\n \"hash\": \"jsrtags\",\r\n \"label\": \"Template tags\"\r\n },\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"hash\": \"apps\",\r\n \"label\": \"Building apps\"\r\n },\r\n {\r\n \"hash\": \"nojqueryapi\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"hash\": \"settings\",\r\n \"label\": \"Settings\"\r\n },\r\n {\r\n \"hash\": \"advanced\",\r\n \"label\": \"Advanced\"\r\n },\r\n {\r\n \"hash\": \"jsrnode\",\r\n \"label\": \"JsRender on Node.js\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrtags\": {\r\n \"title\": \"Template tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Tag syntax\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"JsRender and JsViews tag syntax\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tags without content\",\r\n \"text\": \"- [`{{: ...}}`](#assigntag) (Evaluate)\\n- [`{{> ...}}`](#htmltag) (HTML encode)\\n- [`{{!-- ... --}}`](#commenttag) (Comment)\\n- [`{{* ...}} and {{*: ...}}`](#allowcodetag) (Allow code)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags\",\r\n \"text\": \"- [`{{include ...}}`](#includetag) (Template composition -- partials)\\n- [`{{for ...}}`](#fortag) (Template composition, with iteration over arrays)\\n- [`{{props ...}}`](#propstag) (Iteration over properties of an object)\\n- [`{{if ...}}`](#iftag) (Conditional inclusion)\\n- [`{{mytag ...}}`](#customtagsapi) (Custom tags)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternative content blocks\",\r\n \"text\": \"- [`{{else ...}}`](#elsetag) (Content block separator)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Additional tags in JsViews\",\r\n \"text\": \"When using data-linked templates, with *JsViews*, the following additional template tags are available:\\n\\n- [`{^{radiogroup ...}}`](#jsvradiogrouptag) (Radio button group)\\n- [`{^{on ...}}`](#jsvontag) (Button, or event binding)\\n\\n*See: [Template tags in JsViews](#jsvtags)*\"\r\n }\r\n ]\r\n },\r\n \"assigntag\": {\r\n \"title\": \"Template tag: {{: ...}} (Evaluate)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{: ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert data value or calculated value\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Data-path or expression, to be evaluated and inserted as a string in the rendered output\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{:address.street}}\",\r\n \"description\": \"Evaluate the data-path or expression\",\r\n \"variant\": \"{{:pathOrExpr}}\"\r\n }\r\n ],\r\n \"description\": \"Get the value of the data path or expression, and insert it into the rendered output as a string\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Here are some examples:\",\r\n \"text\": \"(Note the use of different kinds of data-path and expression in the different examples)\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Data:\",\r\n \"code\": \"{name: \\\"Pete\\\"}\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Template:\",\r\n \"markup\": \"{{:name}}\"\r\n }\r\n ],\r\n \"data\": {\r\n \"name\": \"Pete\"\r\n },\r\n \"markup\": \"{{:name}}\",\r\n \"height\": \"38\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:dataproperty}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n{\\n name: \\\"Pete\\\",\\n address: {\\n city: \\\"Seattle\\\"\\n }\\n}\\n```\\n\\n`~root` is the top-level data, and `#data` is the current data item\\n\\n```jsr\\n{{:name}} ... {{:address.city}}\\n\\n... {{:~root.address.city}}\\n\\n... {{:#data.address.city}}\\n```\"\r\n }\r\n ],\r\n \"data\": {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n \"markup\": \"{{:name}}: lives in {{:address.city}}.
                    \\n\\nHere is ~root.address.city: {{:~root.address.city}}
                    \\n\\nHere is #data.address.city: {{:#data.address.city}}\",\r\n \"height\": \"74\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:data.paths}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n[\\n {name: \\\"Pete\\\", ...},\\n {name: \\\"Heidi\\\", ...}\\n]\\n```\\n\\n`#xxx` is the `xxx` property of the current view -- so `#index` is the `view.index` \\n\\n```jsr\\n{{:#index+1}}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"{{:#index+1}}:\\n{{:name}}: lives in {{:address.city}}.
                    \",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ],\r\n \"height\": \"56\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:#index ...}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"***Note:*** When rendering data which is not fully trusted, such as `{{:untrustedValue}}` it would be preferable from a security point of view to use the `{{>untrustedValue}}` -- since the [`{{> ...}}`](#htmltag) tag will HTML encode the data, and thus prevent HTML injection attacks.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Sample: Converters and encoding\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvassigntag\",\r\n \"label\": \"JsViews: {^{: ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"htmltag\": {\r\n \"title\": \"Template tag: {{> ...}} (HTML encode)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{>...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert HTML-encoded data value or calculated value\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Data-path or expression, to be evaluated and inserted as an HTML-encoded string in the rendered output\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{>address.street}}\",\r\n \"description\": \"Evaluate the data-path or expression, and HTML encode the result\",\r\n \"variant\": \"{{>pathOrExpr}}\"\r\n }\r\n ],\r\n \"description\": \"Get the HTML-encoded value of the data path or expression, and insert it into the rendered output\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Data:\",\r\n \"code\": \"{description: \\\"A very nice apartment\\\"}\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Template:\",\r\n \"markup\": \"{{:description}}\\n...\\n{{>description}}\"\r\n }\r\n ],\r\n \"data\": {\r\n \"description\": \"A very nice apartment\"\r\n },\r\n \"markup\": \"{{:description}}
                    \\n{{>description}}\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"title\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{> ...}} for preventing HTML injection attacks\",\r\n \"text\": \"The [`{{> ...}}`](#htmltag) tag should be used instead of the [`{{: ...}}`](#assigntag) whenever *data being rendered is not fully trusted* -- in order to protect against HTML injection attacks. \\n\\nUsing `{{>untrustedValue}}` ensures appropriate HTML encoding.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"convertersapi@html\",\r\n \"label\": \"HTML encoder\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Sample: Converters and encoding\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvhtmltag\",\r\n \"label\": \"JsViews: {^{> ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"includetag\": {\r\n \"title\": \"Template tag: {{include tmpl=... /}} (Template composition – partials)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{include tmpl=... /}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Include an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{include tmpl=\\\"insertedPersonTemplate\\\" /}}\",\r\n \"description\": \"Include the specified template\",\r\n \"variant\": \"{{include tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Include the referenced template: tmpl, rendered using the current data context.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:name}} lives in {{include tmpl=\\\"#addressTemplate\\\"/}}\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Seattle\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Sidney\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"\\n\\n\\n\\n
                    \",\r\n \"title\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{include}} to move to a new data context\",\r\n \"text\": \"`{{include}}` is similar to `{{for}}` in that it can take an argument for moving to a new data context -- as in the following examples: \\n\\n*Block tag with inline content:*\\n\\n```jsr\\n{{include address}}\\n {{:street}}\\n{{/include}}\\n```\\n\\n*Self-closing tag, referencing block content as `tmpl=...` :*\\n\\n```jsr\\n{{include address tmpl=\\\"#addressTemplate\\\"/}}\\n```\\n\\n```jsr\\n\\n```\\n\\nThe above two examples are equivalent to:\\n\\n```jsr\\n{{:address.street}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{include pathOrExpr}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{include pathOrExpr}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{include}}` block is the object returned by the path or expression.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If the object returned is an array, then the block is rendered once for each item, and the data context for each rendered block is the data item from the array.\"\r\n }\r\n ],\r\n \"example\": \"{{include billing.address}}\\n {{:city}}\\n{{/include}}\",\r\n \"description\": \"Render the block content of the tag, with the given object or array as data context\",\r\n \"variant\": \"{{include pathOrExpr}}...{{/include}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{include pathOrExpr}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{include billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template, with the given object or array as data context\",\r\n \"variant\": \"{{include pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Render the block content of the {{include}} (or the referenced external template), using the object or array specified by the path or expression as data context.

                    (Similar to {{for pathOrExpr}} but with no iteration over arrays...)\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Unlike `{{for objectOrArray}}`, `{{include objectOrArray}}` does not iterate over arrays.\\n\\nConsider this example:\\n\\n```jsr\\nNumber of friends: {{:friends.length}} {{!-- Get 'length' of 'friends' array --}}\\nFriends:\\n{{for friends}} {{!-- Iterate over 'friends' array --}}\\n {{name:}} {{!-- Current data context (#data) is a 'friend'. Get 'name' --}} \\n{{/for}}\\n```\\n\\nThe example could actually be rewritten, equivalently, as follows:\\n\\n```jsr\\n{{include friends}} {{!-- Move to 'friends' array as data context, no iteration --}}\\n Number of friends: {{:length}} {{!-- Current data context (#data) is 'friends'. Get 'length' --}}\\n Friends:\\n {{for}} {{!-- or {{for #data}} ... --}} {{!-- Iterate over current data context (friends array) --}}\\n {{name:}} \\n {{/for}}\\n{{/include}}\\n```\\n\\nHere it is as a running sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{include friends}}:\\n Number of friends {{:length}}\\n ...\\n{{/include}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"markup\": \"{{include friends}} {{!-- move to friends array as data context --}}\\n\\n Number of friends: {{:length}}. {{!-- length of friends array --}}\\n\\n
                    Friends:\\n\\n {{for}} {{!-- Iterate over current data context (friends array) --}}\\n {{:name}} \\n {{/for}}\\n\\n{{/include}}\",\r\n \"title\": \"{{include array}} does not iterate\",\r\n \"data\": {\r\n \"friends\": [\r\n {\r\n \"name\": \"Jeff\"\r\n },\r\n {\r\n \"name\": \"Fabien\"\r\n }\r\n ]\r\n },\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"55\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvincludetag\",\r\n \"label\": \"JsViews: {^{include ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"fortag\": {\r\n \"title\": \"Template tag: {{for ...}} (Template composition, with iteration over arrays)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{for ...}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{for}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{for}}` block is the object returned by the path or expression.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If the object returned is an array, then the block is rendered once for each item, and the data context for each rendered block is the data item from the array.\"\r\n }\r\n ],\r\n \"example\": \"{{for billing.address}}\\n {{:city}}\\n{{/for}}\",\r\n \"description\": \"Render the block content of the tag for the given object, or iterate over the given array\",\r\n \"variant\": \"{{for pathOrExpr}}...{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{for}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{for billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template for the given object, or iterate over the given array\",\r\n \"variant\": \"{{for pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Render the block content of the {{for}} (or the referenced external template), using the object or array specified by the path or expression as data context. If it is an array, iterate over the array, rendering once for each item.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here are some examples:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:name}} lives in \\n{{for address}}\\n {{>city}}\\n{{/for}}\\n\"\r\n }\r\n ],\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"html\": \"\",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ],\r\n \"markup\": \"
                    \\n {{:name}} lives in\\n {{for address}}\\n {{>city}}\\n {{/for}}\\n
                    \",\r\n \"title\": \"{{for object}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:name}} lives in {{for address tmpl=\\\"#addressTemplate\\\" /}}\\n```\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                    \",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Seattle\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Sidney\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"title\": \"{{for object tmpl=... /}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:title}}\\n
                      \\n {{for members}}\\n
                    • {{:name}} ...
                    • \\n {{/for}}\\n
                    \"\r\n }\r\n ],\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"data\": {\r\n \"title\": \"The A team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ]\r\n },\r\n \"markup\": \"{{:title}}\\n
                      \\n {{for members}}\\n
                    • {{:name}} lives in {{:address.city}}
                    • \\n {{/for}}\\n
                    \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"90\",\r\n \"title\": \"{{for array}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{for}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{for}}` and `{{/for}}`, allows alternate rendering based on the object or array returned from the path or expression `{{for pathOrExpr}}`\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{for ...}}...{{else}}...{{/for}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on whether an array is empty or not\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{for members}}\\n Name: {{:name}}\\n{{else}}\\n No members...\\n{{/for}}\",\r\n \"description\": \"Render first block if array is not empty, otherwise render second block\",\r\n \"variant\": \"{{for pathOrExpr}...{{else}}...{{/for}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional blocks: – Render the block content of the {{for}} tag (or referenced template) if the object is defined and is not an empty array, otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{for members}}\\n
                    {{:name}}
                    \\n{{else}}\\n
                    No members!
                    \\n{{/for}}\\n\"\r\n }\r\n ],\r\n \"markup\": \"{{:title}}\\n
                      \\n {{for members}}\\n
                    • Name: {{:name}}
                    • \\n {{else}}\\n
                    • No members!
                    • \\n {{/for}}\\n
                    \",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team\",\r\n \"members\": []\r\n },\r\n {\r\n \"title\": \"The B team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"height\": \"134\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{for array}}...{{else}}...{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{for manager}}\\n
                  • Manager: {{:name}}
                  • \\n{{else}}\\n
                  • There is no team manager!
                  • \\n{{/for}}\"\r\n }\r\n ],\r\n \"markup\": \"{{:title}}\\n
                      \\n {{for manager}}\\n
                    • Manager: {{:name}}
                    • \\n {{else}}\\n
                    • There is no team manager!
                    • \\n {{/for}}\\n
                    \",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team2\",\r\n \"manager\": {\r\n \"name\": \"Pete\"\r\n }\r\n },\r\n {\r\n \"title\": \"The B team\"\r\n }\r\n ],\r\n \"title\": \"{{for object}}...{{else}}...{{/for}}\",\r\n \"height\": \"134\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Note:* A `{{for}}` tag (like an `{{if}}` tag) can have multiple `{{else}}` blocks. See for example [this sample](#jsvelsetag@for-else-multiple).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{for array}} with sorting and filtering, or specifying a range of items\",\r\n \"text\": \"When using the `{{for}}` tag to render arrays, built-in features allow sorting, filtering and 'slicing' the rendered list:\",\r\n \"anchor\": \"sortfilterrange\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The reverse property: specifying reverse ordering (or reverse sorting) on {{for array}}\",\r\n \"text\": \"To iterate over an array in reverse order, set the `reverse` property to `true`:\\n\\n```jsr\\n{{for array reverse=true }}...{{/for}}\\n```\\n\\nSetting `reverse=true` can be combined with using the [`sort`](#fortag@sort), [`filter`](#fortag@filter), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties, to reverse the order of iteration (for example to sort in *descending* order rather than *ascending* order).\",\r\n \"anchor\": \"reverse\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The sort property: specifying sorting on {{for array}}\",\r\n \"text\": \"To specify sorting, set the `sort` property: \\n\\n```jsr\\n{{for array sort=\\\"firstName\\\" }}...{{/for}}\\n```\\n\\n- If the array is an array of objects, the `sort=...` property of `{{for}}` is usually set to an object property to be sorted by, such as `firstName`, or to a data path, such as `sort=\\\"address.street\\\"`\\n- To sort an array of numbers, strings or `Date`s, set the `sort` property to the empty string: `sort=\\\"\\\"`\\n- For advanced scenarios you can provide your own sort function: `sort=~mySortFunction`\\n\\nSetting `sort=...` can be combined with using the [`reverse`](#fortag@reverse), [`filter`](#fortag@filter), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties.\\n\\nThe following three samples illustrate the above scenarios, using the `reverse` and `sort` properties:\",\r\n \"anchor\": \"sort\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                    Template:
                    *\\n```jsr\\n{{for colors sort=\\\"\\\" reverse=true}}...{{/for}} {{!-- (Reverse) sort array of strings --}}\\n{{for amounts sort=\\\"\\\"}}...{{/for}} {{!-- Sort array of Numbers --}}\\n{{for dates sort=\\\"\\\"}}...{{/for}} {{!-- Sort array of Dates --}}\\n```\\n\\n*
                    Data:
                    *\\n```js\\ncolors: [\\\"red\\\", ...],\\namounts: [33.001, ...],\\ndates: [new Date(2000, 0, 1), ...]\\n```\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"$.views.converters(\\\"formatDate\\\", function(date) {\\n // Converter to format Dates\\n return date.toLocaleDateString(\\\"en-US\\\");\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\n \\\"red\\\",\\n \\\"white\\\",\\n \\\"blue\\\"\\n ],\\n amounts: [\\n 33,\\n -2.333,\\n 2.4,\\n -22,\\n 22\\n ],\\n dates: [\\n new Date(2000, 0, 1),\\n new Date(1998, 6, 30),\\n new Date(2000, 11, 31)\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"110\",\r\n \"title\": \"Sorting an array of strings/Numbers/Dates\",\r\n \"anchor\": \"sortvalues\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                    Template:
                    *\\n```jsr\\n{{for people sort=\\\"firstName\\\"}}...{{/for}} {{!-- Sort by first name --}}\\n{{for people sort=\\\"lastName\\\" reverse=true}}...{{/for}} {{!-- Sort by last name, decreasing --}}\\n{{for people sort=\\\"address.street\\\"}} {{!-- Sort by address.street --}}\\n```\\n\\n*
                    Data:
                    *\\n```js\\npeople: [\\n {firstName: \\\"Jo\\\", ... address: {street: \\\"1st Street\\\" ...}},\\n ...\\n]\\n```\"\r\n }\r\n ],\r\n \"markup\": \"Sort by first name\\n
                      \\n {{for people sort=\\\"firstName\\\"}}\\n
                    • {{:firstName}} {{:lastName}}
                    • \\n {{/for}}\\n
                    \\n\\nSort by last name, decreasing\\n
                      \\n {{for people sort=\\\"lastName\\\" reverse=true}}\\n
                    • {{:firstName}} {{:lastName}}
                    • \\n {{/for}}\\n
                    \\n\\nSort by street\\n
                      \\n {{for people sort=\\\"address.street\\\"}}\\n
                    • {{:firstName}}: {{:address.street}}
                    • \\n {{/for}}\\n
                    \",\r\n \"data\": {\r\n \"people\": [\r\n {\r\n \"firstName\": \"Jo\",\r\n \"lastName\": \"Blow\",\r\n \"address\": {\r\n \"street\": \"1st Street\"\r\n }\r\n },\r\n {\r\n \"firstName\": \"Adriana\",\r\n \"lastName\": \"Zhang\",\r\n \"address\": {\r\n \"street\": \"1st Avenue\"\r\n }\r\n },\r\n {\r\n \"firstName\": \"Xavier\",\r\n \"lastName\": \"Rossi\",\r\n \"address\": {\r\n \"street\": \"2nd Street\"\r\n }\r\n }\r\n ]\r\n },\r\n \"height\": \"294\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Sorting an array of objects\",\r\n \"anchor\": \"sortobjects\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people sort=~multilevel}}...{{/for}} {{!-- Sort using a custom helper function: ~multilevel --}}\\n```\\n\\nThe custom sort function takes arguments `(a, b)` for the two objects being compared. The `this` pointer is the current `view` object.\\n\\n```js\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n return ... // Return 1, -1 or 0 to specify relative position of `a` and `b` in the sort order\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"// Helper function for multi-level sort\\nfunction level(aField, bField) {\\n return aField > bField ? 1 : aField < bField ? -1 : 0;\\n}\\n\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n // Sort by role, then by age (descending) then by name\\n return level(a.details.role.toLowerCase(), b.details.role.toLowerCase()) // by role\\n || level(b.details.age, a.details.age) // by age\\n || level(a.name.toLowerCase(), b.name.toLowerCase()); // by name\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: [\\n {name: \\\"Bill\\\", details: {age: 22, role: \\\"Lead\\\"}},\\n {name: \\\"Anne\\\", details: {age: 32, role: \\\"Assistant\\\"}},\\n {name: \\\"Emma\\\", details: {age: 19.1, role: \\\"Team member\\\"}},\\n {name: \\\"Jeff\\\", details: {age: 33.5, role: \\\"Lead\\\"}},\\n {name: \\\"Xavier\\\", details: {age: 32, role: \\\"Team member\\\"}},\\n {name: \\\"Julia\\\", details: {age: 18, role: \\\"Assistant\\\"}},\\n {name: \\\"Bill\\\", details: {age: 32, role: \\\"Team member\\\"}}\\n ]},\\n\\n html = myTmpl.render(data, { \\n multilevel: multilevelSort\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"150\",\r\n \"title\": \"Using a custom sort function: multi-level sort \",\r\n \"anchor\": \"sortcustom\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The filter property: specifying filtering on {{for array}}\",\r\n \"text\": \"To filter the rendered items, use the `filter` property to specify a filter function: \\n\\n```jsr\\n{{for array filter=~myfilter}}...{{/for}}\\n```\\n\\n```js\\nfunction myfilter(item, index, items) {\\n return ...; // Return true/false to include/exclude any item from the result\\n}\\n```\\n\\nThe filter function is called with the `tagCtx` object as `this` pointer, and with arguments:\\n\\n- `item`: The current item being processed in the array\\n- `index`: The index of the current item being processed in the array\\n- `array`: The array being filtered\\n\\nSetting `filter=...` can be combined with using the [`sort`](#fortag@sort), [`reverse`](#fortag@reverse), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties (to filter the items after sorting or reversing, or before 'slicing').\\n\\nThe following sample renders a subset of an array of `people`, filtered by age:\",\r\n \"anchor\": \"filter\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction ageRangeFilter(item, index, items) {\\n return item.details.age > this.props.minAge ...\\n}\\n```\\n\\n```jsr\\n{{for people filter=~ageRange minAge=20 maxAge=40 sort=\\\"name\\\"}}...{{/for}}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"function ageRangeFilter(item, index, items) {\\n return item.details.age > this.props.minAge && item.details.age < this.props.maxAge;\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: [\\n {name: \\\"Bill\\\", details: {age: 25}},\\n {name: \\\"Anne\\\", details: {age: 32}},\\n {name: \\\"Emma\\\", details: {age: 19.1}},\\n {name: \\\"Jeff\\\", details: {age: 33.5}},\\n {name: \\\"Xavier\\\", details: {age: 52}},\\n {name: \\\"Julia\\\", details: {age: 18}},\\n {name: \\\"Jo\\\", details: {age: 30}}\\n ]},\\n\\n html = myTmpl.render(data, { \\n ageRange: ageRangeFilter\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample renders an array of `people` in a two row layout -- by filtering for the items with even (first row) and odd (second row) index.\\n\\n(See also an alternative approach using `step=...`, in the [section](#fortag@start-end) below).\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people filter=~evenOdd odd=false sort=\\\"name\\\"}}...{{/for}}\\n...\\n{{for people filter=~evenOdd odd=true sort=\\\"name\\\"}}...{{/for}}\\n``` \\n\\n```js\\nevenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data, {\\n evenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n }\\n });\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"100\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The start, end and step properties: limiting range and/or selecting every n'th item of {{for array}}\",\r\n \"text\": \"To limit the range of an array ('slice' the array) of rendered items, use the `start` and/or `end` properties to specify the starting and ending index. In addition, the `step` property lets you take every other *n'th* item in the array.\\n\\nThe behavior of start and end corresponds to the [array.slice(start, end)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) JavaScript method: \\n\\n- `start`: zero-based index at which to begin rendering\\n - A negative index indicates an offset from the end of the sequence\\n - If `start` is undefined, begins from index `0`\\n- `end`: zero-based index before which to end rendering (render up to but not including `end`)\\n - A negative index indicates an offset from the end of the sequence\\n - If `end` is undefined, render through the end of the array\\n- `step`: A positive integer *'n'*, in order to include every *nth* item, beginning with `start`. Defaults to `1`\\n\\n```jsr\\n{{for colors start=1 end=-1 step=2}}...{{/for}}\\n```\\n\\nSetting `start=...`, `end=...` and/or `step=...` can be combined with using the [`sort`](#fortag@sort), [`reverse`](#fortag@reverse), [`filter`](#fortag@filter) to limit the item selection, after sorting, reversing or filtering.\\n\\n```jsr\\n{{for colors sort=\\\"name\\\" start=1 end=-1}}...{{/for}}\\n```\\n\\nThe following sample illustrates the use of `start=...` and `end=...` with or without sorting:\",\r\n \"anchor\": \"start-end\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for colors}}...{{/for}}\\n{{for colors start=1 end=-1}}...{{/for}}\\n{{for colors step=2}}...{{/for}}\\n{{for colors step=2 start=1}}...{{/for}}\\n{{for colors sort=\\\"\\\"}}...{{/for}}\\n{{for colors sort=\\\"\\\" start=1 end=-1}}...{{/for}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\\"red\\\", \\\"orange\\\", \\\"yellow\\\", \\\"green\\\", \\\"blue\\\", \\\"indigo\\\", \\\"violet\\\"]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"200\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample uses `step=...` to render multi-row layouts of an array of people:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people step=3 start=0 sort=\\\"name\\\" end=-2}}\\n{{for people step=3 start=1 sort=\\\"name\\\" end=-2}}\\n{{for people step=3 start=2 sort=\\\"name\\\" end=-2}}\\n```\\n\\n```jsr\\n{{for people step=2 start=0 sort=\\\"name\\\" reverse=true}}\\n{{for people step=2 start=1 sort=\\\"name\\\" reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"220\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sorting, filtering, 'slicing' operations in any order\",\r\n \"text\": \"Some of the above samples include applying a sort operation followed by a 'slice' operation. It is also possible reverse the order of operations, and to limit the range **_before_** sorting the result, as in the following two examples:\",\r\n \"anchor\": \"anyorder\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people end=-2 noIteration=true}} {{!-- slice (remove last two) --}}\\n ...\\n {{for #data step=3 start=0 sort=\\\"name\\\"}} {{!-- sort ... --}}\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"height\": \"132\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for colors start=1 end=-1 noIteration=true}} {{!-- slice (remove first and last) --}}\\n {{for #data sort=\\\"\\\"}}...{{/for}} {{!-- sort ... --}}\\n{{/for}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\\"red\\\", \\\"orange\\\", \\\"yellow\\\", \\\"green\\\", \\\"blue\\\", \\\"indigo\\\", \\\"violet\\\"]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"42\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A similar approach can be used to apply any desired `filter`, `sort`, `reverse`, or 'slice' operations in any order. For example:\\n\\n```jsr\\n{{for colors filter=~preSort noIteration=true}}\\n {{for #data sort=... noIteration=true}}\\n {{for #data filter=~afterSort}}...{{/for}}\\n {{/for}}\\n{{/for}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{for start=... end=... step=...}} to iterate over a range of numbers\",\r\n \"text\": \"The `{{for}}` tag can be used to iterate over a range of numbers, rather than iterating over a data array.\\n\\nFor example:\\n\\n```jsr\\n{{for start=0 end=4}}{{:}}, {{/for}}\\n```\\n\\nwill render the result `0, 1, 2, 3, `.\\n\\nBy setting the `start` and `end` properties (and optionally the `step` property) to appropriate `Numbers`, *but without providing any argument as data array*, the `{{for}}` tag will in fact generate a corresponding array of numbers (usually integers), and will iterate over that generated array.\\n\\n- `start`: Initial number for generated array. If undefined, defaults to `0`\\n- `end`: Number before which to end the array (generate numbers up to but not including `end`)\\n- `step`: Optional: the incremental amount for subsequent numbers in the array. Defaults to `1`\\n\\nFor example:\\n\\n```jsr\\n{{for start=4.5 end=-2 step=-1.5}}{{:}}, {{/for}}\\n```\\n\\nwill output `4.5, 3, 1.5, 0, -1.5, `\\n\\nThe following sample uses generated arrays to render table layouts of `people` 'by rows':\",\r\n \"anchor\": \"number-range\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Sorted table, by rows:*\\n\\n```jsr\\n{{for end=people.length/2 itemVar='~row'}}\\n \\n {{for ~root.people start=~row*2 end=(~row+1)*2 sort=\\\"name\\\"}}\\n \\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"240\",\r\n \"title\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Use of itemVar with noIteration=true, to reference the array\",\r\n \"text\": \"Note the use of `itemVar='~row'` in the above examples. [`itemVar`](#contextualparams@itemvar) is used to provide an alias for the current data in the wrapped content, so in this case it is the current integer as we iterate over the generated array.\\n\\nSo the following:\\n\\n```jsr\\n{{for start=0 end=4 itemVar='row'}}{{:~row}} {{/for}}\\n```\\n\\n```jsr\\n{{for start=0 end=4}}{{:}} {{/for}}\\n```\\n\\nare equivalent, and each render the result `\\\"0 1 2 3\\\"`.\\n\\nBy setting `noIteration=true` we can instead use `itemVar` for the array itself, as in the following sample:\",\r\n \"anchor\": \"itemvar\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for start=1 end=7 noIteration=true itemVar=\\\"~cols\\\"}} {{!-- ~rows is an array from 1 to 6 --}}\\n {{for start=1 end=5 noIteration=true itemVar=\\\"~rows\\\"}} {{!-- ~cols is an array from 1 to 4 --}}\\n
                    ...{{:name}}
                    \\n {{for ~rows itemVar=\\\"~j\\\"}} {{!-- iterate over ~rows array --}}\\n \\n {{for ~cols itemVar=\\\"~i\\\"}} {{!-- iterate over ~cols array --}}\\n \\n```\"\r\n }\r\n ],\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n html = myTmpl.render({});\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"title\": \"itemVar - passing arrays around then iterating over them\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following more advanced approach to sorting by columns uses the `noIteration=true itemVar=\\\"~sorted\\\"` technique:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people sort=\\\"name\\\" noIteration=true itemVar=\\\"~sorted\\\"}} {{!-- ~sorted is the sorted people array --}}\\n ...\\n {{for end=length step=2 itemVar=\\\"~col\\\"}} {{!-- iterate over even integers from 0 to ~sorted.length--}}\\n {{!-- render the person.name for ~sorted items with index 0, 2, 4... --}}\\n ...\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"100\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also the ['range' sample](#jsvfortag@jsvsortfilterrange), for an example of dynamic use of the `start` and `end` properties of `{{for}}`, along with JsViews data-linking.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/paths\",\r\n \"label\": \"Sample: Paths\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvfortag\",\r\n \"label\": \"JsViews: {^{for ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"propstag\": {\r\n \"title\": \"Template tag: {{props ...}} (Iteration over properties of an object)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{props ...}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{props}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{props}}` block is an object with properties `key` and `props`:\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"{\\n key: propertyName,\\n prop: propertyValue // could be a string, number, object, etc.\\n}\"\r\n }\r\n ],\r\n \"example\": \"{{props billing.address}}\\n {{>key}}: {{>prop}}\\n{{/props}}\",\r\n \"description\": \"Render the block content of the tag for each property of the given object\",\r\n \"variant\": \"{{props pathOrExpr}}...{{/props}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{props}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{props billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template once for each property of the given object\",\r\n \"variant\": \"{{props pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Iterate over the properties of the object, and render the block content of the {{props}} tag (or the referenced external template) once for each property – using as data context: {key: propertyName, prop: propertyValue}.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here are some examples:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"...\\n{{props address}}\\n {{>key}}: {{>prop}}
                    \\n{{/props}}\\n\"\r\n }\r\n ],\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"200\",\r\n \"html\": \"\",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"street\": \"12 Pike Place\",\r\n \"city\": \"Seattle\",\r\n \"ZIP\": \"98101\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"street\": \"5000 Broadway\",\r\n \"city\": \"Sidney\",\r\n \"country\": \"Australia\"\r\n }\r\n }\r\n ],\r\n \"markup\": \"
                    {{:~i}}, {{:~j}}... {{:~sorted[~col].name}}
                    \\n \\n \\n
                    name: {{:name}}
                    \\n {{props address}}\\n {{>key}}: {{>prop}}
                    \\n {{/props}}\\n
                    \",\r\n \"title\": \"{{props object}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props address tmpl=\\\"#addressTemplate\\\" /}}\\n```\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                    \",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"5000 Broadway\\\",\\n \\\"city\\\": \\\"Sidney\\\",\\n \\\"country\\\": \\\"Australia\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"200\",\r\n \"title\": \"{{props object tmpl=... /}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{props}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{props}}` and `{{/props}}`, allows alternate rendering based on the object returned from the path or expression `{{props pathOrExpr}}`\",\r\n \"anchor\": \"else\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{props ...}}...{{else}}...{{/props}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on whether an object is empty or not\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{props address}}\\n Key: {{:key}} Value: {{:prop}}\\n{{else}}\\n No properties...\\n{{/for}}\",\r\n \"description\": \"Render first block if object is not empty, otherwise render second block\",\r\n \"variant\": \"{{for pathOrExpr}...{{else}}...{{/for}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional blocks: – Render the block content of the {{prop}} tag (or referenced template) if the object is defined and is not an empty object (no properties), otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{props address}}\\n {{>key}}: {{>prop}}
                    \\n{{else}}\\n The address is blank (no properties)!\\n{{/props}}\"\r\n }\r\n ],\r\n \"markup\": \"\\n \\n \\n
                    name: {{:name}}
                    \\n {{props address}}\\n {{>key}}: {{>prop}}
                    \\n {{else}}\\n The address is blank (no properties)!\\n {{/props}}\\n
                    \",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"street\": \"12 Pike Place\",\r\n \"city\": \"Seattle\",\r\n \"ZIP\": \"98101\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {}\r\n }\r\n ],\r\n \"height\": \"160\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props USaddress}}\\n {{>key}}: {{>prop}}
                    \\n{{else UKaddress}}\\n {{>key}}: {{>prop}}
                    \\n{{else}}\\n The address is blank (no properties)!\\n{{/props}}\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"USaddress\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },{\\n \\\"name\\\": \\\"Jeff\\\",\\n \\\"UKaddress\\\": {\\n \\\"street\\\": \\\"3a Upton Place\\\",\\n \\\"city\\\": \\\"London\\\",\\n \\\"code\\\": \\\"W2 1JA\\\"\\n }\\n },{\\n \\\"name\\\": \\\"Heidi\\\",\\n }\\n ],\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"240\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The noFunctions property\",\r\n \"text\": \"By default `{{props}}` will iterate over all members of an object, including members of type: *function* (methods). To prevent outputting members of type *function*, set the `noFunctions` property to `true`:\\n\\n```jsr\\n{{props ... noFunctions=true}}\\n```\\n\\n\",\r\n \"anchor\": \"nofunctions\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props person noFunctions=true}}\\n {{>key}}: {{>prop}}
                    \\n{{/props}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {\\n person: {\\n first: \\\"Jo\\\",\\n last: \\\"Blow\\\",\\n fullName: function() {\\n return this.first + \\\" \\\" + this.last;\\n }\\n }\\n },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{props}} to iterate over a top-level dictionary/hash data-collection\",\r\n \"text\": \"If the data (obtained for example, from the server) is a collection, but in the form of an object (dictionary/hash) rather than an array, then *__`{{props}}`__* without arguments (or equivalently *__`{{props #data}}`__*) can be used to iterate over the collection, as shown in the next sample:\\n\\n(When using JsViews, see also [`{^{props}}`](#jsvpropstag@load-hash) for loading and providing complete editability of a top-level dictionary/hash.)\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Dictionary/hash -- collection of people:*\\n\\n```js\\nvar people = {\\n pt1: {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n ...\\n }\\n },\\n Hd1: {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n ...\\n }\\n }\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                    \",\r\n \"code\": \"var people = {\\n pt1: {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },\\n Hd1: {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"5000 Broadway\\\",\\n \\\"city\\\": \\\"Sidney\\\",\\n \\\"country\\\": \\\"Australia\\\"\\n }\\n }\\n};\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"height\": \"194\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{props}} with specific sorting, filtering or range of the rendered properties\",\r\n \"text\": \"When using the `{{props}}` tag to render properties, built-in features allow sorting, filtering and 'slicing' of the rendered list. (These features correspond exactly to the equivalent [sorting and filtering](#fortag@sortfilterrange) features provided by the`{{for}}` tag):\",\r\n \"anchor\": \"sortfilterrange\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The reverse property: specifying reverse ordering (or reverse sorting) on {{props object}}\",\r\n \"text\": \"To iterate over the object properties in reverse order, set the `reverse` property to `true`:\\n\\n```jsr\\n{{props object reverse=true }}...{{/props}}\\n```\\n\\nSetting `reverse=true` can be combined with using the [`sort`](#propstag@sort), [`filter`](#propstag@filter), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties, to reverse the order of iteration (for example to sort in *descending* order rather than *ascending* order).\",\r\n \"anchor\": \"reverse\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The sort property: specifying sorting on {{props object}}\",\r\n \"text\": \"To specify sorting, set the `sort` property: \\n\\n```jsr\\n{{props object sort=\\\"prop.firstName\\\" }}...{{/props}}\\n```\\n\\n- To sort the properties by *key*, set `sort=\\\"key\\\"`\\n- If the properties are objects (a 'hash' of objects), the `sort=...` property of `{{props}}` is usually set to an object property to be sorted by, such as `prop.firstName`, or to a data path, such as `sort=\\\"prop.address.street\\\"`\\n- To sort a hash of numbers, strings or `Date`s, set the `sort` property to: `sort=\\\"prop\\\"`\\n- For advanced scenarios you can provide your own sort function: `sort=~mySortFunction`\\n\\nSetting `sort=...` can be combined with using the [`reverse`](#propstag@reverse), [`filter`](#propstag@filter), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties.\\n\\nThe following three samples illustrate the above scenarios, using the `reverse` and `sort` properties:\",\r\n \"anchor\": \"sort\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                    Template:
                    *\\n```jsr\\n{{props colors sort=\\\"prop\\\" reverse=true}} {{!-- (Reverse) sort string properties --}}\\n{{props amounts sort=\\\"key\\\"}} {{!-- Sort Number properties by key --}}\\n{{props dates sort=\\\"prop\\\"}} {{!-- Sort Date properties --}}\\n```\\n\\n*
                    Data:
                    *\\n```js\\ncolors: {c1: \\\"red\\\", ...},\\namounts: {\\\"1st quarter\\\": 111.2, ...},\\ndates: {Created: new Date(2000, 0, 1), ...}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"$.views.converters(\\\"formatDate\\\", function(date) {\\n // Converter to format Dates\\n return date.toLocaleDateString(\\\"en-US\\\");\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"white\\\",\\n c3: \\\"blue\\\"\\n },\\n amounts: {\\n \\\"1st quarter\\\": 111.2,\\n \\\"3rd quarter\\\": -2.33,\\n \\\"4th quarter\\\": 2.4,\\n \\\"2nd quarter\\\": -22\\n },\\n dates: {\\n Created: new Date(2000, 0, 1),\\n Deleted: new Date(2000, 11, 31),\\n Edited: new Date(1998, 6, 30)\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"110\",\r\n \"title\": \"Sorting strings/Numbers/Date properties\",\r\n \"anchor\": \"sortvalues\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                    Template:
                    *\\n```jsr\\n{{props people sort=\\\"prop.lastName\\\" reverse=true}}...{{/props}} {{!-- Sort by last name, decreasing --}}\\n{{props people sort=\\\"prop.address.street\\\"}} {{!-- Sort by address.street --}}\\n{{props people sort=\\\"key\\\" reverse=true}} {{!-- Reverse sort by key --}}\\n```\\n\\n*
                    Data:
                    *\\n```js\\npeople: {\\n p1: {firstName: \\\"Jo\\\", ... address: {street: \\\"1st Street\\\" ...}},\\n ...\\n}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"Sort by last name, decreasing\\n
                      \\n {{props people sort=\\\"prop.lastName\\\" reverse=true}}\\n
                    • {{:prop.firstName}} {{:prop.lastName}}
                    • \\n {{/props}}\\n
                    \\n\\nSort by street\\n
                      \\n {{props people sort=\\\"prop.address.street\\\"}}\\n
                    • {{:prop.firstName}}: {{:prop.address.street}}
                    • \\n {{/props}}\\n
                    \\n\\nReverse sort by key\\n
                      \\n {{props people sort=\\\"key\\\" reverse=true}}\\n
                    • {{:key}}: {{:prop.firstName}} {{:prop.lastName}}
                    • \\n {{/props}}\\n
                    \",\r\n \"data\": {\r\n \"people\": {\r\n \"p1\": {\r\n \"firstName\": \"Jo\",\r\n \"lastName\": \"Blow\",\r\n \"address\": {\r\n \"street\": \"1st Street\"\r\n }\r\n },\r\n \"p2\": {\r\n \"firstName\": \"Adriana\",\r\n \"lastName\": \"Zhang\",\r\n \"address\": {\r\n \"street\": \"1st Avenue\"\r\n }\r\n },\r\n \"p3\": {\r\n \"firstName\": \"Xavier\",\r\n \"lastName\": \"Rossi\",\r\n \"address\": {\r\n \"street\": \"2nd Street\"\r\n }\r\n }\r\n }\r\n },\r\n \"height\": \"290\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Sorting a hash of objects\",\r\n \"anchor\": \"sortobjects\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people sort=~multilevel}}...{{/props}} {{!-- Sort using a custom helper function: ~multilevel --}}\\n```\\n\\nThe custom sort function takes arguments `(a, b)` for the two objects being compared. The `this` pointer is the current `view` object.\\n\\n```js\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n return ... // Return 1, -1 or 0 to specify relative position of `a` and `b` in the sort order\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"// Helper function for multi-level sort\\nfunction level(aField, bField) {\\n return aField > bField ? 1 : aField < bField ? -1 : 0;\\n}\\n\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n // Sort by role, then by age (descending) then by name\\n return level(a.prop.details.role.toLowerCase(), b.prop.details.role.toLowerCase()) // by role\\n || level(b.prop.details.age, a.prop.details.age) // by age\\n || level(a.prop.name.toLowerCase(), b.prop.name.toLowerCase()); // by name\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: {\\n p1: {name: \\\"Bill\\\", details: {age: 22, role: \\\"Lead\\\"}},\\n p2: {name: \\\"Anne\\\", details: {age: 32, role: \\\"Assistant\\\"}},\\n p3: {name: \\\"Emma\\\", details: {age: 19.1, role: \\\"Team member\\\"}},\\n p4: {name: \\\"Jeff\\\", details: {age: 33.5, role: \\\"Lead\\\"}},\\n p5: {name: \\\"Xavier\\\", details: {age: 32, role: \\\"Team member\\\"}},\\n p6: {name: \\\"Julia\\\", details: {age: 18, role: \\\"Assistant\\\"}},\\n p7: {name: \\\"Bill\\\", details: {age: 32, role: \\\"Team member\\\"}}\\n }},\\n\\n html = myTmpl.render(data, { \\n multilevel: multilevelSort\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"150\",\r\n \"title\": \"Using a custom sort function: multi-level sort \",\r\n \"anchor\": \"sortcustom\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The filter property: specifying filtering on {{props object}}\",\r\n \"text\": \"To filter the rendered properties, use the `filter` property to specify a filter function: \\n\\n```jsr\\n{{props object filter=~myfilter}}...{{/props}}\\n```\\n\\n```js\\nfunction myfilter(item, index, items) {\\n return ...; // Return true/false to include/exclude any item from the result\\n}\\n```\\n\\nThe filter function is called with the `tagCtx` object as `this` pointer, and with arguments:\\n\\n- `item`: The current `{key:..., prop:...}` 'property' object being processed\\n- `index`: The index of the current item being processed in the (sorted) array of 'property' objects\\n- `array`: The (sorted) array of 'property' objects being filtered\\n\\nSetting `filter=...` can be combined with using the [`sort`](#propstag@sort), [`reverse`](#propstag@reverse), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties (to filter the items after sorting or reversing, or before 'slicing').\\n\\n\\nThe following sample renders a subset of a hash of `people`, filtered by age:\",\r\n \"anchor\": \"filter\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction ageRangeFilter(item, index, items) {\\n return item.prop.details.age > this.props.minAge ...\\n}\\n```\\n\\n```jsr\\n{{props people filter=~ageRange minAge=20 maxAge=40 sort=\\\"prop.name\\\"}}...{{/props}}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"120\",\r\n \"code\": \"function ageRangeFilter(item, index, items) {\\n return item.prop.details.age > this.props.minAge && item.prop.details.age < this.props.maxAge;\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Bill\\\", details: {age: 25}},\\n p2: {name: \\\"Anne\\\", details: {age: 32}},\\n p3: {name: \\\"Emma\\\", details: {age: 19.1}},\\n p4: {name: \\\"Jeff\\\", details: {age: 33.5}},\\n p5: {name: \\\"Xavier\\\", details: {age: 52}},\\n p6: {name: \\\"Julia\\\", details: {age: 18}},\\n p7: {name: \\\"Jo\\\", details: {age: 30}}\\n }\\n },\\n\\n html = myTmpl.render(data, { \\n ageRange: ageRangeFilter\\n });\\n\\n$(\\\"#page\\\").html(html);\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample renders a hash of `people` in a two row layout -- by filtering for the items with even (first row) and odd (second row) index.\\n\\n(See also an alternative approach using `step=...`, in the [section](#propstag@start-end) below).\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people filter=~evenOdd odd=false sort=\\\"prop.name\\\"}}...{{/props}}\\n...\\n{{props people filter=~evenOdd odd=true sort=\\\"prop.name\\\"}}...{{/props}}\\n``` \\n\\n```js\\nevenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data, {\\n evenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n }\\n });\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"100\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The start, end and step properties: limiting range and/or selecting every n'th item of {{props object}}\",\r\n \"text\": \"To limit the range of rendered properties, use the `start` and/or `end` properties to specify the starting and ending index. In addition, the `step` property lets you take every other *n'th* item in the array of 'property' objects.\\n\\nThe behavior of start and end corresponds to the [array.slice(start, end)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) JavaScript method: \\n\\n- `start`: zero-based index at which to begin rendering\\n - A negative index indicates an offset from the end of the sequence\\n - If `start` is undefined, begins from index `0`\\n- `end`: zero-based index before which to end rendering (render up to but not including `end`)\\n - A negative index indicates an offset from the end of the sequence\\n - If `end` is undefined, render through the end of the array\\n- `step`: A positive integer *'n'*, in order to include every *nth* item, beginning with `start`. Defaults to `1`\\n\\n```jsr\\n{{props colors start=1 end=-1 step=2}}...{{/props}}\\n```\\n\\nSetting `start=...`, `end=...` and/or `step=...` can be combined with using the [`sort`](#propstag@sort), [`reverse`](#propstag@reverse), [`filter`](#propstag@filter) to limit the range, after sorting, reversing or filtering.\\n\\n```jsr\\n{{props colors sort=\\\"name\\\" start=1 end=-1 step=2}}...{{/props}}\\n```\\n\\nThe following sample illustrates the use of `start=...` and `end=...` with or without sorting:\",\r\n \"anchor\": \"start-end\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props colors}}...{{/props}}\\n{{props colors start=1 end=-1}}...{{/props}}\\n{{props colors step=2}}...{{/props}}\\n{{props colors step=2 start=1}}...{{/props}}\\n{{props colors sort=\\\"name\\\"}}...{{/props}}\\n{{props colors sort=\\\"name\\\" start=1 end=-1}}...{{/props}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"orange\\\",\\n c3: \\\"yellow\\\",\\n c4: \\\"green\\\",\\n c5: \\\"blue\\\",\\n c6: \\\"indigo\\\",\\n c7: \\\"violet\\\"\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"200\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample uses `step=...` to render multi-row layouts of a hash of people:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people step=3 start=0 sort=\\\"name\\\" end=-2}}\\n{{props people step=3 start=1 sort=\\\"name\\\" end=-2}}\\n{{props people step=3 start=2 sort=\\\"name\\\" end=-2}}\\n```\\n\\n```jsr\\n{{props people step=2 start=0 sort=\\\"name\\\" reverse=true}}\\n{{props people step=2 start=1 sort=\\\"name\\\" reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"height\": \"220\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sorting, filtering, 'slicing' operations in any order\",\r\n \"text\": \"Some of the above samples include applying a sort operation followed by a 'slice' operation. It is also possible reverse the order of operations, and to limit the range **_before_** sorting the result, as in the following two examples:\",\r\n \"anchor\": \"anyorder\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people end=-2 noIteration=true}} {{!-- slice (remove last two) --}}\\n ...\\n {{for #data step=3 sort=\\\"prop.name\\\"}} {{!-- sort ... --}}\\n ...\\n```\"\r\n }\r\n ],\r\n \"height\": \"132\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props colors start=1 end=-1 noIteration=true}} {{!-- slice (remove first and last) --}}\\n {{for #data sort=\\\"prop\\\"}}...{{/for}} {{!-- sort ... --}}\\n{{/props}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"orange\\\",\\n c3: \\\"yellow\\\",\\n c4: \\\"green\\\",\\n c5: \\\"blue\\\",\\n c6: \\\"indigo\\\",\\n c7: \\\"violet\\\"\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"42\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A similar approach can be used to apply any desired `filter`, `sort`, `reverse`, or 'slice' operations in any order. For example:\\n\\n```jsr\\n{{props colors filter=~preSort noIteration=true}}\\n {{for #data sort=... noIteration=true}}\\n {{for #data filter=~afterSort}}...{{/for}}\\n {{/for}}\\n{{/props}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/paths\",\r\n \"label\": \"Sample: Paths\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvpropstag\",\r\n \"label\": \"JsViews: {^{props ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"iftag\": {\r\n \"title\": \"Template tag: {{if ...}} (Conditional inclusion)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Conditional block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{if}}` block is the same as the outer context\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{/if}}\",\r\n \"description\": \"Render the block only if the expression is true\",\r\n \"variant\": \"{{if pathOrExpr}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Conditional inclusion of external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{if nickname tmpl=\\\"nicknameTemplate\\\" /}}\",\r\n \"description\": \"Render the specified template only if the expression is true\",\r\n \"variant\": \"{{if pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional inclusion: – Render the block content of the {{if}} tag (or the referenced external template) only if the data-path or expression evaluates to true (or a 'truthy' value)\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{if}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{if}}` and `{{/if}}`, allows alternate rendering based on 'if ... else ...' logic:\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ...}}...{{else}}...{{/if}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on an expression\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{if}}` and `{{else}}` blocks is the same as the outer context\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{else}}\\n No nickname...\\n{{/if}}\",\r\n \"description\": \"Render first block if condition is true, otherwise render second block\",\r\n \"variant\": \"{{if pathOrExpr}...{{else}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render different templates depending on one or more expressions\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{if nickname tmpl=\\\"nicknameTemplate\\\"}}\\n{{else tmpl=\\\"noNicknameTemplate\\\"}}\\n{{/if}}\",\r\n \"description\": \"Render first template if condition is true, otherwise render second template\",\r\n \"variant\": \"{{if pathOrExpr1 tmpl=nameOrExpr1 }}{{else tmpl=nameOrExpr2 }}{{/if}}\"\r\n }\r\n ],\r\n \"description\": \"Alternative conditional blocks: – Render the block content of the {{if}} tag (or referenced template) if the expression is true, otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"else and elseif\",\r\n \"text\": \"You can add more than one `{{else}}` tag between `{{if}}` and `{{/if}}`, to get alternate rendering based on 'if ... elseif ... else ...' logic. For elseif, just include an expression...:\\n\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ....}}...{{else ...}}...{{else}}...{{/if}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on one or more expressions\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: Any of the `{{if}}` or `{{else}}` tags can have a `tmpl=nameOrExpr` parameter. The external template will be used instead of block content for that tag.\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{else altnickname}}\\n Alternate nickname: {{:altnickname}}\\n{{else}}\\n No nickname...\\n{{/if}}\",\r\n \"description\": \"Render first block for which condition is true, otherwise last block\",\r\n \"variant\": \"{{if pathOrExpr1}}...{{else pathOrExpr2}}...{{else}}...{{/if}\"\r\n }\r\n ],\r\n \"description\": \"Multiple alternative conditional blocks: – Render the first {{if}} or {{else}} block for which the expression is true. If none are true, and there is an {{else}} without an expression, render that block\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n[\\n {title: \\\"The A team\\\", members: [...], standby: [...]},\\n {title: \\\"The B team\\\", members: [], standby: [...]},\\n {title: \\\"The C team\\\", standby: []}\\n]\\n```\\n\\n```jsr\\n{{if members && members.length}}\\n ...\\n{{else standby && standby.length}}\\n Standby only:\\n ...\\n{{else}}\\n No members!\\n{{/if}}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"

                    {{:title}}

                    \\n{{if members && members.length}}\\n
                      \\n {{for members}}\\n
                    • {{:name}}
                    • \\n {{/for}}\\n
                    \\n{{else standby && standby.length}}\\n Standby only:\\n
                      \\n {{for standby}}\\n
                    • {{:name}}
                    • \\n {{/for}}\\n
                    \\n{{else}}\\n No members!\\n{{/if}}\",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\"\r\n },\r\n {\r\n \"name\": \"Heidi\"\r\n }\r\n ],\r\n \"standby\": [\r\n {\r\n \"name\": \"Xavier\"\r\n }\r\n ]\r\n },\r\n {\r\n \"title\": \"The B team\",\r\n \"members\": [],\r\n \"standby\": [\r\n {\r\n \"name\": \"Robert\"\r\n },\r\n {\r\n \"name\": \"Adriana\"\r\n }\r\n ]\r\n },\r\n {\r\n \"title\": \"The C team\",\r\n \"standby\": []\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"300\",\r\n \"title\": \"{{if}}...{{else}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsviftag\",\r\n \"label\": \"JsViews: {^{if ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"elsetag\": {\r\n \"title\": \"Template tag: {{else ...}} (Content blocks separator)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"{{else}} can be used with {{if}}, {{for}}, {{props}} or any custom tag!\",\r\n \"text\": \"The `{{else}}` tag acts as a separator, for block tags, to divide the content of a tag into two or more different content blocks.\\n\\nSo it allows a block tag to provide specific behavior involving more than one content block.\\n\\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\\n\\n```jsr\\n{{if firstExpression}}\\n render this if the firstExpression is true\\n{{else secondExpression}}\\n else render this if the secondExpression is true\\n{{else}}\\n else render this\\n{{/if}}\\n```\\n\\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\\n\\n```jsr\\n{{for members}}\\n Member Name: {{:name}}\\n{{else}}\\n There are currently no members...\\n{{/for}}\\n```\\n\\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\\n\\n```jsr\\n{{tabs caption=\\\"First Tab\\\"}}\\n first tab content\\n{{else caption=\\\"Second Tab\\\"}}\\n second tab content\\n{{/tabs}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"iftag\",\r\n \"label\": \"{{if}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"fortag\",\r\n \"label\": \"{{for}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"propstag\",\r\n \"label\": \"{{props}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls/tabs\",\r\n \"label\": \"Sample: tabs control\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvelsetag\",\r\n \"label\": \"JsViews: {{else}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"commenttag\": {\r\n \"title\": \"Template tag: {{!-- ... --}} (Comment)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{!-- a comment --}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Adding comments\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{!-- this is a comment --}}\",\r\n \"description\": \"The comment will be ignored during template rendering – and will produce no output\",\r\n \"variant\": \"\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Commenting out sections of a template\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{!-- this section will be omitted \\n\\nDo I really want to show this? {{:password}}\\n\\n--}}\",\r\n \"description\": \"The comment can be multiline. All content will be ignored during template rendering - and will produce no output\",\r\n \"variant\": \"\"\r\n }\r\n ],\r\n \"description\": \"Adding comments to templates, or commenting out sections of a template\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender comment tags versus HTML comments\",\r\n \"text\": \"You can include \\n\\n```jsr\\n\\n```\\n\\n— but unlike the JsRender comment tag, the HTML comment will not be ignored by JsRender or JsViews. It will be included in the rendered output, and will get inserted into the DOM along with other rendered markup.\"\r\n }\r\n ]\r\n },\r\n \"allowcodetag\": {\r\n \"title\": \"Template tags: {{*... }} and {{*: ... }} (Allow code)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\\n\\n```jsr\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n```\\n\\nNevertheless, in order to improve encapsulation and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \\n\\nIf you want complete freedom to insert any code into a compiled template, you can [set **allowCode**](#settings/allowcode) to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the `{{* ...}}` tag, or you can return (render into the template output) the result of evaluating any expression, using the `{{*: ...}}` tag.\\n\\n(*Note:* these ***allow code*** tags are not recommended for use within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{* ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert code\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"anyJavascriptCode \",\r\n \"type\": \"code\",\r\n \"optional\": false,\r\n \"description\": \"\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{* window.myvar=2; myvar+=4; }}\",\r\n \"description\": \"If allowCode is set to true, include any code in the compiled template.\",\r\n \"variant\": \"{{* anyJavascriptCode /}}\"\r\n }\r\n ],\r\n \"description\": \"Insert code into the template\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{*: ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Evaluate expression\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"anyJavascriptExpression \",\r\n \"type\": \"code\",\r\n \"optional\": false,\r\n \"description\": \"\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{*: myvar/2 }}\",\r\n \"description\": \"If allowCode is set to true, evaluate any expression, and insert the result into the rendered output.\",\r\n \"variant\": \"{{*: anyJavascriptExpression /}}\"\r\n }\r\n ],\r\n \"description\": \"Evaluate any code expression\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example, with `allowCode` set to `true` globally:\\n\\n```js\\n$.views.settings.allowCode(true);\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Enable `allowCode` in all templates:\\n\\n```js\\n$.views.settings.allowCode(true);\\n```\\n\\nDefine a global variable, then increment it:\\n\\n```jsr\\n{{* window.myvar=2; myvar+=4; }}\\n```\\n\\nInsert the value into the rendered output:\\n\\n```jsr\\n
                    Initial value: {{*:myvar}}
                    \\n```\\n\\nIncrement the value again, and output the new value:\\n\\n```js\\n{{* window.myvar+=11; }}\\n\\n
                    New value: {{*:myvar}}
                    \\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"code\": \"$.views.settings.allowCode(true); \\n\\nvar html = $(\\\"#myTemplate\\\").render();\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"title\": \"allowCode\",\r\n \"markup\": \"\",\r\n \"anchor\": \"sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is an example that uses both regular JsRender tags, like `{{for}}`, and allowCode tags:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(true);\\n```\\n\\nDefine a global variable:\\n\\n```jsr\\n{{* window.total = 0}}\\n```\\n\\nIterate through a list, and use `{{* ...}}` to increment the `total`, and `{{*:}}` to return each value:\\n\\n```js\\n{{for list}}\\n {{* total += data}}\\n
                  • \\n Amount {{:}} (Running total: {{*: total}})\\n
                  • \\n{{/for}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"144\",\r\n \"code\": \"var data = {\\n title: \\\"My list\\\",\\n list: [2, 10.3, 77, -44, -5.5]\\n };\\n\\n$.views.settings.allowCode(true);\\n\\nvar html = $(\\\"#myTemplate\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"title\": \"allowCode and regular tags\",\r\n \"anchor\": \"plusreg\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is another example, in which we will replace the `{{for list}}` iteration by pure code-based iteration using `{{* ...}}`. This makes it easy to iterate only over the odd members of the array.\\n\\n
                    This time we will allow code ***just for this template***:\\n\\n```js\\n$.templates(..., {\\n markup: ...,\\n allowCode: true,\\n ...\\n})\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Enable allowCode just for this template:\\n\\n```js\\nvar tmpl = $.templates({\\n markup: \\\"#myTemplate\\\",\\n allowCode: true\\n });\\n \\nvar html = tmpl.render(data);\\n```\\n\\nInsert template code to iterate over odd numbers:\\n\\n```jsr\\n{{* for (i=0; ifor block, {{* } }} into the template code:\\n\\n```jsr\\n {{* } }}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"110\",\r\n \"code\": \"var data = {\\n title: \\\"My list\\\",\\n list: [2, 10.3, 77, -44, -5.5]\\n };\\n\\nvar tmpl = $.templates({\\n markup: \\\"#myTemplate\\\",\\n allowCode: true\\n });\\n \\nvar html = tmpl.render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"title\": \"allowCode for template\",\r\n \"anchor\": \"tmpl\"\r\n }\r\n ]\r\n },\r\n \"customtagsapi\": {\r\n \"title\": \"Custom tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining custom tags\",\r\n \"text\": \"JsRender deliberately has only a small number of built-in tags -- each of which is very flexible and useful. This is intended to reduce the 'learning curve'. And at the same time JsRender makes it very easy to create your own custom tags:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tags\",\r\n \"label\": \"Using custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsapi\",\r\n \"label\": \"Registering custom tags: $.view.tags()\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"rendertmpl\": {\r\n \"title\": \"Render a template\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A template is rendered by calling the `render()` method.\\n\\nThe `render(data, helpersOrContext)` method takes as parameters the data (used as the 'data context' during the rendering), and optionally additional metadata or contextual helpers. It returns a string -- which is the rendered template -- typically HTML markup with data values or computed values inserted at appropriate points in the string.\\n\\nThere are three ways of calling the `render()` method:\\n- If you have a reference to the template object -- `myTmpl`, call [myTmpl.render(...)](#tmplrender)\\n- If you have registered the template by name -- `\\\"myTmpl\\\"`, call [$.render.myTmpl(...)](#d.render)\\n- If the template is declared in a script block, with selector `\\\"#myTmpl\\\"`, you can also call [$(\\\"#myTmpl\\\").render(...)](#db.render)\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tmplrender\",\r\n \"label\": \"myTmpl.render()\"\r\n },\r\n {\r\n \"hash\": \"d.render\",\r\n \"label\": \"$.render.myTmpl()\"\r\n },\r\n {\r\n \"hash\": \"db.render\",\r\n \"label\": \"$(\\\"#myTmpl\\\").render()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tmplrender\": {\r\n \"title\": \"Render a template against data objects or arrays\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"myTmpl.render()\",\r\n \"text\": \"If `myTmpl` is the compiled template object for your template, you can render it using the `myTmpl.render()` method -- which takes a data object or array (as well as an optional helpersOrContext object), and returns the rendered template as a string.\\n\\nThere is also a shortcut version of the `render()` method: you can call the template object itself as a function: `var html = myTmpl(data)` -- which is equivalent to `var html = myTmpl.render(data)`.\\n\\nTo get a template object from a template string, a template declared in a script block, or a previously registered *named template*, see [`$.templates()`](#d.templates).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(myData);\",\r\n \"description\": \"Render template against data\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, and return a string.\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing an object to the `render()` method.\\n\\n*--- The template is rendered once, with the object as data context:*\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar html = myTmpl.render(person);\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"template.render(object):\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"50\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing an array to the `render()` method.\\n\\n*--- The template is rendered once for each item in the array:*\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var html = myTmpl.render(people);\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\\n\\nvar html = myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"template.render(array):\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing helpers to the `render()` method.\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data, helpersOrContext)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(myData, myHelpers);\",\r\n \"description\": \"Render template against data, and pass in helpers\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, along with helper objects or context, and return a string\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"helpers\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"You can pass in any JavaScript type (object, string, number, function...) as helpers on the `helpersOrContext` object, and use them as metadata, or as helper functions for formatting etc.\\n\\nNote: By passing in helpers in this way, you are making them specific to this render call. Alternatively, you can declare helpers globally, -- and you can also declare helpers that are private to a specific template. See *[Registering helpers: `$.views.helpers()`](#helpers)* for details...\\n\\nWithin the template, helpers (whether global, or passed in to the `render()` method) are accessed by *helper paths*: `~keyName`. \\n\\nFor example you might pass in an object with some utility functions:\\n\\n```js\\nvar myHelpers = {\\n util: {\\n split: function(val, part) {...},\\n ...\\n },\\n ...\\n};\\n\\nvar html = myTmpl.render(myData, myHelpers);\\n```\\n\\n-- and access them in the template using a *helper path* such as:\\n\\n```jsr\\n{{:~util.split(fullName, 0)}}\\n```\\n\\nSee *[Registering helpers](#helpers)*.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction toUpper(val) {...}\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = myTmpl.render(person, myHelpers);\\n```\\n\\n```jsr\\n\\n {{:~format(name)}}\\n\\n```\\n\\nClick Try it and change the color to \\\"green\\\"...\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"function toUpper(val) { return val.toUpperCase(); }\\n\\nvar myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = myTmpl.render(person, myHelpers);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"template.render(object, myHelpers):\",\r\n \"height\": \"52\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Passing an array to render(), but without iteration.\",\r\n \"text\": \"When rendering an array, an additional optional boolean parameter, `true`, can be passed to the `render()` method, in order to prevent iteration.\\n\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data, helpersOrContext, noIteration)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(data, helpers, true);\",\r\n \"description\": \"Render template against data, pass in helpers, and specify iteration behavior\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, along with helpers/context (and determine iteration behavior with array data). Return a string. \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"noiteration\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"By passing in `true` as the third *'noIteration'* parameter (or as second parameter if no `helpersOrContext` are passed), the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\\n\\nWithin the template, `{{for}}` (or equivalently `{{for #data}}`) can be used to iterate over the array, as in the following example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Code:\\n\\n```js\\nvar html = myTmpl.render(people, true);\\n```\\n\\nTemplate:\\n\\n```jsr\\n\\n \\n \\n {{for}}\\n \\n {{/for}}\\n \\n
                    \\n {{:#data.length}} people\\n
                    \\n {{:name}}\\n
                    \\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"110\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\\n\\nvar html = myTmpl.render(people, true);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"template.render(array, helpers, noIteration):\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternative compact syntax for render() call\",\r\n \"text\": \"The compiled template is in fact *itself a function*, equivalent to its own `render()` method. \\n\\nThis means that any `render()` call can be replaced by an equivalent (but more compact) syntax, as shown in the following example:\\n\\n```js\\nvar html = myTmpl(people, helpers, true);\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"d.render\": {\r\n \"title\": \"Render a named template without needing the template object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"$.render.myTmpl()\",\r\n \"text\": \"If a template has been [registered](#d.templates) as a named template:\\n\\n```js\\n$.templates(\\\"myTmpl\\\", \\\"#personTmpl\\\");\\n```\\n\\nor\\n\\n```js\\n$.templates(\\\"myTmpl\\\", \\\"some markup string\\\");\\n```\\n\\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates).\\n\\nJust call `$.render.myTmpl(...)`, or `$.render[\\\"myTmpl\\\"](...)`\\n\\n(**Note:** there is also an alternative syntax for rendering a named template: `$.templates.myTmpl(...);`)\\n\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.render.myTmpl(data, helpersOrContext, noIteration)\",\r\n \"name\": \"myTmpl\",\r\n \"object\": \"$.render\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = $.render.myTmpl(data, helpers, true);\",\r\n \"description\": \"Render template against data. Optionally pass in helpers and specify iteration behavior.\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data. Return a string.
                    (Optionally provide helpers/context, and specify iteration behavior). \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar html = $.render.personTmpl(person);\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"function toUpper(val) { return val.toUpperCase(); }\\n\\n$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = $.render.personTmpl(person, myHelpers);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"$.render.personTmpl(...):\",\r\n \"height\": \"50\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"db.render\": {\r\n \"title\": \"jQuery instance method to render a template declared in a script block\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"$(\\\"#myTmpl\\\").render()\",\r\n \"text\": \"If a template has been [registered](#d.templates) using a script block:\\n\\n```jsr\\n\\n```\\n\\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates), and without registering a named template.\\n\\nJust call `$(\\\"#myTmpl\\\").render(...)`\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$(tmplSelector).render(data, helpersOrContext, noIteration)\",\r\n \"name\": \"render\",\r\n \"object\": \"$(tmplSelector)\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = $(\\\"#myTmpl\\\").render(myData, myHelpers, true);\",\r\n \"description\": \"Render template against data. Optionally pass in helpers and specify iteration behavior.\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data. Return a string.
                    (Optionally provide helpers/context, and specify iteration behavior). \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"$(\\\"#personTemplate\\\").render(...):\",\r\n \"height\": \"50\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"compiletmpl\": {\r\n \"title\": \"Using templates\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering templates](#d.templates): The `$.views.templates()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining templates\",\r\n \"text\": \"To define a template you need to provide the markup for the template. JsRender will convert (compile) the markup into a JavaScript function -- the 'render' function for your template. In fact for convenience, JsRender creates a *template object* which has a [`template.render()`](#rendertmpl) method which is the compiled function.\\n\\nThere are two ways to create a template:\\n\\n- Pass the markup string to the [`$.templates()`](#d.templates) method\\n- Declare the template in a script block with `type=\\\"text/x-jsrender\\\"` (or at least a type other than the default `text/javascript`), then pass the jQuery selector for the script block to the [`$.templates()`](#d.templates) method\\n\\nIn either case, the `$.templates()` method will compile a template object, and optionally register it by name.\\n\\nHere is an example of the first approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"We pass our markup string to the [`$.templates()`](#d.templates) method:\\n\\n```jsr\\nvar myTmpl = $.templates(\\\" {{:name}} \\\");\\n```\\n\\nthen call the [`render()`](#rendertmpl) method on the returned template object:\\n\\n```js\\nvar html = myTmpl.render(people);\\n```\"\r\n }\r\n ],\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"
                    \",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}} \\\");\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\\n\\nvar html = myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering a template from a template markup string:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is an example of the second:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This time we put our markup in a script block with `type=\\\"text/x-jsrender\\\"`\\n\\n```jsr\\n\\n```\\n\\nand then in the code we call the [`$.templates()`](#d.templates) method with a jQuery selector for that script block: \\n\\n```jsr\\nvar myTmpl = $.templates(\\\" {{:name}} \\\");\\n```\\n\\nThen as before we call the [`render()`](#rendertmpl) method on the returned template object:\\n\\n```js\\nvar html = myTmpl.render(people);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\\n\\nvar html =myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering a template declared in script block:\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The first approach above has the advantage of keeping your template declaration independent of the HTML markup that you are loading into the browser. Indeed you may want to provide the template markup strings for your templates in different application-specific ways, such as loading the string from the server (using a script file or text or html file), creating 'computed' template markup strings on the fly, etc.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example of fetching the markup string from the server\",\r\n \"text\": \"Here is a simple example of fetching the markup string from the server. We load a `.../person.js` file from the server which registers a named `\\\"person\\\"` template.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"We load the *person.js* script from the server, which registers a named `\\\"person\\\"` template:\\n\\n```js\\n$.templates(\\\"person\\\", \\\" {{:name}} \\\");\\n```\\n\\nAs soon as the script is loaded, we call the [`render(...)`](#d.render) method for the registered template:\\n\\n```js\\n$.getScript(\\\".../person.js\\\", function() {\\n var html = $.render.person(people);\\n $(\\\"#peopleList\\\").html(html);\\n });\\n```\\n\\n*Note:* For a more sophisticated example of lazy loading of scripts for registering templates, see the [remote templates](#samples/jsr/composition/remote-tmpl) sample.\"\r\n }\r\n ],\r\n \"markup\": \"\\n\",\r\n \"data\": {},\r\n \"code\": \"$.getScript(\\\"//www.jsviews.com/samples/resources/templates/person.js\\\", function() {\\n var html = $.render.person(people);\\n $(\\\"#peopleList\\\").html(html);\\n });\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\",\r\n \"html\": \"
                    \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"title\": \"Fetching a script file from the server, which registers a named template from a string\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/resources/templates/person.js\",\r\n \"label\": \"person.js\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is a variant of the same sample, where we fetch a text file containing the template markup:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The markup string is fetched in an AJAX request (the *person.txt* file).\\n\\n```jsr\\n {{:name}}\\n```\\n\\nAs soon as the request returns, we use the markup string to compile the `personTemplate` object. This time we will not register it as a *named template*, but instead directly call the [`render(...)`](#tmplrender) method of the returned `personTemplate` object:\\n\\n```js\\n$.get(\\\"...person.txt\\\", function(value) {\\n personTemplate = $.templates(value);\\n var html = personTemplate.render(people);\\n $(\\\"#peopleList\\\").html(html);\\n});\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\",\r\n \"code\": \"var personTemplate;\\n\\n$.get(\\\"resources/templates/person.txt\\\", function(value) {\\n personTemplate = $.templates(value);\\n var html = personTemplate.render(people);\\n $(\\\"#peopleList\\\").html(html);\\n});\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\",\r\n \"title\": \"Registering a named template using markup fetched from the server in a text file\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/resources/templates/person.txt\",\r\n \"label\": \"person.txt\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the second approach:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering templates](#d.templates): The `$.views.templates()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Sample: sub-templates\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"d.templates\": {\r\n \"title\": \"Registering templates: $.templates()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.templates()` is used to register or compile templates. See *[Using templates](#compiletmpl)* for an overview, and simple examples.\\n\\nThis topic provides more details.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Simple scenarios\",\r\n \"text\": \"`$.templates(...)` is powerful and flexible. You can use it for many scenarios, including the following:\\n- Compile a template from a string\\n- Get a template object for a template declared in a script block\\n- Register a template (from either a string or a script block declaration) as a *named template*\\n- Get a template object for a previously registered *named template*\\n- On Node.js: Get a template object for a template declared as a file on the file-system (see *[File-based templates on Node.js](#node/filetmpls)*).\",\r\n \"anchor\": \"$.templates\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(...)\",\r\n \"name\": \"templates\",\r\n \"object\": \"$\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"Compiled template object\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"markupOrSelector\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"A markup string or a selector for a template declaration script block\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var myTemplate = $.templates(myMarkupString);\",\r\n \"description\": \"Compile a template from a string or selector, and return the template object\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered template\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"markupOrSelector\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"A markup string or a selector for a template declaration script block\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(\\\"myTemplateName\\\", myMarkupString);\",\r\n \"description\": \"Register a named template from a string or selector\"\r\n }\r\n ],\r\n \"description\": \"Create one or more compiled templates – optionally registered as named templates\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}}\\\");\\n\\nvar html = myTmpl.render(person);\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}}\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Compile a template from a string\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"anchor\": \"tmpl-string\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\nvar myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar html = myTmpl.render(person);\\n```\"\r\n }\r\n ],\r\n \"title\": \"Get template object for script block template\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\" {{:name}}\\\");\\n\\nvar html = $.render.personTmpl(person);\\n\"\r\n }\r\n ],\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\" {{:name}}\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                    \",\r\n \"height\": \"40\",\r\n \"title\": \"Register named template from a string\",\r\n \"anchor\": \"namedfromstring\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar html = $.render.personTmpl(person);\\n\"\r\n }\r\n ],\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"title\": \"Register named template from script block\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Register multiple templates in one call\",\r\n \"text\": \"You can register multiple named templates in one call to `$.templates()` as follows:\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(namedTemplates)\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTemplates\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"<label>Name:</label>\\\"\\n});\",\r\n \"description\": \"Register multiple named templates\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\n$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"\\\"\\n});\\n\\nvar html = $.render.personTmpl(person);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"\\\"\\n});\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering multiple templates\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Get a template object for a named template\",\r\n \"text\": \"You can get the template object for a previously registered *named template* as follows:\\n\\n```js\\nvar myTemplate = $.templates.myTemplateName; // or $.templates[\\\"myTemplateName\\\"]\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregister a named template\",\r\n \"text\": \"To unregister a previously registered named template, pass `null` to `$.templates()`:\\n\\n```js\\n$.templates(\\\"myTemplateName\\\", null);\\n// Named template \\\"myTemplateName\\\" is no longer registered\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advanced scenarios: Associating private resources with templates\",\r\n \"text\": \"$.templates() can also be used for the following more advanced scenarios:\\n\\n- Compile a template, (or multiple templates) along with specified resources to be available only within that template\\n- Compile one or more templates to be added to the set of private resources of another (already compiled) template\\n\\nYou can use `$.templates()` to compile or register not only a template, but in addition some helpers, converters, custom tags or nested sub-templates, to be made available to the new template as private resources.\\n\\nNote that as an alternative you can register resources (helpers, converters, custom tags or templates) globally, using `$.views.helpers()`, `$.views.converters()`, `$.views.tags()`, or `$.templates()` -- rather than making them private to the template that needs to reference them.\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(...) — associating resources\",\r\n \"name\": \"templates\",\r\n \"object\": \"$\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"templateOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var myTmpl = $.templates({\\n markup: \\\"...\\\",\\n helpers: {...},\\n tags: {...}\\n ...\\n});\",\r\n \"description\": \"Compile a template, along with specified resources to be available only within this template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered template\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"templateOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(\\\"myTmpl\\\", {\\n markup: \\\"...\\\",\\n helpers: {...},\\n tags: {...}\\n ...\\n});\",\r\n \"description\": \"Register a named template, along with specified resources available only within that template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTemplates\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these template(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(namedTemplates, parentTemplate);\",\r\n \"description\": \"Register named templates as private resources for a 'parent template'\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"resources\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A converter and a helper are registered as private resources for the `personTmpl` named template.\\n\\n```js\\n$.templates(\\\"personTmpl\\\", {\\n markup: \\\"#personTemplate\\\",\\n converters: {\\n upper: function(val) {return val.toUpperCase();}\\n },\\n helpers: {\\n append: function(a, b) {return a + b;}\\n }\\n});\\n```\\n\\nThey are accessed within the `personTmpl`\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"// Register a template along with a converter and a helper that it will use.\\n// These resources are private to the template, rather than being registered\\n// globally using $.views.converters or $.views.helpers\\n$.templates(\\\"personTmpl\\\", {\\n markup: \\\"#personTemplate\\\",\\n converters: {\\n upper: function(val) {return val.toUpperCase();}\\n },\\n helpers: {\\n append: function(a, b) {return a + b;}\\n }\\n});\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Register a named template along with specified resources\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding templates as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.templates(...)`. In that way the template you are registering becomes a 'private template resource' for the `parentTemplate`.\\n\\nHere is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"labelTmpl\\\", \\\"\\\", personTmpl);\\n\"\r\n }\r\n ],\r\n \"code\": \"var personTmpl = $.templates(\\\"#personTemplate\\\");\\n\\n$.templates(\\\"labelTmpl\\\", \\\"\\\", personTmpl);\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = personTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"title\": \"Add a \\\"labelTmpl\\\" template resource as a 'sub template' – a private resource for an existing \\\"personTemplate\\\"\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Debug a template by including a debugger; statement\",\r\n \"text\": \"As a technique for debugging compiled templates, you can temporarily set the template option `debug: true`:\\n\\n```js\\n$.templates({\\n myTmpl: {\\n markup: \\\"...\\\",\\n debug: true // This option will add a debugger; statement to the compiled template\\n }\\n});\\n```\\n\\nThe result will be to include a `debugger;` statement at the beginning of the compiled template, which will behave as a breakpoint when debugging, and will facilitate understanding, or stepping through, the compiled template.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"compiletmpl\",\r\n \"label\": \"Using templates\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Sample: sub-templates\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrregister\": {\r\n \"title\": \"Register helpers, converters, tags...\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"converters\",\r\n \"label\": \"$.views.converters()\"\r\n },\r\n {\r\n \"hash\": \"tags\",\r\n \"label\": \"$.views.tags()\"\r\n },\r\n {\r\n \"hash\": \"helpers\",\r\n \"label\": \"$.views.helpers()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tags\": {\r\n \"title\": \"Using custom tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering tags](#tagsapi): The `$.views.tags()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What is a custom tag?\",\r\n \"text\": \"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\\n\\nA tag renders itself as part of the template output. You determine how it renders, generally by specifying either a function as *render()* method or a template, when you declare your custom tag.\\n\\nThe *render()* method, or the *template*, can access both unnamed arguments (*args*) and named parameters (*props*) and , [as in](#tagsyntax@tagparams):\\n\\n```jsr\\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\\n```\\n\\nIn fact it can also access the current data item -- or even the whole hierarchy of views and data...\\n\\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering a custom tag\",\r\n \"text\": \"To register a custom tag, you call [`$.views.tags(...)`](#tagsapi):\\n```js\\n$.views.tags(\\\"mytag\\\", tagOptions)\\n```\\n\\nYou provide a `tagOptions` object, whose properties will typically include a `render: tagRenderFn` (function to be used as *render()* method) and/or a `template: tagTemplate` (template to be rendered -- markup string, selector string or template object).\\n\\nFor the simple case where the *only* option you need to specify is a *render()* method, you can provide the function directly:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagRenderFn);\\n```\\n\\nOr if you *only* want to provide a template markup string, to show how it renders, you can again provide it directly:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagTemplate);\\n```\\n\\nHere is an example of a simple custom tag using just a function:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Render method for the tag\\nfunction renderBoldP(value) {\\n return \\\"

                    \\\" + value + \\\"

                    \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // Provide just a render method\\n```\\n\\nAlternatively we could have written:\\n\\n```js\\n$.views.tags(\\\"boldp\\\", {\\n render: renderBoldP); // Provide just a render method\\n});\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Using the tag\",\r\n \"markup\": \"This is the title:{{boldp title /}}\"\r\n }\r\n ],\r\n \"title\": \"A custom tag using just a render() method\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"// Render method for the tag\\nfunction renderBoldP(value) {\\n return \\\"

                    \\\" + value + \\\"

                    \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // Provide just a render method\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"70\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"render-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the equivalent sample using just a template:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Template markup string for the tag\\nvar tagTemplate = \\\"

                    {{:}}

                    \\\";\\n\\n$.views.tags(\\\"boldp\\\", tagTemplate); // Provide just a template markup string\\n```\\n\\nAlternatively we could have written:\\n\\n```js\\n$.views.tags(\\\"boldp\\\", {\\n template: tagTemplate; // Provide just a template markup string\\n});\\n```\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Using the tag\",\r\n \"markup\": \"This is the title:{{boldp title /}}\"\r\n }\r\n ],\r\n \"code\": \"// Template markup string for the tag\\nvar tagTemplate = \\\"

                    {{:}}

                    \\\";\\n\\n$.views.tags(\\\"boldp\\\", tagTemplate); // Provide just a template markup string\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"title\": \"A custom tag using just a template\",\r\n \"height\": \"70\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"template-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing unnamed arguments, named parameters, data, etc. within the render() method\",\r\n \"text\": \"The `this` pointer within the tag *render()* method is the instance of the tag, and can be used to access parameters, data, view hierarchy, and more. Most of the useful context is provided via `this.tagCtx`. (See [tagCtx object](#tagcontextobject).)\\n\\nIn particular, unnamed arguments can be accessed via `tagCtx.args`, and named parameters via `tagCtx.props`.\\n\\nHere is tag with two arguments and one named parameter:\\n\\n```jsr\\n{{sometag title name mode=\\\"edit\\\"}}\\n```\\n\\nFrom within the *render()* method of `sometag`, you can access `title` and `name` as `this.tagCtx.args[0]` and `this.tagCtx.args[1]`. And you can access mode as `this.tagCtx.props.mode`.\\n\\nIn addition to being accessible as `tagCtx.args`, unnamed arguments are also passed directly as arguments to the *render()* method (if your tag is using one):\\n\\n```js\\nfunction sometagRenderMethod(title, name) {\\n // Here, this.tagCtx.args[1] and the name argument are the same thing\\n}\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Render method for the tag\\nfunction sometagRenderMethod(title, name) {\\n var parentData = this.tagCtx.view.data;\\n\\n return\\n \\\"title: \\\" ... title ... // Get argument passed to render method\\n + \\\"parentData.title: \\\" ... this.tagCtx.view.data.title ... // Get title from parent context\\n\\n + \\\"args[1]: \\\" ... this.tagCtx.args[1] ... // Get argument from args[]\\n + \\\"mode: \\\" ... this.tagCtx.props.mode; // Get named parameter from props\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"// Render method for the tag\\nfunction sometagRenderMethod(title, name) {\\n var parentData = this.tagCtx.view.data;\\n\\n return \\\"title: \\\" + title + \\\"
                    \\\" // Get argument passed to render method\\n + \\\"parentData.title: \\\" + this.tagCtx.view.data.title + \\\"
                    \\\" // Get title from parent context\\n + \\\"args[1]: \\\" + this.tagCtx.args[1] + \\\"
                    \\\" // Get argument from args[]\\n + \\\"mode: \\\" + this.tagCtx.props.mode; + \\\"\\\"// Get named parameter from props\\n}\\n\\n$.views.tags(\\\"sometag\\\", sometagRenderMethod); // Provide just a render method\\n\\nvar team = {\\n title: \\\"theTitle\\\",\\n name: \\\"theName\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"title\": \"Accessing context within the render() method\",\r\n \"action\": \"append\",\r\n \"header\": \"\",\r\n \"anchor\": \"context-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing arguments, named parameters, data, etc. from the tag template\",\r\n \"text\": \"Within the template, the tag instance can be accessed as `~tag`, and so unnamed arguments and named parameters are obtained using `~tagCtx.args[...]` and `~tagCtx.props...`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Template markup for the tag\\nvar sometagTemplate =\\n \\\"title: {{:}}\\\" // The data context within the tag is the first argument, title\\n + \\\"title (#data): {{:#data}}\\\" // Equivalent unabbreviated syntax for current data\\n + \\\"parentData.title: {{:~tagCtx.view.data.title}}\\\" // Get title from parent context\\n\\n + \\\"args[1]: {{:~tagCtx.args[1]}}\\\" // Get argument from args[]\\n + \\\"mode: {{:~tagCtx.props.mode}}\\\"; // Get named parameter from props\\\";\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"// Template markup for the tag\\nvar sometagTemplate =\\n \\\"title: {{:}}
                    \\\" // The data context within the tag is the first argument, title\\n + \\\"title (#data): {{:#data}}
                    \\\" // Equivalent unabbreviated syntax for current data\\n + \\\"parentData.title: {{:~tagCtx.view.data.title}}

                    \\\" // Get title from parent context\\n + \\\"args[1]: {{:~tagCtx.args[1]}}
                    \\\" // Get argument from args[]\\n + \\\"mode: {{:~tagCtx.props.mode}}\\\"; // Get named parameter from props\\n\\n$.views.tags(\\\"sometag\\\", sometagTemplate ); // Provide just a template markup string\\n\\nvar team = {\\n title: \\\"theTitle\\\",\\n name: \\\"theName\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"124\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"title\": \"Accessing context from the tag template\",\r\n \"anchor\": \"tmplcontext-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing and rendering wrapped block content, in a custom tag\",\r\n \"text\": \"A common requirement is to define a custom tag to be used as a block tag, which renders itself by wrapping the rendered block content with other markup.\\n\\nFor example, a `boldp` tag which wraps its content as: `

                    ...

                    `:\\n\\n```jsr\\n{{boldp}}\\n This is inside our block content:
                    \\n {{:title}}\\n{{/boldp}}\\n```\\n\\n**_Block content, using a render() method_**:\\n\\nIn a *render()* method, the block content can be included in the rendered output using:\\n\\n```js\\n... this.tagCtx.render() ...\\n```\\n\\n(For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See [template as fallback sample](#tags@tmpl-fallback) below) \\n\",\r\n \"anchor\": \"wrapping\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag render method:*\\n\\n```js\\nfunction renderBoldP(val) {\\n //To render the block content, we call this.tagCtx.render()\\n return \\\"

                    \\\" + this.tagCtx.render() + \\\"

                    \\\";\\n}\\n```\\n\\n*Using the tag:*\\n\\n```jsr\\nThis is outside our block content: ...\\n{{boldp}}\\n This is inside our block content: ...\\n {{:title}}\\n{{/boldp}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Rendering block content from a custom tag render() method\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"function renderBoldP(val) {\\n return \\\"

                    \\\" + this.tagCtx.render() + \\\"

                    \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // User renderBoldP() as render method\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"renderblock-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"When using `tagCtx.render()` without arguments, the data context within the block content is the same as the data context outside our custom tag. However by passing an argument to `tagCtx.render(myData)` the inner data context can be moved to the chosen data. \\n\\nThe following sample shows a custom `{{runningTotal}}` tag which renders an array of `lineItems` (with a column for each property), and provides a running total of one of the columns.\\n\\nIt uses a *render()* method to access tag arguments and named parameters, and iterate over the `lineItems` array. It renders a row for each `lineItem`, using the code:\\n\\n```js\\nret += this.tagCtx.render(lineItem, {total: totalVal});\\n```\\n\\nHere, the row is rendered using the block content as template -- with the `lineItem` passed in as data context. The running total `totalVal` is provided as contextual helper: `~total`.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"You call the custom `{{runningTotal}}` tag like this:\\n\\n```jsr\\n{{runningTotal lineItems totalColumn=\\\"quantity\\\"}}\\n ...{{:quantity}}\\n ...{{:~total}}\\n{{/runningTotal}}\\n```\\n\\nAnd the *render()* method code accesses context (`this.tagCtx`) to get at the arguments and named parameters... :\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", function renderLineItems(array) {\\n ...\\n totalVal = 0; // Initialize ~total to 0 before rendering\\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\\n for (var i = 0; i < array.length; i++) {\\n lineItem = array[i];\\n totalVal += lineItem[totalCol]; // Compute running total\\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content as\\n // template. Pass lineItem as data and totalVal as helper: ~total\\n }\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"function renderLineItems(array) {\\n var lineItem,\\n ret = \\\"\\\",\\n totalVal = 0, // Initialize ~total to 0 before rendering\\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\\n for (var i = 0; i < array.length; i++) { // Iterate over array and render a row for each lineItem \\n lineItem = array[i];\\n totalVal += lineItem[totalCol]; // Compute running total\\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content\\n // as template, and passing lineItem as current data and totalVal as helper: ~total\\n }\\n return ret;\\n}\\n\\n$.views.tags(\\\"runningTotal\\\", renderLineItems); // Use renderLineItems() as render method\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ]\\n};\\nvar html = $(\\\"#myTmpl\\\").render(data);\\n\\n$(\\\"#lineItems\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"152\",\r\n \"title\": \"A {{runningTotal}} custom tag, using a render() method \",\r\n \"anchor\": \"runningtotal-sample\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"**_Block content, using a template_**:\\n\\nTo render block content declaratively within a custom tag template, use:\\n\\n```jsr\\n{{include tmpl=#content/}}\\n```\\n\\nor equivalently:\\n\\n```jsr\\n{{include tmpl=~tagCtx.content/}}\\n```\\n\\nHere is a modified [`{{boldp}}`](#tags@renderblock-sample) sample using a custom template instead of a *render()* method.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"To render block content, we use `{{include tmpl=#content/}}`\\n\\n```js\\ntemplate: \\\"

                    {{include tmpl=#content/}}

                    \\\"\\n```\\n\\n(The syntax `#content` is an example of a `view path` -- equivalent to `#view.content`.)\\n\\nThe `content` property on the `view` object is a compiled template for the block content, which is also available as the `content` property on the `tagCtx`.\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"boldp\\\", {\\n template: \\\"

                    {{include tmpl=#content/}}

                    \\\"\\n});\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"title\": \"Rendering block content from a custom tag template\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"tmplblock-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here, the default data context within the block content is the same as the data context outside our custom tag (as was the case in the [previous](#tags@renderblock-sample) `{{boldp}}` sample). However by providing an argument to the `{{include...}}`, as in `{{include myData tmpl=#content/}}`, the inner data context can be moved to the chosen data.\\n\\n(Note: To be precise, the default data in the two samples is different. When using `tagCtx.render()` the outer context is *outside our `{{boldp}}` tag*. Whereas when using `{{include}}`, it is *outside the `{{include}}` and within the `{{boldp}}` template*. If we provide an argument to the tag: '{{mytag someArgument}}...' then in custom tag template approach the passed-in argument value will be used as default data context.)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"For further details and examples of custom tags which wrap content, see [*Rendering wrapped block content*](#tagsapi@wrapping)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags using both a render() method and a template\",\r\n \"text\": \"If there is both a *template* and a *render()* method, then the *template* will only be used if the *render()* method returns *undefined*.\\n\\nLet's take our `{{runningTotal}}` example using a *render()* method, but provide a *template* which will be used as \\\"fallback\\\" rendering for the tag in the case when there are no items to render in the chosen range. We will also provide support for limiting the range of line items by setting `start=... end=...`:\",\r\n \"anchor\": \"tmpl-fallback\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"First, in the *render()* method, we will change the original code to test whether the item exists in the array, before rendering the block content.\\n\\nSecondly, we will make sure that when there is an item we do render the block content and not the template. So we call `this.tagCtx.content.render(...)`, rather than `this.tagCtx.render(...)`.\\n\\nThat's because `this.tagCtx.render(...)` will actually look to see if there is template associated with the tag, (either a template on the tag definition, or a `tmpl` property on the tag) -- in which case it will render that template and not the block content... \\n\\n```js\\nfor (var i=start; iNo line items\\\"\\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.tags(\\\"runningTotal\\\", {\\n render: function(array) {\\n var lineItem,\\n ret = \\\"\\\",\\n totalVal = 0, // Initialize ~total to 0 before rendering\\n props = this.tagCtx.props,\\n totalCol = props.totalColumn; // The column/property to use for running total\\n start = props.start,\\n end = props.end;\\n for (var i=start; iNo line items\\\" // Template for fallback if no line items\\n});\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ],\\n lineItems2: []\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(data, {\\n category: function(item, index, items) {\\n return item.category === this.props.category;\\n }\\n});\\n\\n$(\\\"#purchases\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"height\": \"244\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"\",\r\n \"anchor\": \"renderplustmpl-sample\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"url\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In the above sample our feature for limiting the range of items by setting `start=... end=...` is basically identical to the corresponding feature available natively on the [`{{for}}`](#fortag@sortfilterrange) tag:\\n\\n```jsr\\n{{for start=... end=...}}\\n```\\n\\nIn fact we can add this feature to our `{{runningTotal}}` tag for free (along with providing sorting, filtering etc.) by making `{{runningTotal}}` derive from `{{for}}`, as `baseTag`. This will also simplify our code considerably. See [*Specifying tag inheritance*](#tagsapi@basetag) for details and an [updated](#tagsapi@derivedfor) `{{runningTotal}}` sample.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags and 'tag controls'\",\r\n \"text\": \"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering tags](#tagsapi): The `$.views.tags()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls\",\r\n \"label\": \"Samples: JsViews tag controls\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvtagcontrols\",\r\n \"label\": \"JsViews tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrobjects\": {\r\n \"title\": \"JsRender objects\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"viewsobject\",\r\n \"label\": \"$.views object\"\r\n },\r\n {\r\n \"hash\": \"templateobject\",\r\n \"label\": \"template object\"\r\n },\r\n {\r\n \"hash\": \"viewobject\",\r\n \"label\": \"view object\"\r\n },\r\n {\r\n \"hash\": \"tagobject\",\r\n \"label\": \"tag object\"\r\n },\r\n {\r\n \"hash\": \"viewcontextobject\",\r\n \"label\": \"view context object\"\r\n },\r\n {\r\n \"hash\": \"tagcontextobject\",\r\n \"label\": \"tag context object\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"viewsobject\": {\r\n \"title\": \"The $.views object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `$.views` object provides access to APIs for creating templates, tags, helpers etc.

                    \\n\\n\\n- `$.views.templates(...)` -- available also as `$.templates(...)`\\n
                    Used for defining templates -- see: [Registering templates](#d.templates)\\n- `$.views.tags(...)`\\n
                    Used for defining custom tags -- see: [Registering custom tags](#tagsapi)\\n- `$.views.converters(...)`\\n
                    Used for defining converters -- see: [Registering converters](#convertersapi)\\n- `$.views.helpers(...)`\\n
                    Used for defining helpers -- see: [Registering helpers](#helpersapi)\\n- `$.views.viewModels(...)`\\n
                    Used for defining View Models -- see: [Compiled View Models](#viewmodelsapi)\\n\\nIt also provides access to:

                    \\n- `$.views.settings`\\n
                    Used for modifying JsViews settings and options -- see: [Settings](#jsvsettings)\\n- `$.views.map(...)`\\n
                    Used for defining custom maps (advanced) \\n- `$.views.jsviews`\\n
                    Provides the version number of the currently loaded JsViews or JsRender library\\n\\n\"\r\n }\r\n ]\r\n },\r\n \"settingsobject\": {\r\n \"title\": \"$.views.settings object\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"subobject\": {\r\n \"title\": \"$.views.sub object\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"templateobject\": {\r\n \"title\": \"The template object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The [`$.templates()`](#d.templates) API can be used to obtain a compiled template object:\\n\\n```js\\nvar myTmpl = $.templates(\\\" {{:name}}\\\");\\n```\\n\\nThe compiled template object (`myTmpl`, in the example) provides a number of properties and methods, in particular:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The render() method\",\r\n \"text\": \"```js\\nvar html = myTmpl.render(person);\\n```\\n\\nSee [Render a template against data objects or arrays](#tmplrender)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The markup property\",\r\n \"text\": \"The declarative markup string for the template (available whether the template was registered by providing a markup string, or by a script block reference).\\n\\n```js\\nvar test = myTmpl.markup; // \\\" {{:name}}\\\"\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The compiled template object is actually a render() function\",\r\n \"text\": \"The compiled template *is itself a function*, corresponding to its own render method, so the following two examples are actually equivalent.\\n\\n*Calling the render method:*\\n\\n```js\\nvar html = myTmpl.render(person);\\n```\\n\\n*Invoking the compiled template directly as render method:*\\n\\n```js\\nvar html = myTmpl(person);\\n```\"\r\n }\r\n ]\r\n },\r\n \"viewobject\": {\r\n \"title\": \"The view object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates render as a [*view hierarchy*](#views).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"A view object has the following properties and methods:\",\r\n \"text\": \"- [type property](#viewobject@type)\\n- [data property](#viewobject@data)\\n- [parent property](#viewobject@parent)\\n- [index property](#viewobject@index)\\n- [getIndex() method](#viewobject@getindex)\\n- [get(type) method](#viewobject@get)\\n- [content property](#viewobject@content)\\n- [root property](#viewobject@root)\\n- [other properties (tmpl, views, ctx, tag)](#viewobject@other)\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `view` objects have additional methods:*\\n- *[refresh()](#jsvviewobject@refresh)*\\n- *[contents()](#jsvviewobject@contents)*\\n- *[childTags()](#jsvviewobject@childtags)*\\n- *[nodes()](#jsvviewobject@nodes)*\\n\\n*See [JsViews `view` object](#jsvviewobject).*\\n\\n\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing view objects\",\r\n \"text\": \"The properties of the current view are accessed *declaratively* in a template using *[view paths](#paths)* -- such as `#parent` for the `view.parent` property.\\n\\nAccessing `view` objects *programmatically* is less common in JsRender, but can be useful for example:\\n\\n- in a helper function, `~myHelper()`, where the `this` pointer is the current view\\n- in the render() method of a custom tag -- using `this.tagCtx.view`\\n\\n*Note:* In JsViews, accessing `view` objects programmatically is very common, thanks to the [`$.view()`](#jsv.d.view) method. For example in a click handler, `$.view(this);` returns the corresponding `view` object.

                    \\n\\n\\n### Properties and methods:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The type property:\",\r\n \"text\": \"***view.type**: string corresponding to the type of view:*\\n\\n- `\\\"data\\\"` -- for the top-level view from a `render()` call\\n- `\\\"array\\\"` or `\\\"item\\\"` -- from `{{for array}}` or `{{props object}}` (see *[array and item views](#views@itemview)*)\\n- `\\\"sometag\\\"` -- for the view from `{{sometag}}...{{sometag}}` -- for example: `\\\"include\\\"`, `\\\"if\\\"`, `\\\"for\\\"`, `\\\"props\\\"`, `\\\"mytag\\\"`...\\n\",\r\n \"anchor\": \"type\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The data property:\",\r\n \"text\": \"***view.data**: the current data context for the view* -- as in:\\n\\n```js\\nvar team = view.data.team; // The team property of the current data object\\n```\\n\\n`view.data` can be accessed declaratively in templates as `#data`-- as in:\\n\\n```jsr\\n{{:#data}}\\n{{>#data.description()}}\\n{{for #data.team.members}}...\\n```\\n\\nBut note that since `#data`, the current data context, is the starting point for *[data paths](#paths)* within templates, the above expressions with `#data' can be abbreviated to:\\n\\n```jsr\\n{{:}}\\n{{>description()}}\\n{{for team.members}} etc.\\n```\\n\\n \",\r\n \"anchor\": \"data\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parent property:\",\r\n \"text\": \"***view.parent**: the parent view* (used to step up through views in the hierarchy).\\n\\n```js\\nvar index = view.parent.index; // The index of the parent view\\n```\\n\\nAccessed declaratively as `#parent`:\\n\\n```jsr\\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\\n```\\n\\n(See also *[Accessing parent data](#parentdata)*)\",\r\n \"anchor\": \"parent\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The index property:\",\r\n \"text\": \"***view.index**: the view index* (only available on [item views](#views@itemview)).\\n\\n```js\\nvar index = view.index; // The index of the view (for \\\"item\\\" views - otherwise an 'error string')\\n```\\n\\nAccessed declaratively as `#index`:\\n\\n```jsr\\n{{if #index > 2}} {{!-- we are in an \\\"item\\\" view --}}\\n {{:#parent.index}}... {{!-- \\\"item\\\" view index (- the parent - since we are inside the 'ifView') --}}\\n{{/if}}\\n```\\n\\n**Note:** On non-\\\"item\\\" views, accessing the index property returns the error message prompt: *\\\"For #index in nested block use #getIndex().\\\"*\",\r\n \"anchor\": \"index\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The getIndex() method:\",\r\n \"text\": \"***view.getIndex()**: get the index of current \\\"item\\\" view* (steps up to nearest [item view](#views@itemview), and returns the index).\\n\\n```js\\nvar index = view.getIndex(); // The index of the view\\n```\\n\\nAccessed declaratively as `#getIndex()`:\\n\\n```jsr\\n{{for teams}}\\n {{for members}}\\n {{if #getIndex() > 0}} {{!-- index of member (- this view is an \\\"item\\\" view for member) --}}\\n {{:#getIndex()}} {{!-- index of member --}}\\n {{/if}}\\n\\n {{:#parent.getIndex()}}... {{!-- index of team (-nearest \\\"item\\\" view of parent is team \\\"item\\\" view) --}}\\n {{/for}}\\n{{/for}}\\n```\\n\",\r\n \"anchor\": \"getindex\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If index is a multiple of 3, render new tr, and format index in bold.\\n\\nUse `getIndex()` to get *item* index from within *if* block.\\n\\n```jsr\\n\\n\\n{{for members}}\\n {{if #index===0}}\\n \\n{{/for}}\\n\\n
                    1:\\n {{else #index%3===0}}\\n
                    {{:#getIndex()+1}}:\\n {{else}}\\n {{:#getIndex()+1}}:\\n {{/if}}\\n {{:name}}\\n
                    \\n```\"\r\n }\r\n ],\r\n \"markup\": \"\\n\\n{{for members}}\\n {{if #index===0}}\\n \\n{{/for}}\\n\\n
                    1:\\n {{else #index%3===0}}\\n
                    {{:#getIndex()+1}}:\\n {{else}}\\n {{:#getIndex()+1}}:\\n {{/if}}\\n {{:name}}\\n
                    \",\r\n \"data\": {\r\n \"title\": \"The A Team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Jeff\"\r\n },\r\n {\r\n \"name\": \"Jack\"\r\n },\r\n {\r\n \"name\": \"Jim\"\r\n },\r\n {\r\n \"name\": \"Jo\"\r\n },\r\n {\r\n \"name\": \"Joanna\"\r\n },\r\n {\r\n \"name\": \"James\"\r\n }\r\n ]\r\n },\r\n \"title\": \"getIndex() – iterating + grouping by 3\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"80\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The get(type) method:\",\r\n \"text\": \"***view.get(type)**: returns the nearest parent view of type `type`.*\\n\\n```js\\nvar arrayView = view.get(\\\"array\\\"); // Step through parents to nearest \\\"array\\\" view\\nvar arrayLength = arrayView.data.length; // Get length of data array\\n```\\n\\nAccessed declaratively as `#get(...)`:\\n\\n```jsr\\n{{for members}}\\n {{if #index+1 === #get(\\\"array\\\").data.length}}\\n The last member in the list\\n {{/if}}\\n{{/for}}\\n```\\n\\n**Note:** An additional signature is available: ***view.get(true, type)*** (for advanced scenarios) -- which steps *down* through descendant views (depth first traversal) and returns *the first descendant view of type `type`*.\\n\\n```jsr\\n{{for members}}\\n {{:name}}\\n{{/for}}\\n{{:#get(true, \\\"item\\\").data.name}} {{!-- get the name of the first member --}}\\n```\\n\\nIn using this API it is sometimes necessary to be aware of the processing order. For example in the sample code above, placing `{{:#get(true, \\\"item\\\")...}}` before `{{for members}}` will not return any \\\"item\\\" view, since the `{{:get(...)...}}` is being evaluated during the rendering, and the \\\"item\\\" views for `{{for ...}}` will not yet have been rendered. (View instantiation is part of rendering, which is a single-pass process.) \\n\\n\",\r\n \"anchor\": \"get\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The content property (for views which wrap inline block content):\",\r\n \"text\": \"***view.content**: template corresponding to the inline block content.*\\n\\nAccessed declaratively as `#content`:\\n\\nIn the [wrapping content](#tagsyntax@wrap) scenarios, the tag:\\n\\n```jsr\\n{{sometag ... tmpl=\\\"externalTmpl\\\"}}...{{/sometag}}\\n```\\n\\nor\\n\\n```jsr\\n{{mytag}}...{{/mytag}}\\n```\\n\\nwill render with a view which has both a `view.tmpl` template property and a `view.content` template property.\\n\\nThe `view.content` template corresponds to the inline block content, and is used for wrapping that content as in:\\n\\n```jsr\\nbefore {{include tmpl=#content /}} after\\n```\\n\",\r\n \"anchor\": \"content\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*mytag:* \\n\\n```js\\n$.views.tags(\\n \\\"mytag\\\",\\n \\\"startTag {{include tmpl=#content /}} endTag\\\"\\n);\\n```\\n\\n*externalTmpl:* \\n\\n```js\\n$.templates(\\n \\\"externalTmpl\\\",\\n \\\"startTmpl {{include tmpl=#content /}} endTmpl\\\"\\n);\\n```\\n\\n*Template:* \\n\\n```jsr\\n{{mytag}}\\n
                    inside mytag
                    \\n{{/mytag}}\\n\\n
                    \\n\\n{{mytag tmpl=\\\"externalTmpl\\\"}}\\n
                    inside mytag with external tmpl
                    \\n{{/mytag}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"code\": \"$.views.tags(\\n \\\"mytag\\\",\\n \\\"startTag {{include tmpl=#content /}} endTag\\\"\\n);\\n\\n$.templates(\\n \\\"externalTmpl\\\",\\n \\\"
                    startTmpl {{include tmpl=#content /}} endTmpl
                    \\\"\\n);\\n\\n$(\\\"#result\\\").html(\\n $.templates(\\\"#myTmpl\\\").render()\\n);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"view.content – wrapping content\",\r\n \"height\": \"170\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The root property:\",\r\n \"text\": \"***view.root**: the root view (top-level ancestor view for this view)* -- as in:\\n\\n```js\\nvar topLevelData = view.root.data; // Get the top-level data (obtained from the root view)\\n```\",\r\n \"anchor\": \"root\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Other view object properties:\",\r\n \"text\": \"The following additional properties of the `view` object are used by JsRender for processing templates:\\n\\n- *tmpl*: the template used to render the view\\n- *views*: the child views in the view hierarchy\\n- *ctx*: object (hash) with the named contextual helpers/template parameters for this view\\n- *tag*: the `\\\"mytag\\\"` view rendered by a custom tag `{{mytag ...}}`, has a `view.tag` property -- the instance of the `mytag` tag object.\",\r\n \"anchor\": \"other\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvviewobject\",\r\n \"label\": \"JsViews view object\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tagobject\": {\r\n \"title\": \"The tag object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag object properties and event handlers provided as tag options\",\r\n \"text\": \"The following tag properties and event handlers can be specified as tag options in the [`$.views.tags()`](#tagsapi) call, when registering a custom tag:\\n\\n*Tag properties*\\n\\n- [`baseTag`](#tagsapi@basetag)\\n- [`flow`](#tagsapi@flow)\\n- [`template`](#tagsapi@template)\\n- [`bindTo`](#tagsapi@bindto)\\n- [`ctx`](#tagsapi@ctx)\\n- [`contentCtx`](#tagsapi@contentctx)\\n- [`argDefault`](#tagsapi@argdefault)\\n\\n*Event handlers*:\\n\\n- [`init()`](#tagsapi@init)\\n- [`render()`](#tagsapi@render)\\n- [`convert()`](#tagsapi@convert)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Additional properties and methods on the tag object\",\r\n \"text\": \"In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\\n\\n*Tag properties*\\n\\n- [parent](#tagobject@parent)\\n- [parents](#tagobject@parents)\\n- [tagCtx](#tagobject@tagctx)\\n- [tagCtxs](#tagobject@tagctxs)\\n- [tagName](#tagobject@tagname)\\n- [rendering](#tagobject@rendering)\\n\\n*Tag methods*\\n\\n- [ctxPrm()](#tagobject@ctxprm)\\n- [cvt()](#tagobject@cvt)\\n- [cvtArgs()](#tagobject@cvtargs)\\n- [bndArgs()](#tagobject@bndargs)\\n- [base()](#tagobject@base)\\n- [baseApply()](#tagobject@baseapply)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing tag objects\",\r\n \"text\": \"The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\\n\\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\\n\\n```jsr\\n{{:~tag.parent.tagName}}`\\n```\\n\\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\\n\\n```jsr\\n{{:~tagCtx.props.mode}}`\\n```\\n\\n### Tag properties and methods:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parent property\",\r\n \"text\": \"***tag.parent**: the parent tag* (used to step up through views in the hierarchy).\\n\\n```js\\nvar index = view.parent.index; // The index of the parent view\\n```\\n\\nAccessed declaratively as `#parent`:\\n\\n```jsr\\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\\n```\\n\\n(See also *[Accessing parent data](#parentdata)*)\",\r\n \"anchor\": \"parent\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parents property\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"parents\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagCtx property\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"tagctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagCtxs property\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"tagctxs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagName property\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"tagname\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The rendering property\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"rendering\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The ctxPrm() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"ctxprm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The cvt() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"cvt\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The cvtArgs() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"cvtargs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The bndArgs() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"bndargs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The base() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"base\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The baseApply() method\",\r\n \"text\": \"Additional detailed documentation to follow...\",\r\n \"anchor\": \"baseapply\"\r\n }\r\n ]\r\n },\r\n \"viewcontextobject\": {\r\n \"title\": \"The view context object\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"tagcontextobject\": {\r\n \"title\": \"The tag context object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"- render function(data, context, noIteration, parentView, key, onRender) {\\n- tmpl\\tfunction() {\\n- args\\t[]\\tObject, (Array)\\n- ctx\\t{...}\\tObject\\n- index\\t0\\tNumber\\n- params\\t{...}\\tObject\\n- props\\t{...}\\tObject\\n- tag\\t{...}\\tObject, (Tag)\\n- view\\t{...}\\tObject\\n \\nAdditional detailed documentation to follow…\\n\"\r\n }\r\n ]\r\n },\r\n \"node/browserify\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Browserify support for JsRender and JsViews\\n\\n[Browserify](http://browserify.org/) lets you create modular JavaScript projects for the browser, using the npm `require()` pattern for packages/modules.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender as a Browserify module\",\r\n \"text\": \"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the Browserify client script bundle, and loaded in the browser.\\n\\nThere are three options for loading JsRender in the browser as a Browserify module:\\n\\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the Browserify client script bundle:\\n ```js\\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\\n ```\\n- Load both jQuery and JsRender as modules in the Browserify client script bundle:\\n ```js\\n var $ = require('jquery'); // Load jQuery as a module\\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\n ```\\n- Load JsRender as a module in the Browserify client script bundle, without loading jQuery at all:\\n ```js\\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\\n ```\\n\\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \\n\\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \\n\\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\\n\",\r\n \"anchor\": \"jsrender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded globally:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n \\n\\n
                    \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded as module:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                    \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar $ = require('jquery'); // Load jQuery as a module\\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – JsRender without jQuery:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                    \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\\nvar tmpl = jsrender.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\ndocument.querySelector('#container').innerHTML = html;\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsViews as a Browserify module\",\r\n \"text\": \"JsViews can also be included in the Browserify client-script bundle, and loaded in the browser.\\n\\nAfter installing on the server (using `$ npm install jsviews`), call:\\n\\n```js\\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\\n```\\n\\nor -- if also loading jQuery as a Browserify module, use:\\n\\n```js\\nvar $ = require('jquery');\\n...\\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as a parameter)\\n```\",\r\n \"anchor\": \"jsviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Loading templates as Browserify modules\",\r\n \"text\": \"JsRender includes a Browserify transform: `jsrender/tmplify` (see [below](#node/browserify@clientbundle)) which allows you also to include your server [file-based templates](#node/filetmpls) in the client-script bundle generated by Browserify. \\n\\nYou can then access the compiled templates in the browser, as modules.\\n\\nThe exact syntax depends on whether jQuery is loaded globally, loaded as a Browserify module, or not loaded at all.\\n\\n- If jQuery is loaded globally then use:\\n ```js\\n var tmpl = require('./templates/myTemplate.html'); // Load template (jQuery \\n // is loaded globally)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n- If jQuery is loaded as a module, use:\\n ```js\\n var $ = require('jquery');\\n ...\\n var tmpl = require('./templates/myTemplate.html')($); // Load template (local\\n // jQuery as parameter)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n- If loading JsRender as a module, without jQuery, use:\\n ```js\\n var jsrender = require('jsrender')(); // function call -- no parameter\\n ...\\n var tmpl = require('./templates/myTemplate.html')(jsrender); // Load template (jsrender\\n // namespace as parameter)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n\\n**Note on relative paths:** The `./...` paths used to identify bundled templates are always interpreted as relative paths *relative to the location of your calling script*, which in this case is the Browserify script that created the client bundle. (Note that declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Nested templates\",\r\n \"text\": \"Template inclusion in the bundle can be recursive, so for example if you call `require(\\\"./templates/myTemplate.html\\\");` and *myTemplate.html* includes a nested reference to another template, such as `{{include tmpl=\\\"./another/tmpl2.html\\\"/}}`, then the client-script bundle will include that template too.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Generating the client bundle\",\r\n \"text\": \"If *source.js* includes template references such as: `var tmpl=require('./some/path/myTemplate.html')`, then Browserify generates a client script bundle which will include the referenced templates.\\n\\n[Browserify](http://browserify.org/) provides three different ways of generating a *bundle.js* script from a *source.js* script, and calling a transform:\\n\\n**Command line:**\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\n**package.json:**\\n\\n```bash\\n\\\"browserify\\\": {\\n \\\"transform\\\": [\\n [\\\"jsrender/tmplify\\\"]\\n ]\\n}\\n```\\n\\n**API:**\\n\\n```bash\\nbrowserify('./source.js')\\n .transform(require('jsrender/tmplify'))\\n .bundle()\\n .pipe(fs.createWriteStream('./bundle.js'));\\n```\",\r\n \"anchor\": \"clientbundle\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Option: extensions\",\r\n \"text\": \"The `jsrender/tmplify` Browserify transform uses a white-space-separated list of extensions: `\\\"html jsrender jsr\\\"`, by default. This means that when you generate a client-script bundle using the `tmplify` transform, it will treat any `.html`, `.jsrender` or `.jsr` file as a template, and will include the compiled template in the client-script bundle for rendering in the browser. \\n\\nYou can instead specify a different list of file extensions for templates, by using the `--extensions` or `-e` option, as in the following examples:\\n\\n```bash \\nbrowserify -t [jsrender/tmplify --extensions 'htm jsrender'] ./source.js > ./bundle.js\\n```\\n\\n```bash \\nbrowserify -t [jsrender/tmplify -e 'htm jsrender'] ./source.js > ./bundle.js\\n```\\n\\n```bash \\n\\\"browserify\\\": {\\n \\\"transform\\\": [\\n [\\\"jsrender/tmplify\\\", {\\n \\\"extensions\\\": \\\"htm jsrender\\\"\\n }]\\n ]\\n}\\n```\\n\\n```bash \\nbrowserify('./source.js')\\n .transform(require('jsrender/tmplify'), {extensions: 'htm jsrender'})\\n .bundle()\\n .pipe(fs.createWriteStream('./bundle.js'));\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Including jQuery and/or JsRender/JsViews in the client-script bundle\",\r\n \"text\": \"When using Browserify with JsRender on Node.js, you will generally need jQuery and JsRender/JsViews in the client, to render (and optionally data-link) the templates.\\n\\njQuery, JsRender and JsViews are all available as npm/Browserify modules, so you can choose whether to load them globally, using a script block, or as a module. Here are three examples following alternative strategies:\\n\\n**Load jQuery and JsRender/JsViews globally**\\n\\n`$` is defined as a global variable (`window.$`, or `window.jQuery`).
                    \\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n\\n\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nvar myTmpl = require('./templates/myTemplate.html'); // Include compiled template in client-script bundle\\nvar html = myTmpl(data); // Render using compiled template\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\nSee the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project for complete examples:\\n- [clientcode-hello.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-hello.js) and [layout-hello.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello.html) using JsRender\\n- [clientcode-movies.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-movies.js) and [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) using JsViews.\\n \\n**Load jQuery and JsRender/JsViews as Browserify modules**\\n\\nUse `var $ = require('jquery')` to load jQuery, and `require('jsrender')($)` or `require('jsviews')($)` to load JsRender/JsViews.
                    \\nUse `require(templatePath)($)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nvar $ = require('jquery');\\nrequire('jsrender')($);\\nvar myTmpl = require('./templates/myTemplate.html')($)\\nvar html = myTmpl(data);\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\nSee:\\n- [clientcode-hello-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify.js) and [layout-hello-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify.html) for an example loading jQuery and JsRender as modules\\n- [clientcode-hello-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-hello-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading JsRender as a module (without jQuery)\\n- [clientcode-movies-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-movies-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading jQuery and JsViews as modules\\n\\n**Mixed approach: Load jQuery globally, and JsRender/JsViews as a Browserify module**\\n\\n`$` is defined as a global variable (`window.$` or `window.jQuery`).
                    \\nUse `require('jsrender')` or `require('jsviews')` to load JsRender/JsViews.
                    \\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nrequire('jsrender');\\nvar myTmpl = require('./templates/myTemplate.html');\\nvar html = myTmpl(data);\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\nSee [clientcode-movies-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-movies-browserify.js) and [layout-movies-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies-browserify.html) for an example using JsViews.\",\r\n \"anchor\": \"clientscript\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sample code\",\r\n \"text\": \"For running code examples using JsRender, Browserify, and the `tmplify` transform, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also:\",\r\n \"text\": \"*[Webpack support](#node/webpack)*\"\r\n }\r\n ]\r\n },\r\n \"node/renderfile\": {\r\n \"title\": \"renderFile() method\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender on Node.js provides a shortcut `renderFile` method, for convenience, to compile and render in one step:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n// result: Name: Jim
                    \\n```\\n\"\r\n }\r\n ]\r\n },\r\n \"node/filetmpls\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## File-based templates\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining templates as .html files\",\r\n \"text\": \"On Node.js, JsRender templates can be stored directly in the file system (e.g. as `.html`, `.jsr.` or `.jsrender` files) -- for example:\\n\\n**Template:** *./templates/myTemplate.html* -- with contents:\\n\\n```jsr\\nName: {{:name}}
                    \\n```\\n\\n**Code:** JsRender recognizes file paths (for valid relative file paths starting with `'./'`), so you can write:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar tmpl = jsrender.templates('./templates/myTemplate.html'); // Compile the template\\n\\nvar html = tmpl({name: \\\"Jim\\\"}); // Render\\n// result: Name: Jim
                    \\n```\\n\\n**Note:** The `./...` paths are always interpreted as relative paths *relative to the location of your calling script*. Declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"renderFile() method\",\r\n \"text\": \"JsRender on Node.js provides a shortcut `renderFile()` method, for convenience, to compile and render in one step:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n// result: Name: Jim
                    \\n```\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"jsrender.renderFile(filepath, data)\",\r\n \"name\": \"renderFile\",\r\n \"object\": \"jsrender\",\r\n \"method\": true,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"filepath\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Relative path to template file - starting with './'\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var jsr = require('jsrender');\\nvar html = jsr.renderFile('./.../tmpl.html', data);\",\r\n \"description\": \"Load file-based template, compile and render against data\"\r\n }\r\n ],\r\n \"description\": \"Shortcut method – compile and render\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Nested calls to file-based templates (composition)\",\r\n \"text\": \"JsRender's awareness of Node.js file paths (relative paths starting with `'./'`) means your templates can include recursive calls to other templates (partials). You don't need to register or compile those templates separately. (See also: [template composition](#tagsyntax@composition)).\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\nName: {{:name}}
                    Address: {{include tmpl='./templates/other/addressTemplate.jsr'}}\\n```\\n\\n**Template:** *./templates/other/addressTemplate.jsr*:\\n```jsr\\nStreet: {{:street}}\\n```\\n\\n**Code:** Compile and render, recursively:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar tmpl = jsrender.templates('./templates/personTemplate.html');\\n// Compile template - and also any recursively called templates\\n\\nvar html = tmpl({name: \\\"Jim\\\", street: \\\"Main St\\\"});\\n// result: Name: Jim
                    Address: Main St\\n```\",\r\n \"anchor\": \"composition\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Register a file-based template by name – and render it\",\r\n \"text\": \"For convenience you can register file-based templates by name, just as you can for [templates from strings](#d.templates@namedfromstring).\\n\\n```js\\n// Register named template - \\\"myTmpl1\\n$.templates(\\\"myTmpl1\\\", \\\"./templates/myTemplate.html\\\");\\n\\n// Render named template\\nvar html = $.templates.myTmpl1(person);\\n\\n// Alternative syntax: var html = $.render.myTmpl1(person);\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Automatic caching of file-based templates\",\r\n \"text\": \"The first time `jsrender.templates('./templates/myTemplate.html')` is called, JsRender will:\\n\\n - load the template file from the file system\\n - compile the template\\n - cache the template\\n - return the compiled template\\n\\nThe cached template can be accessed directly as `jsrender.templates['./templates/myTemplate.html']` - and can also be deleted by calling `delete jsrender.templates['./templates/myTemplate.html']`, or `jsrender.templates('./templates/myTemplate.html', null)`\\n\\nOn subsequent calls, JsRender will simply:\\n - return the compiled template\\n\\nThe caching means you can load and compile the template during server initialization, and avoid the cost of reading the file or compiling during HTTP requests:\\n\\n```js\\njsrender.templates('./templates/myTemplate.html'); // Cache the compiled template\\n\\napp.get('/...', function(req, res) {\\n res.render('myTemplate', {name: \\\"Jim\\\"}); // Render previously cached template, using Express\\n});\\n```\\n\\nSimilarly when using the alternative forms for rendering templates:\\n\\n```js\\napp.get('/...', function(req, res) {\\n var tmpl = jsrender.templates('./templates/myTemplate.html'); // Get previously cached template\\n var html = tmpl.render({name: \\\"Jim\\\"});\\n res.send(html);\\n});\\n```\\n\\nor \\n\\n```js\\napp.get('/...', function(req, res) {\\n // Render previously cached template\\n var html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n res.send(html);\\n});\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the same template on the server and in the browser\",\r\n \"text\": \"JsRender lets you easily use the same templates for both server and browser rendering. See *[server/browser templates](#node/server-browser)* for details on two alternative approaches, one with the `{{clientTemplate}}` tag, and the other using *Browserify*.\"\r\n }\r\n ]\r\n },\r\n \"jsrnode\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Quickstart\",\r\n \"text\": \"See the [JsRender Node.js Quickstart](#jsr-node-quickstart) for an overview of JsRender support in Node.js\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Detail topics:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"node/install\",\r\n \"label\": \"Installation and usage\"\r\n },\r\n {\r\n \"hash\": \"node/filetmpls\",\r\n \"label\": \"File-based templates\"\r\n },\r\n {\r\n \"hash\": \"node/express-hapi\",\r\n \"label\": \"Express and Hapi integration\"\r\n },\r\n {\r\n \"hash\": \"node/server-browser\",\r\n \"label\": \"Server/browser shared templates\"\r\n },\r\n {\r\n \"hash\": \"node/browserify\",\r\n \"label\": \"Browserify support\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"node/install\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Installation\\n\\nOn Node.js from the command line, install jsrender:\\n\\n```bash\\n$ npm install jsrender\\n```\\n\\n## Usage\\n\\nLoad the jsrender module:\\n\\n```js\\nvar jsrender = require('jsrender');\\n```\\n\\nNow call JsRender APIs, or use [Express](#node/express-hapi@express) or [Hapi](#node/express-hapi@hapi) integration, for server-rendering of JsRender templates.\\n\\n(For loading JsRender in the browser using Browserify or webpack, see *[JsRender as a Browserify module](#node/browserify@jsrender)* and *[JsRender as a webpack module](#node/webpack@jsrender)*)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender APIs on the server – same as in the browser!\",\r\n \"text\": \"In the browser, when jQuery is present, JsRender loads as a jQuery plugin and adds APIs to the jQuery namespace object, as:\\n\\n`$.views`, `$.templates` and `$.render` \\n\\nOn the server exactly the same APIs are provided, associated instead with the `jsrender` namespace:\\n\\n`jsrender.views`, `jsrender.templates` and `jsrender.render`.\\n\\nFor convenience you can call the namespace `$` and then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy from the regular browser examples/samples -- as if in the browser with jQuery.\\n\\nFor example:\\n\\n```js\\nvar $ = require('jsrender'); // Returns the jsrender namespace object - referenced for convenience as var $\\n\\nvar tmpl = $.templates('Name: {{:first}} {{upper:last'); // Compile template from string\\n\\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\\n \\nvar data = {first: 'Jo', last: 'Ryan'};\\n\\nvar html = tmpl(data); // Or alternative syntax: var html = tmpl.render(data);\\n// result: \\\"Name: Jo RYAN\\\" \\n```\",\r\n \"anchor\": \"apis\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helpers, converters, custom tags...\",\r\n \"text\": \"On Node.js you can use the full set of JsRender features, template tags and APIs, just as you would in the browser -- by simply using the `jsrender` namespace object returned from `require('jsrender')`, instead of the jQuery object, `$`. In addition you can take advantage of [file-based templates](#node/filetmpls).\\n\\n**Custom Tags example:** -- For example, here is the JsRender Quickstart *[Custom Tags Sample](#jsr-quickstart@customtags)*, as you might write it on Node.js:\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\nName: {{fullName person/}}\\n```\\n\\n**Code:**\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\njsrender.views.tags(\\\"fullName\\\", \\\"{{:first}} {{:last}}\\\"); // Register custom tag\\n\\nvar tmpl = jsrender.templates('./templates/personTemplate.html'); // Compile template\\n\\nvar html = tmpl({person: {first: \\\"Jim\\\", last: \\\"Varsov\\\"}}); // Render\\n// result: \\\"Jim Varsov\\\"\\n```\\n\\n**Helpers example:** -- And here is the JsRender Quickstart *[Helpers](#jsr-quickstart@helpers)* example, in a version for Node.js:\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\n{{:~title}} {{:first}} {{:~upper(last)}}\\n```\\n\\n**Code:**\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar myHelpers = {\\n upper: function(val) { return val.toUpperCase(); },\\n title: \\\"Sir\\\"\\n};\\n\\nvar tmpl = $.templates('./templates/personTemplate.html');\\n\\nvar data = {first: \\\"Jim\\\", last: \\\"Varsov\\\"};\\n\\nvar html = tmpl(data, myHelpers);\\n// result: \\\"Sir Jim VARSOV\\\"\\n```\\n\\nOr we can register helpers globally:\\n\\n```js\\njsrender.views.helpers(myHelpers);\\n\\nvar data = {first: \\\"Jim\\\", last: \\\"Varsov\\\"};\\nvar html = tmpl(data);\\n// result: \\\"Sir Jim VARSOV\\\"\\n```\"\r\n }\r\n ]\r\n },\r\n \"node/express-hapi\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Express and Hapi integration\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using Express to render templates\",\r\n \"text\": \"In Express you can use JsRender APIs to render the template, as in the examples above, then return the html in the HTTP response:\\n\\n```js\\napp.get('/...', function(req, res) {\\n res.send(html);\\n});\\n```\\n\\nBut alternatively you can register JsRender as template engine for Express:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\napp.engine('html', jsrender.__express); // Set JsRender as template engine for .html files\\napp.set('view engine', 'html'); \\napp.set('views', __dirname + '/templates'); // Folder location for JsRender templates for Express\\n```\\n\\nRender template *./templates/myTemplate.html* -- content: `Name: {{:name}}
                    `:\\n\\n```js\\napp.get('/...', function(req, res) {\\n res.render('myTemplate', {name: \\\"Jim\\\"}); \\n // result: Name: Jim
                    \\n});\\n```\",\r\n \"anchor\": \"express\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using Hapi to render templates\",\r\n \"text\": \"JsRender also has built-in support as template engine for [Hapi](http://hapijs.com/):\\n\\nSet JsRender as the template engine for Hapi:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nserver.register(vision, function (err) {\\n ...\\n server.views({\\n engines: { html: jsrender },\\n relativeTo: __dirname,\\n path: 'templates'\\n });\\n```\\n\\nUse Hapi to render a template:\\n\\n```js\\nserver.route({\\n method: 'GET',\\n path: '/',\\n handler: function (request, reply) {\\n return reply.view('myTemplate', myData);\\n }\\n});\\n```\",\r\n \"anchor\": \"hapi\"\r\n }\r\n ]\r\n },\r\n \"node/server-browser\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Sharing the same templates between server and browser\\n\\nJsRender lets you share templates between server and client, using either of the *Browserify* or *{{clientTemplate}}* approaches shown below.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Browserify\",\r\n \"text\": \"Using Browserify with the `jsrender/tmplify` transform allows you to include your server [file-based templates](#node/filetmpls) in the Browserify client-script bundle. \\n\\nYou can then access the compiled templates in the browser, as modules, using:\\n\\n```js\\nvar tmpl = require('./.../myTemplate.html)`\\nvar html = tmpl.render(myData);\\n...\\n```\\n\\nFor details, see the *[Browserify](#node/browserify)* topic.\\n\\nFor complete running samples, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering file-based templates in the browser: {{clientTemplate}}\",\r\n \"text\": \"JsRender also provides a `{{clientTemplate}}` tag that makes file-based templates available for rendering in the browser without needing to use Browserify.\\n\\nSimply include `{{clientTemplate \\\"templateFilePath...\\\"}}` in the layout template, for any template you want to expose in the browser:\\n\\n```jsr\\n\\n {{clientTemplate \\\"./templates/myTemplate.html\\\" /}}\\n\\n\\n
                    \\n\\n\\n```\\n\\nSee the *index-express.js* and *index-hapi.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender on the server, JsRender or JsViews in the browser...\",\r\n \"text\": \"Both the *Browserify* and the *{{clientTemplate}}* approach to sharing templates between server and browser let you then render or link those templates in the browser, using JsRender or JsViews.\\n\\nIn the browser, you reference the templates using the same `./file/path/template.html` syntax as on the server. \\n\\nFor example, in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* samples, the [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) template contains the following:\\n\\n```html\\n\\n {{include tmpl=\\\"./templates/movie-list.html\\\"/}}\\n\\n```\\n\\nHere, the `{{include ...}}` is used on the server to do initial rendering of the movies list using the *movie-list.html* template. Then in the browser, the `data-link=\\\"{include ...}` causes JsViews to access the same template in the browser, and provide dynamic data-binding of the list...\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Single Page Apps with initial rendering on server\",\r\n \"text\": \"An important scenario is a *single page app* using JsRender or JsViews in the client to create dynamic UI, combined with initial rendering of the content on the server by JsRender using the same template.\\n\\nThis can bring many advantages, including SEO, and eliminating flicker when the page is refreshed with a new server request.\\n\\n*Note:* To completely eliminate flicker on data-linked content which has already been rendered on the server, it is sometimes useful to use the syntax `data-link=\\\"...^{...}\\\"` -- which data-links without doing the initial render. Here is an example from [movie-detail.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/movie-detail.html) in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)*:\\n\\n```html\\n
                    \\n```\\n\"\r\n }\r\n ]\r\n },\r\n \"tagsyntax\": {\r\n \"title\": \"Tag syntax\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Template tags in JsRender use the Mustache style: `{{...}}`.
                    \\n(You can choose different delimiters, such as `<%...%>`, using `$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\")`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tags without content\",\r\n \"text\": \"The most common JsRender tags are [`{{: pathOrExpr}}`](#assigntag) -- which inserts the value of the path or expression, and [`{{> pathOrExpr}}`](#htmltag) which inserts the *HTML-encoded* value of the path or expression. \\n\\nThose tags, along with the *allow code* tag [`{{* ...}}`](#allowcodetag) and *comment tag* [`{{!-- ... --}}`](#commenttag), are self-contained tags which do not wrap other content:\\n\\n**Built-in tags without content:**\\n\\n```jsr\\n{{: pathOrExpr}} (value)\\n{{> pathOrExpr}} (HTML-encoded value)\\n{{* mycode}} (using code)\\n{{!-- this is a comment --}} \\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags – tags with content: \",\r\n \"text\": \"**All other built-in tags, as well as all custom tags, use the block tag syntax:**\\n\\n```jsr\\n{{include ...}}...{{/include}} or {{include .../}}\\n{{for}}...{{/for}} or {{for.../}}\\n{{props}}...{{/props}} or {{props .../}}\\n{{if}}...{{/if}} or {{if .../}}\\n{{myCustomTag}}...{{/myCustomTag}} or {{myCustomTag .../}}\\n```\\n\\nTags using the *block tag syntax* have *open* and *close* tags, with content, or else they use the self-closing syntax, without content:\\n\\n**Block tag with content**\\n\\n```jsr\\n{{sometag ...}}\\n content\\n{{/sometag}}\\n```\\n\\n**Self-closing block tag (empty tag) -- no content:**\\n\\n```jsr\\n{{sometag .../}}\\n```\\n\\n\",\r\n \"anchor\": \"blocktag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using tmpl=... to reference content as an external template\",\r\n \"text\": \"A particular case of self-closing syntax is when any block tag uses the named parameter `tmpl=...` to reference an external template, which then replaces what would have been the block content.\\n\\nThis is a very useful technique for encapsulation and reuse of tag content. The content becomes a *'partial'* -- and is included thanks to template composition:\\n\\n**Self-closing block tag referencing an external template:**\\n\\n```jsr\\n{{sometag ... tmpl=.../}}\\n```\\n\\n(See for example `{{for languages tmpl=\\\"#columnTemplate\\\"/}}` in [this sample](#samples/jsr/composition/tmpl).)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Template composition (partials)\",\r\n \"text\": \"The most common way of composing templates is to have a layout template, and to use `{{include tmpl=... /}}`:\\n\\n```jsr\\ntop level content\\n{{include tmpl='myInnerTemplate' /}}\\n```\\n\\nBut in fact template composition can be done by adding references to external templates using `tmpl=...` on ***any*** tag, as shown in the previous section.\\n\\n**Dynamic composition**\\n\\nNote that the `tmpl=...` can use any expression, so you can assign different nested templates dynamically based on data or context. For example you might write `{{include tmpl=~getTemplate(type) /}}` -- where `~getTemplate(...)` is a helper which returns a different template based in this case on the `type` property of the current data item.\\n\\nIn fact when setting `tmpl=...` dynamically, the returned template can be in any if the following forms:\\n- a compiled template\\n- a markup string\\n- the name of a registered template\\n- a selector\\n- (on Node.js) a file path to a template\",\r\n \"anchor\": \"composition\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag arguments and named parameters\",\r\n \"text\": \"Tags can take both unnamed arguments and named parameters:\\n\\n```jsr\\n{{sometag argument1 param1=...}}\\n content\\n{{/sometag}}\\n```\\nAn example of a named parameter is the `tmpl=...` parameter mentioned above:\\n\\n```jsr\\n{{for languages tmpl=\\\"#columnTemplate\\\"/}}\\n```\\n\\nArguments and named parameters can be assigned values from simple data-paths such as:\\n\\n```jsr\\n{{formattedAddress address.street format=~util.formats.upper /}}\\n```\\n\\nor from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\\n\\n```jsr\\n{{productValue product.quantity*3.1/4.5 description=name.toUpperCase() /}}\\n```\\n\",\r\n \"anchor\": \"tagparams\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Wrapping content \",\r\n \"text\": \"If a tag has an external `tmpl=...` reference, ***and*** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (one or more times), thanks to the [`view.content`](#viewobject@content) or `#content` property:\\n\\n```jsr\\n{{sometag ... tmpl=\\\"externalTmpl\\\"}}\\n inline block content\\n{{/sometag}}\\n```\\n\\n```js\\n$.templates(\\\"externalTmpl\\\", \\\"before {{include tmpl=#content /}} after\\\";\\n```\\n\\nSimilarly, a custom tag can use a built-in template which wraps the inline content:\\n\\n \\n```jsr\\n{{mytag}}\\n inline block content\\n{{/mytag}}\\n```\\n\\n```js\\n$.view.tags(\\\"mytag\\\", {\\n ...\\n template: \\\"before {{include tmpl=#content /}} after\\\"),\\n ...\\n});\\n```\",\r\n \"anchor\": \"wrap\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags with {{else}}\",\r\n \"text\": \"Some block tags provide features which involve using alternative content blocks. Block tag syntax supports this by allowing the content to be separated into two or more alternative content blocks, using `{{else}}` tags as separators:\\n\\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\\n\\n```jsr\\n{{if firstExpression}}\\n render this if the firstExpression is true\\n{{else secondExpression}}\\n else render this if the secondExpression is true\\n{{else}}\\n else render this\\n{{/if}}\\n```\\n\\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\\n\\n```jsr\\n{{for members}}\\n Member Name: {{:name}}\\n{{else}}\\n There are currently no members...\\n{{/for}}\\n```\\n\\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\\n\\n```jsr\\n{{tabs caption=\\\"First Tab\\\"}}\\n first tab content\\n{{else caption=\\\"Second Tab\\\"}}\\n second tab content\\n{{/tabs}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsrtags\",\r\n \"label\": \"Template tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"views\": {\r\n \"title\": \"JsRender view hierarchy\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"A view is a rendered template/block tag\",\r\n \"text\": \"Each instance of a rendered template or a template [block tag](#tagsyntax@blocktag) is associated with a JsViews [*\\\"view\\\"* object](#viewobject).\\n\\nFor example, if the following template is rendered, and inserted into the page --\\n\\n```jsr\\n\\n```\\n\\n```js\\nvar team = {title: \\\"The A team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n```\\n\\n-- then the rendered result will have the following *view structure*:\\n\\n
                    \\n— teamView                (Team: The A team)\\n   — ifView               (The team has members!)\\n
                    \\n\\n\\nEach view is associated with a [`view`](#viewobject) object, which provides APIs for accessing properties of that view, as well as for accessing parent or child views in the view hierarchy.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The data context of a view\",\r\n \"text\": \"In particular, a [`view`](#viewobject) has a [`data`](#viewobject@data) property, which is the *current data context* used for rendering that *view* (rendering that template, or inline block content):\\n\\n
                    \\n— teamView                data: team\\n   — ifView               data: team\\n
                    \\n\",\r\n \"anchor\": \"datacontext\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Inline block content / external 'tmpl=...' reference: same view hierarchy...\",\r\n \"text\": \"A view corresponds to an instance of a *[block tag](#tagsyntax@blocktag)* ***or*** a *rendered template* -- so if we replace the inline content of a tag by an external reference: `tmpl=...`, the rendered result will be unchanged, and *the view structure will also be identical*:\\n\\n```jsr\\n\\n\\n\\n```\\n\\nSame view structure as before:\\n \\n
                    \\n— teamView                data: team\\n   — ifView               data: team\\n
                    \",\r\n \"anchor\": \"nestedtmpl\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Stepping into a block tag – what is the new data context?\",\r\n \"text\": \"Let's add a custom tag `{{mytag}}` to our template:\\n\\n```jsr\\nMy team\\n{{mytag members/}}\\n...\\n```\\n\\nWe'll define the custom tag, with a built-in template:\\n\\n```js\\n $.views.tags(\\\"mytag\\\", \\\"{{:length}} member(s)\\\");\\n```\\n\\n`{{mytag members/}}` will render block content (with an associated view) using its tag template `\\\"{{:length}} members\\\"`. \\n\\n*What will the data context be for the `mytag` view?*\\n\\nBy default:\\n\\n- a block tag with no argument `{{sometag}}` will stay on the current data context\\n- a block tag with an argument `{{sometag expr ...}}` will move the data context to `expr`.\\n\\nSo `{{mytag members}}` (just like `{{include members}}`) *will move the data context to `members`*.\",\r\n \"anchor\": \"innerdata\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"However a block tag may be designed to simply stay on the same data context as the parent block -- and that is the case for the `{{if}}` tag:\\n\\n- `{{if expr}}` does not move the data context.\\n\\nSo our template\\n\\n```jsr\\n\\n```\\n\\nwill have this view structure:\\n\\n
                    \\n— teamView                data: team\\n   — mytagView            data: team.members\\n   — ifView               data: team (same as parent – teamView)\\n
                    \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Array views and item views – {{for array}}\",\r\n \"text\": \"Now let's add a `{{for members}}` tag to iterate over the `members`, inside the `{{if}}` block:\\n\\n```jsr\\nTeam\\n{{mytag members/}}\\n\\n{{if members.length}}\\n Members:\\n {{for members}}\\n {{:name}}\\n {{/for}}\\n{{/if}}\\n```\\n\\nWhen a [`{{for ...}}`](#propstag) tag is used with an array it creates:\\n\\n- an *\\\"array\\\" view*, whose `data` property is the array -- and under the \\\"array\\\" view:\\n- an *\\\"item\\\" view* for each item in the array -- with as `data` property the item, and as [`index`](#getindex) property the index in the array:\\n\\n(Similarly, any tag which derives from the `{{for}}` tag -- such as the [`{{props}}`](#propstag) tag -- will also add an \\\"array\\\" view and \\\"item\\\" views...)\\n\\nSo our view structure with the `{{for}}` tag included will now be :\\n\\n
                    \\n— teamView                data: team                 type: \\\"data\\\"\\n   — mytagView            data: team.members         type: \\\"mytag\\\"\\n   — ifView               data: team                 type: \\\"if\\\"\\n      — arrayView         data: team.members         type: \\\"array\\\"\\n         — itemView       data: team.members[0]      type: \\\"item\\\"\\n         — itemView       data: team.members[1]      type: \\\"item\\\"\\n
                    \\n\\n-- where we show also the [`type`](#viewobject@type) property of each `view`.\",\r\n \"anchor\": \"itemview\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Array views and item views – tmpl.render(array)\",\r\n \"text\": \"Suppose now we have an array of teams -- and we pass the `teams` array to the `render()` method:\\n\\n```js\\nvar teams = [\\n {title: \\\"A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n```\\n\\nJsRender will render the `teamTemplate` once for each team -- and just like with the `{{for}}` it will create an *\\\"item\\\" view* for each item in the `teams` array -- with the two *\\\"item\\\" views* as children of an *\\\"array\\\" view*.\\n\\nHere it is as a working sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var html = $(\\\"#teamTemplate\\\").render(teams);\\n\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"// mytag: custom tag to output \\\"1 member\\\" or \\\"n members\\\"\\n$.views.tags(\\\"mytag\\\", \\\"{{:length == 1 ? '1 member' : length + ' members'}}
                    \\\");\\n// Alternative version of mytag:\\n// $.views.tags(\\\"mytag\\\", \\\"{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
                    \\\");\\n\\nvar teams = [\\n {title: \\\"The A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"The B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"86\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the resulting view structure:\\n\\n
                    \\n— arrayView               data: teams\\n   — itemView             data: teams[0]               (Team: The A Team - )\\n      — mytagView         data: team.members           (2 members)\\n      — ifView            data: teams[0]               (Members:)\\n         — arrayView      data: teams[0].members\\n            — itemView    data: teams[0].members[0]    (Jeff)\\n            — itemView    data: teams[0].members[1]    (Maria)\\n   — itemView             data: teams[1]               (Team: The B Team - )\\n      — mytagView         data: team.members           (1 members)\\n      — ifView            data: teams[1]               (Members:)\\n         — arrayView      data: teams[1].members\\n            — itemView    data: teams[1].members[0]    (Francis)\\n
                    \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The default argument for a tag is the current data – #data\",\r\n \"text\": \"For all built-in tags (and custom tags if you don't use the [argDefault](#tagsapi@argdefault) option), you can pass the current data to the tag by writing it without an argument.\\n\\nSo the following:\\n\\n```jsr\\n{{:}} {{!--Render value of current data (string)--}}\\n{{>}} {{!--Render value of current data (string)--}}\\n{{for}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\\n{{if}}...{{/if}} {{!--Render block if current data is truthy--}}\\n{{props}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\\n```\\n\\nare equivalent to:\\n\\n```jsr\\n{{:#data}} {{!--Render value of current data (string)--}}\\n{{>#data}} {{!--Render value of current data (string)--}}\\n{{for #data}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\\n{{if #data}}...{{/if}} {{!--Render block if current data is truey--}}\\n{{props #data}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"In JsViews: From UI back to data:\",\r\n \"text\": \"***Note:*** One of the features provided by JsViews data-linking (when you use the JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method) is the [`$.view(elem)`](#$view) method. This method provides a *reverse mapping* and lets you get from a rendered DOM element back to the corresponding view object in the view hierarchy. From the view you can get to the underlying data, the index, etc.\\n\\nSo in effect in JsViews, *the mapping from the view hierarchy to the UI becomes a two-way mapping...* \\n\\nSee [*Using $.view() to get from the rendered UI back to the data*](#jsv.d.view)\",\r\n \"anchor\": \"#$view\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"getindex\",\r\n \"label\": \"getIndex()\"\r\n },\r\n {\r\n \"hash\": \"contextualparams\",\r\n \"label\": \"Contextual parameters\"\r\n },\r\n {\r\n \"hash\": \"parentdata\",\r\n \"label\": \"Accessing parent data\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"paths\": {\r\n \"title\": \"Paths and expressions\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender tags can take [unamed arguments, or named parameters](#tagsyntax@tagparams):\\n\\n```jsr\\n{{:arg0}}\\n\\n{{sometag arg1 arg2 param_a=param1 param_b=param2}}\\n content\\n{{/sometag}}\\n```\\n\\nThe values of the arguments or parameters (such as `arg0`... `param1` ... above) must be valid JsRender paths or expressions.\\n\\nJsRender expressions are regular Javascript expressions, but with *no access to global variables*.\\n\\nInstead of global Javascript variables, JsRender expressions use *data paths*, *helper paths* and *view paths*, to access data values, values provided by helpers, and values obtained from the [view hierarchy](#views), such as the `#getIndex()`.\\n\\n***Data paths*** are of the form `dataProperty.bb.cc`, and they step through the data hierarchy, starting from the current data item (the [data context](#views@datacontext) for the current view). They can include array access, such as `team.members[id]`\\n\\n***View paths*** are of the form `#viewProperty.bb.cc`, and they start from the current [view](#views). So for example, `#data` is short for `#view.data` -- where `#view` is the current view.\\n\\n***Helper paths*** are of the form `~myHelper.bb.cc`, and they start from the named [helper](#helpers) `\\\"myHelper\\\"`. In addition they can be used to access *[contextual parameters](#contextualparams)*, or the built-in [`~root`](#contextualparams@root) \\n\\nHere are some examples of JsRender paths and values:\\n\\n*Data paths*:\\n\\n```jsr\\n{{:name}}\\n{{for address.street}}...{{/for}}\\n{{>team.members[0].lastName}}\\n{{:name.toUpperCase()}}\\n```\\n\\n*Helper paths*:\\n\\n```jsr\\n{{>~utilities.errorMessages.msg1}}\\n{{if ~settings.show}}...{{/if}}\\n{{:~root.selectedName}} {{!--Accessing root data--}}\\n```\\n\\n*View paths*:\\n\\n```jsr\\n{{:#getIndex()}}\\n{{include #content /}}\\n{{if #parent.parent.data.isLead}}...{{/if}}\\n{{>~getDescription(#data)}}\\n```\\n\\n*A primitive value of type string, number, boolean, null ...*:\\n\\n```jsr\\n{{if isOpen tmpl='It is open' /}}\\n{{for address tmpl=\\\"#addressTemplate\\\"}}...{{/for}}\\n{{for members start=1 end=5 /}}\\n{{for members reverse=true /}}\\n```\\n\\nJsRender expressions can combine values in more complex expressions, using functions, parens, operators such as `+` `-` `*` `/` `!` `===` `==` `>` `!==` `||` `&&`, as well as ternary expressions: `...?...:...`, array and object accessors: `[...]` etc.\\n\\n*Here are some examples of expressions*: \\n\\n```jsr\\n{{if book.author === \\\"Jim Boyd\\\"}}...{{/if}}\\n{{:~utilities.format(book.title, 'upper', true)}}\\n{{for ~sort(~root.getMembers()}}}...{{/for}}\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n{{for #parent.data.members()/}}\\n{{:(~addRebate(book.price) + 23.2)*3.5/2.1}}\\n{{:~mode === \\\"useTitle\\\" ? book.title : book.name}}\\n{{if error}}...{{else !utilities.valid(book.description)}}...{{else}}...{{/if}}\\n{{:~books[id].title}}\\n{{:people[~currentIndex].name}}\\n```\\n\\nExpressions can include white space. The following two examples are equivalent:\\n\\n```jsr\\n{{averageValue product.quantity*3.1/4.5 description=~getDescription(#data) /}}\\n{{averageValue product.quantity * 3.1 / 4.5 description = ~getDescription( #data ) /}}\\n```\\n\\nThe `{{averageValue}}` tag is being assigned one argument, and one named \\\"description\\\" parameter. The two expressions differ only in white space, and both are syntactically valid. However, removing optional white space -– as in the first example -– makes it easier to see the distinct arguments and parameters of the tag.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Chained paths: Stepping through object properties (or functions)\",\r\n \"text\": \"All of the paths above (whether *Data/Helper/View paths*) involve starting from an initial value (a *current data item property/helper/view property*) -- and then, if it is an object, perhaps stepping through one or more chained properties.\\n\\nFor example `team.manager.address.street` starts from a `team` object and steps through the `manager` property -- which is itself a 'person' object with an `address` property, etc. \\n\\n(See also *[Data-linked paths](#linked-paths)*.)\",\r\n \"anchor\": \"paths\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Computed properties\",\r\n \"text\": \"In some cases a property may be of type *function* (possibly taking parameters), so you might have:\\n\\n`team.manager().getAddress('home').street`\\n\\n-- where the manager property is in fact a *'getter'* function which returns a `person` object, which has a `getAddress()` parameterized accessor (taking `'home'` or `'work'` -- or maybe a Boolean `isHomeAddress`). Similarly a path can include an array accessor such as `team.members['id'].address`.\\n\\nProperties of type function -- returning a value -- are referred to as a *computed properties*, or *getter properties*, and
                    \\n`team.manager().getAddress('home').street` is an example of chained computed properties.\\n\\n(See also *[Computed properties and computed observables](#computed)* -- for using computed properties with JsViews and data-linking.)\\n\\nA computed value can also use JavaScript methods, such `toFixed()` to format a number:\\n\\n```jsr\\n{{:price.toFixed(2)}} \\n{{:(+price).toFixed(2)}} \\n```\",\r\n \"anchor\": \"computed\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter properties and computed properties\",\r\n \"text\": \"A common pattern using computed 'getter' functions would be to provide a `person.firstName()` 'getter' property which returns a value: `person._firstName`, considered as 'private'.\\n\\nIn addition, there may be computed properties which depend on other properties, such as a `person.fullName()` which concatenates first and last name.\\n\\nHere is a sample showing both types of computed property:\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Data:*\\n\\n```js\\nfunction firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nvar data = {\\n person: {\\n _firstName: \\\"Jo\\\",\\n _lastName: \\\"Blow\\\",\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n }\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n First name: {{:person.firstName()}}\\n Last name: {{:person.lastName()}}\\n Full name: {{:person.fullName()}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"function firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nvar data = {\\n person: {\\n _firstName: \\\"Jo\\\",\\n _lastName: \\\"Blow\\\",\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n }\\n};\\n\\nvar html = $(\\\"#personTmpl\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"height\": \"72\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Getter properties with plain objects\",\r\n \"anchor\": \"getter-plain-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter properties on a View Model\",\r\n \"text\": \"Rather than using plain JavaScript objects with getter functions, as above, a more common pattern (providing better encapsulation) would be to define a *'View Model'* class -- with getter properties defined in the class -- and to instantiate that class to provide data instances.\\n\\n(See *[Plain objects or View Model](#explore/objectsorvm)* for details.)\\n\\nThe following sample uses that approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Data:*\\n\\n```js\\nfunction firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nfunction Person(first, last) {\\n this._firstName = first;\\n this._lastName = last;\\n}\\n\\nPerson.prototype = {\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n};\\n\\nvar data = {\\n person: new Person(\\\"Jo\\\", \\\"Blow\\\")\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n First name: {{:person.firstName()}}\\n Last name: {{:person.lastName()}}\\n Full name: {{:person.fullName()}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"72\",\r\n \"code\": \"function firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nfunction Person(first, last) {\\n this._firstName = first;\\n this._lastName = last;\\n}\\n\\nPerson.prototype = {\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n};\\n\\nvar data = {\\n person: new Person(\\\"Jo\\\", \\\"Blow\\\")\\n};\\n\\nvar html = $(\\\"#personTmpl\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"Getter properties with a View Model\",\r\n \"anchor\": \"getter-vm-sample\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"settings/allowcode@security\",\r\n \"label\": \"Expressions and security\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tmplsyntax\": {\r\n \"title\": \"Template syntax and structure\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following topics provide information on JsRender template syntax:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"settings\": {\r\n \"title\": \"Settings\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender provides the following APIs for modifying settings:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"settings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"hash\": \"settings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"hash\": \"settings/allowcode\",\r\n \"label\": \"Allow code\"\r\n },\r\n {\r\n \"hash\": \"settings/advanced\",\r\n \"label\": \"Additional advanced settings\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"settings/delimiters\": {\r\n \"title\": \"Setting tag delimiters for JsRender\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also *[Setting tag delimiters for JsViews](#jsvsettings/delimiters)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender default tag delimiters\",\r\n \"text\": \"Template tags in JsRender use the Mustache style: `{{...}}`\\n\\n(JsRender also accepts the data-linked tag syntax used in in JsViews: `{^{...}}`). \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Changing delimiters:\",\r\n \"text\": \"Sometimes there can be a need to use different delimiters. For example there may be a conflict if the template is being rendered on the server using a declarative syntax such as *Django* with the same default delimiters `{{` and `}}`.\\n\\nThe following call:\\n\\n```js\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n```\\n\\nwill change the tag syntax to `<%...%>`.\\n\\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `[\\\"<%\\\", %>\\\"]` -- as shown in the last sample below.)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Verifying current setting for tag delimiters:\",\r\n \"text\": \"```js\\nvar delimiters = $.views.settings.delimiters();\\n// Returns an array [\\\"{{\\\", \\\"}}\\\", \\\"^\\\"] - JsRender tag delimiters (and JsViews link character)\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Markup:* \\n\\n```jsr\\n\\n```\\n\\n*Code*\\n\\n```js\\n$.views.settings.delimiters(\\\"[%\\\", \\\"%]\\\");\\n\\nvar tmpl = $.templates(\\\"#peopleTmpl\\\");\\n...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"$.views.settings.delimiters(\\\"[%\\\", \\\"%]\\\");\\n\\nvar tmpl = $.templates(\\\"#peopleTmpl\\\");\\n\\nvar team = {\\n title: \\\"A team\\\",\\n members: [{name: \\\"Jo\\\"}]\\n };\\n\\nvar html = tmpl.render(team);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"70\",\r\n \"title\": \"Choosing alternative tag delimiters, with JsRender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using alternative delimiters to 'render a template with a template'\",\r\n \"text\": \"In some scenarios you might want to use a template to generate a template, such as a template on the server to generate/render a template that will then be used in the browser.\\n\\nA good approach to achieving this is to use a different set of delimiters on the server.\\n\\nA similar scenario is to use a 'base' template to render different versions of a template for different languages/localities, as in this example:\\n\",\r\n \"anchor\": \"tmpl-for-tmpl\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n<%:hello%>, {{:name}}
                    \\n<%:welcome%> {{:place}}\\n```\\n\\n```js\\n// Get current delimiters\\nvar currentDelimiters = $.views.settings.delimiters();\\n\\n// Temporarily switch delimiters\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n\\n// Translate to Spanish localized version\\nvar localizedTemplate = $.templates(\\\"#baseTmpl\\\").render(spanishTerms);\\n\\n// Revert to original delimiters\\n$.views.settings.delimiters(currentDelimiters);\\n\\n// Render data using localized template\\nhtml = $.templates(localizedTemplate).render(data);\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \\n\",\r\n \"code\": \"var spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Get current delimiters\\nvar currentDelimiters = $.views.settings.delimiters();\\n\\n// Temporarily switch delimiters\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n\\n// Translate to Spanish localized version\\nvar localizedTemplate = $.templates(\\\"#baseTmpl\\\").render(spanishTerms);\\n\\n// Revert to original delimiters\\n$.views.settings.delimiters(currentDelimiters);\\n\\n// Render data using localized template\\nhtml = $.templates(localizedTemplate).render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"54\",\r\n \"title\": \"Template for a template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Incidentally the above scenario of localized terms in a template can be achieved without the 'build step' of creating localized templates, simply by passing in the terms as helpers, distinct from the data itself.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Pass in localized terms as helpers\\nvar html = $.templates(\\\"#tmpl\\\").render(data, spanishTerms );\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \\n\",\r\n \"code\": \"var spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Pass in localized terms as helpers\\nvar html = $.templates(\\\"#tmpl\\\").render(data, spanishTerms );\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"height\": \"54\",\r\n \"title\": \"Passing in terms as helpers\",\r\n \"anchor\": \"passing\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n }\r\n ]\r\n },\r\n \"settings/onerror\": {\r\n \"title\": \"onError\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"settings/dbgmode\": {\r\n \"title\": \"dbgMode\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"settings/debugmode\": {\r\n \"title\": \"Setting debug mode\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender has a *'debug mode'* setting which determines whether error messages encountered during rendering are displayed.\\n\\n***To get current debug mode:***\\n\\n```js\\nvar isDebugMode = $.views.settings.debugMode(); // false by default\\n```\\n\\n***To set debug mode:***\\n\\n```js\\n$.views.settings.debugMode(...);\\n```\\n\\nDebug mode can be set to any of the following:\\n\\n- `false` -- *errors during rendering will not be rendered* (but an exception will be thrown)\\n- `true` -- no exception will be thrown, but *the error message will be rendered*, in place of the template tag or block\\n- `\\\"some string\\\"` -- no exception. *The string `\\\"some string\\\"` will be rendered* in place of the tag or block\\n- `\\\"\\\"` (empty string) -- no exception. The tag or block will simply be *replaced by the empty string*\\n- a function (to be used as an error handler) -- no exception. The handler will run, and *the error string will be rendered, or else, if the function returns a string, that string will be rendered*\\n\\nSee *[Error handling and debugging](#onerror)* for a full discussion of alternative approaches, together with [details and working examples](#onerror@debugmode) of `$.views.settings.debugMode(...)`.\\n\\n \"\r\n }\r\n ]\r\n },\r\n \"settings/allowcode\": {\r\n \"title\": \"Allow code\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\\n\\n```jsr\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n```\\n\\n\\n\\nNevertheless, in order to improve encapsulation, security and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \\n\\nIf you want complete freedom to insert any code into a compiled template, you can set **allowCode** to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the [`{{* ...}}`](#allowcodetag) tag, or you can return (render into the template output) the result of evaluating any expression, using the [`{{*: ...}}`](#allowcodetag) tag.\\n\\n(*Note:* it is not recommended to set `allowCode` to true within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"User-defined templates and security\",\r\n \"text\": \"For most purposes there is no need to set `allowCode` to true, since the built-in template expressions provide rich functionality which is sufficient for most scenarios.\\n\\nJsRender can be used to render templates either on the server or in the browser -- and is often used for applications which allow users to create their own templates, or to insert markup and expressions into templates. With `allowCode` false, JsRender is designed to *make it impossible for such user-defined templates to run arbitrary code*.\\n\\nUsers can include rich template expressions in the template, but they won't be able to insert code that accesses any variables (or runs any methods) that are outside of the template scope. (They can only access the contextual data/model, use the standard operators, and use any helper methods and variables which the author decides to provide.)\",\r\n \"anchor\": \"security\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode to true, globally\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(true);\\n```\\n(See samples for [`{{* ...}}` and `{{*: ...}}`](#allowcodetag@sample))\\n \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode back to false, globally\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(false);\\n```\\n\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To get current global allowCode setting\",\r\n \"text\": \"```js\\nvar allowCodeIsTrue = $.views.settings.allowCode(); // false by default\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode to true for a specific template\",\r\n \"text\": \"```js\\n$.templates(..., {\\n markup: ...,\\n allowCode: true,\\n ...\\n})\\n```\\n\\n(See `{{* ...}}` and `{{*: ...}}` sample: *[allowCode for template](#allowcodetag@tmpl)*).\"\r\n }\r\n ]\r\n },\r\n \"settings/advanced\": {\r\n \"title\": \"Advanced settings\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender has the following advanced setting:\\n\\n- **useViews** -- *default:* `false`\\n\\nand also the following 'private' advanced setting:\\n\\n- **_jsv** -- *default:* `false`\\n\\n***useViews*** controls a JsRender performance optimization, while building the *[view hierarchy](#views)*. In very simple templates there will usually not be any need to access the [`view`](#viewobject). JsRender detects these cases, does not create a view, and hence obtains a slight performance gain. By setting `useViews` to `true`, you guarantee that JsRender will *always* create views for template blocks.\\n\\n***_jsv*** is a 'private' setting (could change in the future). If set to `true` JsRender provides a global `_jsv` variable, which gives access to the internal store of views.\\n\\n***To get current advanced settings:***\\n\\n```js\\nvar advancedSettings = $.views.settings.advanced();\\n```\\n\\nBy default the returned `advancedSettings` object is:\\n\\n```js\\n{useViews: false, _jsv: false}\\n```\\n\\n***To set advanced settings:***\\n\\n```js\\n$.views.settings.advanced({useViews: true});\\n// Set one or more advanced settings\\n```\"\r\n }\r\n ]\r\n },\r\n \"onerror\": {\r\n \"title\": \"Error handling and debugging\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Sometimes when rendering a JsRender template, a JavaScript error is encountered. For example `{{:address.street}}` in a template will render without error provided there is an `address` property on the current data object. But if there is no `address` property, then *there will be an error*: ***\\\"Cannot read property 'street' of undefined\\\"***.\\n\\nJsRender provides two features which provide powerful control over rendering behavior when errors are encountered.\\n\\n- The optional [`onError=...` property](#onerror@onerror) that can be set on any tag -- for controlling error handling behavior on that specific tag\\n- The [`$.views.settings.debugMode(...)` setting](#onerror@debugmode) -- which provides global control over error handling during rendering\\n\\nIn addition, for advanced debugging of compiled templates, see:\\n\\n- *[Using debugging helpers](#onerror@dbg)*\\n\\n
                    \\n## Specifying onError fallback behavior on a tag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to a string\",\r\n \"text\": \"All JsRender tags (including custom tags) such as `{{address.street}}` or `{{for getItems()}}` allow you to provide a `onError` tag property, with a fallback string to render in the case of errors:\\n\\n```jsr\\n{{:address.street onError=\\\"Address unavailable\\\"}}\\n```\\n\\n```jsr\\n{{for phones() onError=\\\"No phones\\\"}}\\n```\\n\\n```jsr\\n{{myCustomTag ... onError=\\\"\\\"}}\\n```\\n\\nThe `onError` fallback string will be rendered whenever there an error (or exception) is encountered during the tag rendering.\\n\\nSetting to the empty string ensures that errors are simply ignored, and the tag renders as the empty string.\",\r\n \"anchor\": \"onerror\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In this sample, if a `member` object has no `address` property, the `address.street` expression will lead to a JavaScript error, and the `{{:address.street onError=\\\"Address unavailable\\\"}}` will render the fallback string: `\\\"Address unavailable\\\"`.\\n\\nSimilarly, `{{for phones() onError=\\\"...\\\"}}`, if `phones()` produces an error... \\n\\n*Template:*\\n\\n```jsr\\n{{for phones() onError=\\\"No phones\\\"}} ...\\n{{:address.street onError=\\\"Address unavailable\\\"}}\\n```\\n\\n*Code:*\\n\\n```js\\nfunction phones() { if (!this._phones) { throw new Error(\\\"phones() error\\\"); } ... }\\n```\\n\\n*Data:*\\n\\n```js\\nmembers: [\\n {address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"], ...\\n {address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], ... // No address\\n {address: {street: \\\"Main St\\\"}, _phones: undefined, ... // _No phones\\n]\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"data\": [],\r\n \"code\": \"function phones() {\\n if (!this._phones) {\\n throw new Error(\\\"phones() error\\\");\\n }\\n return this._phones;\\n}\\n\\nvar team = {\\n members: [\\n {address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"],\\n phones: phones},\\n {address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], // No address\\n phones: phones},\\n {address: {street: \\\"Main St\\\"}, _phones: undefined, // _No phones\\n phones: phones}\\n ]\\n};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"onError=\\\"fallback string...\\\" \",\r\n \"height\": \"164\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to an expression\",\r\n \"text\": \"More specific or powerful behavior can be obtained by setting onError to an expression, such as:\\n\\n```jsr\\n{{:address.street onError=name + \\\" has no address\\\"}}\\n```\\n\\n```jsr\\n{{:address.street onError=~errorMessages(1, name, 'address')}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for phones() onError=name + \\\" has no phones\\\"}} ...\\n```\\n\\n```jsr\\n{{:address.street onError=~errorMessages(1, name, \\\"address\\\")}}\\n```\\n\\n```js\\n$.views.helpers(\\\"errorMessages\\\", function(id, param1, param2) {\\n if (id === 1) { return param1 + \\\" has no \\\" + param2; } ...\\n});\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"function phones() {\\n if (!this._phones) {\\n throw new Error(\\\"phones() error\\\");\\n }\\n return this._phones;\\n}\\n\\nvar team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"],\\n phones: phones},\\n {name: \\\"Jane\\\", address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], // No address\\n phones: phones},\\n {name: \\\"Ava\\\", address: {street: \\\"Main St\\\"}, _phones: undefined, // _No phones\\n phones: phones}\\n ]\\n};\\n\\n$.views.helpers(\\\"errorMessages\\\", function(id, param1, param2) {\\n if (id === 1) {\\n return param1 + \\\" has no \\\" + param2;\\n } \\n});\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"height\": \"210\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"onError=someExpression...\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to a function\",\r\n \"text\": \"If `onError=myOnErrorHandler` is set to a function, then the function will be called when there is an error.\\n\\n- If the function returns a string, then that string will be rendered, replacing the output of the tag\\n- If the function has no return value, then the error message will be rendered\\n\\nFor example, you can provide a `person.error()` error handler method on a person object, and set `onError=error`. Or you can use global helper (or a helper passed to the render function), and set `onError=~myErrorHandler`, such as the following to log the error and display just the empty string:\\n\\n```js\\nfunction myErrorHandler(e, view) {\\n console.log(...); // Log the error \\n return \\\"\\\"; // Display the empty string \\n}\\n```\\n\\nThe parameters of the onError handler function -- `myHandler(e, view)` -- will be:\\n\\n- `e` -- the `error` object\\n- `view` -- the current `view` object\\n- The `this` pointer will be the current data item, `view.data`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:address.street onError=~myOnError}}\\n```\\n```js\\nfunction onErrorHandler(e, view) {\\n console.log(e.message);\\n if (!this.address) {\\n return this.name + \\\" has no address (\\\" + e.message + \\\")\\\";\\n }\\n}\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team, {myOnError: onErrorHandler});\\n```\"\r\n }\r\n ],\r\n \"code\": \"var team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}},\\n {name: \\\"Jane\\\", address: undefined} // No address\\n ]\\n};\\n\\nfunction onErrorHandler(e, view) {\\n console.log(e.message);\\n if (!this.address) {\\n return this.name + \\\" has no address (\\\" + e.message + \\\")\\\";\\n }\\n}\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team, {myOnError: onErrorHandler});\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"height\": \"126\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"onError=~myOnError\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
                    \\n## Setting debug mode\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `$.views.settings.debugMode(...)` setting provides control of error handling during rendering, similar to the `onError` feature [above](#onerror@onerror), but operating at a global level rather than on individual tags.\\n\\nThese two approaches are complementary and can be used together. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting debug mode to true\",\r\n \"text\": \"- By default *debug mode* is **false** -- and *an exception will be thrown if a JavaScript error is encountered while rendering a tag or template*\\n- If *debug mode* is set to **true** -- any error message encountered while rendering a tag *will replace the rendered content of that tag*\\n\\n***To set debug mode to true:***\\n\\n```js\\n$.views.settings.debugMode(true);\\n```\\n\\n***To set debug mode back to false:***\\n\\n```js\\n$.views.settings.debugMode(false);\\n```\\n\\n***To get current debug mode:***\\n\\n```js\\nvar isDebugMode = $.views.settings.debugMode(); // false by default\\n```\\n\\nIn the following example *debug mode* is set to `true`. The error message is rendered, replacing the rendered tag.\\n\\n(Choose *Try it* and change *debug mode* to `false`, to see the difference.)\\n\",\r\n \"anchor\": \"debugmode\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Code:*\\n\\n```js\\n$.views.settings.debugMode(true);\\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by the error message.\\n\\n```js\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n...\\n```\\n\\n*Template:*\\n\\n```jsr\\n{{for members}}\\n
                    {{:name}} - {{:address.street}}
                    \\n{{/for}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.settings.debugMode(true); \\n// Change to $.views.settings.debugMode(false); - The error\\n// will not be displayed, but an exception will be thrown.\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\",\r\n \"title\": \"Debug mode set to true\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following example also illustrates setting *debug mode* to `true`, but this time it is used with JsViews, and the `link(...)` method, rather than JsRender and `render(...)`.\\n\\nThe error conditions can arise both in expressions within tags, such as `{^{:manager.name}}` and data-link expressions such as `\\n {{if owner}}\\n Owner: {^{:manager.name}}\\n {{/if}}\\n
                    \\nEdit: \\n```\\n\\n*Code:*\\n\\n```js\\n$.views.settings.debugMode(true);\\n// Debug mode is set to true, so error messages are rendered in place of the corresponding tag or data-link expression.\\n\\nvar team = {owner:\\n {name:\\\"Jo\\\"}\\n}; // team.manager is undefined...\\n...\\ntmpl.link(\\\"#result\\\", team); // Error...\\n```\\n\\nIf you choose *Try it* and change to `$.views.settings.debugMode(false);`, the error will instead be thrown as an exception.\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n
                    \\n\\n\\n\\n\",\r\n \"code\": \"$.views.settings.debugMode(true);\\n\\nvar team = {owner:\\n {name:\\\"Jo\\\"}\\n}; // team.manager is undefined...\\n\\nvar tmpl = $.templates(\\\"#teamTmpl\\\");\\n\\ntmpl.link(\\\"#result\\\", {team: team}); // Error...\",\r\n \"height\": \"80\",\r\n \"title\": \"Debug mode set to true – JsViews\",\r\n \"anchor\": \"datalink\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting debug mode to a string\",\r\n \"text\": \"By setting debug mode to a string rather than to `true`, no exception will be thrown, and the chosen string will be rendered, replacing the rendered tag. \\n\\n```js\\n$.views.settings.debugMode(\\\"Error!\\\");\\n``` \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.settings.debugMode(\\\"Error!\\\"); \\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by `\\\"Error!\\\"`.\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"code\": \"$.views.settings.debugMode(\\\"Error!\\\"); // Do not throw exception - render \\\"Error!\\\"\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"title\": \"Debug mode set to a default string\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In some scenarios the desired behavior may be to ignore errors during rendering, by skipping any tag with an error, rendering it as an empty string. This is achieved very easily, by simply writing:\\n\\n```js\\n$.views.settings.debugMode(\\\"\\\");\\n``` \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n$.views.settings.debugMode(\\\"\\\");\\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is skipped.\"\r\n }\r\n ],\r\n \"title\": \"Debug mode set to empty string\",\r\n \"code\": \"$.views.settings.debugMode(\\\"\\\"); // Do not throw exception - render \\\"\\\"\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a debug mode handler (function)\",\r\n \"text\": \"If debug mode is set to a function, the function will be called each time an error is encountered during rendering. \\n\\n- If the function returns a string, then that string will be rendered, replacing the rendered tag\\n- If the function has no return value, then the error message will be rendered\\n\\n```js\\n$.views.settings.debugMode(myOnErrorHandler);\\n\\nfunction myOnErrorHandler(e, fallback, view) {\\n // This handler will log the error, and then display the empty string\\n console.log(...);\\n return \\\"\\\"; \\n}\\n```\\n\\nThe parameters of the debug mode error handler function -- `myHandler(e, fallback, view)` -- will be:\\n\\n- `e` -- the error object\\n- `fallback` -- the fallback error string, provided by the *[onError fallback](#onerror@onerror)* specified on the tag, if there is one\\n- `view` -- the current view object\\n- The `this` pointer will be the current data item, `view.data`\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:address.street onError='address'}}\\n```\\n\\n```js\\nfunction onErrorHandler(e, fallback, view) {\\n console.log(e.message);\\n if (fallback === \\\"address\\\") {\\n return 'Address error for ' + this.name + '. (\\\"' + e.message + '\\\")';\\n }\\n}\\n```\\n\\n```js\\n$.views.settings.debugMode(onErrorHandler);\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\\n\",\r\n \"code\": \"var team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}},\\n {name: \\\"Jane\\\", address: undefined} // No address\\n ]\\n};\\n\\nfunction onErrorHandler(e, fallback, view) {\\n console.log(e.message);\\n if (fallback === \\\"address\\\") {\\n return 'Address error for ' + this.name + '. (\\\"' + e.message + '\\\")';\\n }\\n}\\n\\n$.views.settings.debugMode(onErrorHandler);\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"title\": \"Debug mode – onError handler\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"116\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advanced debugging, using debugging helpers\",\r\n \"text\": \"***Inserting breakpoints during rendering:***\\n\\nJsRender (and JsViews) provide some helpers for debugging code within compiled templates:\\n\\n- The `{{dbg expression/}}` tag\\n- The `{{dbg: expression}}` converter\\n- The `~dbg(expression)` helper function\\n\\nEach of the above will\\n- evaluate the expression\\n- output a `console.log(...)` call\\n- throw and catch an exception -- which you can use as a break point by *stopping on caught exceptions*\\n- render the evaluated expression\\n\\nThis is done by inserting code into the compiled template which calls into the built-in *dbgBreak* code:\\n\\n```js\\nfunction dbgBreak(val) {\\n try {\\n console.log(\\\"JsRender dbg breakpoint: \\\" + val);\\n throw \\\"dbg breakpoint\\\"; // To break here, stop on caught exceptions.\\n }\\n catch (e) {}\\n```\\n\\n`val` will be the result of evaluating `expression`.\\n\\nWhen rendering execution breaks at the above code, you can then step up through the call stack to the compiled template code, for further debugging.\\n\\nUsage examples: `{{dbg:...}}`, `{{:~dbg(...)}}`, `{{dbg .../}}` etc.\\n\\n***Breakpoints during data linking:***\\n\\nIn JsViews, a breakpoint can also be inserted during template data-linking, as in `{^{for ... onAfterLink=~dbg}}`.\\n\\n___Using {{*debugger}}:___\\n\\nAn alternative (but similar) debugging technique is to use `allowCode` to insert a `debugger;` statement directly into the compiled template code, as follows:\\n\\n*Code:*\\n\\n```js\\nvar tmpl = $.templates({\\n markup: \\\"#myTmpl\\\",\\n allowCode: true // Alternatively use global setting: $.views.settings.allowCode(true)\\n});\\n```\\n\\n*Template:*\\n\\n```jsr\\n...\\n{{*debugger}}\\n...\\n```\",\r\n \"anchor\": \"dbg\"\r\n }\r\n ]\r\n },\r\n \"advanced\": {\r\n \"title\": \"JsRender – advanced topics\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"onerror\",\r\n \"label\": \"Error handling\"\r\n },\r\n {\r\n \"hash\": \"settings/advanced\",\r\n \"label\": \"Advanced settings\"\r\n },\r\n {\r\n \"hash\": \"jsrobjects\",\r\n \"label\": \"JsRender objects\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"apps\": {\r\n \"title\": \"Building apps\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Apps using JsRender\",\r\n \"text\": \"*JsRender* is a simple light-weight templating engine. It can be used in the browser within simple web pages, or within complex single-page apps, or in conjunction with other frameworks. It can also be used on the server, using *Node.js*.\\n\\nIt is highly flexible, expressive, and 'unopinionated' -- so it leaves you free to work within your own choice of overall application architecture (including architectures based on *MVVM*, *MVP* or *MVC* -- optionally with server/client integration), and lets you use your own flavor of data/model layer -- whether simple plain JavaScript objects, hand-coded *View Model* instances, or *[compiled View Models](#viewmodelsapi)*.\\n\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Components of an app using JsRender\",\r\n \"text\": \"Any app or web page using JsRender templates will generally involve defining or registering the following elements:\\n\\n- one or more **templates** -- see *[Templates](#compiletmpl)*\\n- a **'data Layer'** -- see *[JsRender: Data or View Model](#jsrmodel)*\\n- optionally, **helpers** -- in the form of metadata, helper functions and converter functions, see *[Helpers](#helpers)* and *[Converters](#converters)*\\n- optionally, **reusable components** for use within your templates -- see *[Custom tags](#tags)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Apps using JsViews\",\r\n \"text\": \"*JsRender* also provides optional integration with *JsViews*. *JsViews* is much more of a framework than *JsRender*. It does much more than just templating -- providing also data-binding, *MVVM* support, observability of the *data/View Model* layer, support for interactive encapsulated components (*JsViews tag controls*), and more. Nevertheless, it can also interoperate with other frameworks and components. See *[Building apps in JsViews](#jsvapps)* for more information.\"\r\n }\r\n ]\r\n },\r\n \"getindex\": {\r\n \"title\": \"Iterating over arrays: accessing the array index\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If you pass an array to the JsRender [`.render(myArray)`](#rendertmpl) method, or if you use [`{{for myArray}}`](#propstag), in a template, JsRender will iterate over the array, and render an [*item view*](#views@itemview) for each item in the array.\\n\\nWithin an item view you can access the array-index of the current item, using `{{:#index}}`:\\n\\n- *Getting item index within a top-level item view (from `.render(myArray)`)*:\\n\\n ```jsr\\n ...\\n {{:#index}}\\n ...\\n ```\\n\\n- *Getting item index within a `{{for myArray}}` block*:\\n\\n ```jsr\\n {{for myArray}}\\n ...\\n {{:#index}}\\n ...\\n {{/for}}\\n ```\\n\\nIf there are additional nested tags, then from within the nested tags you can still access the index, by using `{{:#getIndex()}}`:\\n\\n- *Getting item index from nested tags within an item view*:\\n\\n ```jsr\\n {{for myArray}}\\n ...\\n {{if ...}}\\n ...\\n {{:#getIndex()}}\\n ...\\n {{/if}}\\n ...\\n {{/for}}\\n ```\\n\\nSee [`index`](#viewobject@index) and [`getIndex()`](#viewobject@getIndex) for additional details.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"contextualparams\": {\r\n \"title\": \"Contextual parameters\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining contextual parameters\",\r\n \"text\": \"*Contextual parameters* provide a very convenient way of passing values in to nested tag contexts. (See *[View hierarchy](#views)*.)\\n\\nA contextual parameter is defined by simply writing `~myValue=...` (for any expression) on any block tag, such as `{{if}}` or `{{for}}`.\\n\\nThe resulting `~myValue` parameter can then be accessed within the block tag -- or deeper down within nested tag contexts, at any depth. \\n\\nFor example, the following template defines three contextual parameters, and uses them in nested contexts:\\n\\n```jsr\\n...\\n{{if isActive ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\\n {{for members}}\\n {{if ~teamIndex>2}}\\n {{:~teamTitle}} {{:~teamData.description}}\\n ...\\n```\\n\\n*Note:* You can also set contextual parameters on `{{else}}` blocks, such as in the following example which uses the same template for the `{{if}}` and `{{else}}` blocks, but assigns different values to the `~teamTitle` parameter in each case:\\n\\n```jsr\\n{{if isActive ~teamTitle=activeTitle tmpl=\\\"teamTmpl\\\"}}\\n{{else ~teamTitle=inactiveTitle tmpl=\\\"teamTmpl\\\"}}\\n{{/if}}\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"itemVar – contextual parameter for data 'item' of block\",\r\n \"text\": \"The *itemVar* feature lets you set up a contextual parameter for the current data 'item' of a block. It is in effect an 'alias' for `#data` within the block.\\n\\nTo define an *itemVar* contextual parameter for a block tag, simply write `itemVar=~someName`. The parameter `~someName` can then be accessed like any other helper variable or contextual parameter, within nested contexts to any depth.\\n\\n```jsr\\n...\\n{{for teams itemVar=\\\"~team\\\"}}\\n ...\\n {{for members itemVar=\\\"~member\\\"}}\\n ...\\n {{if isActive}}\\n {{:~team.title}} {{:~member.name}}\\n```\\n\\nSee also [this sample](#fortag@itemvar).\",\r\n \"anchor\": \"itemvar\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing root data: the built-in '~root' contextual parameter\",\r\n \"text\": \"The built-in contextual parameter `~root` provides direct access to the *root data* which was passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews). It can be accessed from anywhere within a template, at an level of nested tags.\\n\\n*Note:* If an array is passed to `render()` or `link()` then `~root` will be the array (so you can render `{{:root.length}}` for example).\",\r\n \"anchor\": \"root\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"parentdata\": {\r\n \"title\": \"Accessing parent data\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing \\\"parent\\\" data, from nested views. Passing in template variables\",\r\n \"text\": \"When a template (containing nested template tags) is rendered, the result is a [view hierarchy](#views) -- where the views provide information on how the underlying data objects map to the rendered UI.\\n\\nOften it is helpful to be able to access the data for a *parent view* from a [*nested* template](#views@nestedtmpl) or [block](#tagsyntax@blocktag) (*nested view*).\\n\\nThere are several ways to get to *parent data*:\\n\\n- Create a *[contextual parameter](#contextualparams)* to pass a value to nested views.\\n\\n Here are three examples:\\n\\n ```jsr\\n ...\\n {{if ... ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\\n ...\\n {{for ...}}\\n ...\\n {{:~teamTitle}} {{:~teamData.title}} {{:~teamIndex}}\\n ```\\n\\n- Use [`itemVar`](#contextualparams@itemvar) to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \\n\\n ```jsr\\n ...\\n {{for members itemVar=\\\"~member\\\"}}\\n ...\\n {{props}}\\n ...\\n {{:~member.name}}\\n ```\\n\\n- Use the [`view.parent`](#viewobject@parent) property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\\n\\n ```jsr\\n ...\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#parent.parent.data.title}}\\n ```\\n\\n- Use the [`view.get(type)`](#viewobject@get) method to get to a parent view of a given `type`:\\n\\n ```jsr\\n ...\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#get(\\\"if\\\").data.title}}\\n\\n ```\\n\\n- Use the [`view.getIndex()`](#viewobject@getIndex) method to get to the index of a parent *\\\"item\\\"* view:\\n\\n ```jsr\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#parent.getIndex()}}\\n {{:#getIndex()}}\\n ```\\n\\nHere is a sample showing all of these methods:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This sample shows all the ways to get to *parent data* described in the section above:\\n\\n- Create a *contextual parameter* to pass a value to nested views.
                    \\n- Use `itemVar` to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \\n- Use the `view.parent` property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\\n- Use the `view.get(type)` method to get to a parent view of a given `type`:\\n- Use the `view.getIndex()` method to get to the index of a parent *\\\"item\\\"* view:\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \",\r\n \"code\": \"// mytag: custom tag to output \\\"1 member\\\" or \\\"n members\\\"\\n$.views.tags(\\\"mytag\\\", \\\"{{:length == 1 ? '1 member' : length + ' members'}}
                    \\\");\\n// Alternative version of mytag:\\n// $.views.tags(\\\"mytag\\\", \\\"{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
                    \\\");\\n\\nvar teams = [\\n {title: \\\"The A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"The B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"290\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrmodel\": {\r\n \"title\": \"JsRender: Data / View Model\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsRender* is designed to work well with either plain JavaScript objects and arrays, or with instances of JavaScript classes, such as *View Model* classes.\\n\\nSo, for example, if you are using data obtained from a JSON request, you can choose between:\\n- rendering your templates directly against the objects and arrays returned from the JSON request\\n- passing the data through a 'mapping' process to create a hierarchy of *View Model* instances, and rendering your templates against those objects\\n\\nThe *plain objects* [approach](#jsrmodel@plain) is convenient and simple for getting rapidly up and running with templates. But for more complex projects the *View Model* approach is better for creating clean well-designed modular code, where each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using JsRender built-in compiled View Models\",\r\n \"text\": \"*JsRender* will work well with your own 'hand-coded' *View Model* classes (see [below](#jsrmodel@vm)).\\n\\nBut in most cases it is simpler and better to use the [`$.views.viewModels(...)`](#jsrmodel@compilevm) API. This API lets you very easily and rapidly compile *View Model* classes for your own needs, following a standard pattern, and with some additional powerful features:\\n\\n- It provides a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\\n- It also provides a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Data / View Model with JsViews\",\r\n \"text\": \"All of the alternatives mentioned above (plain object hierarchies, hand-coded *View Model* classes, or JsRender *compiled View Model* classes) can also be used with *JsViews* data-binding and observable data. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: JsRender with plain objects and arrays\",\r\n \"text\": \" \"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Suppose this is our data from a JSON request:\",\r\n \"code\": \"var person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"We'll render using a template structured like this:\",\r\n \"markup\": \"... \\n{{:name}}\\n...\\n{{:address.street}}\\n...\\n{{for phones}}\\n ... \\n {{:number}}\\n ...\\n{{/for}}\\n...\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person (plain object)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\\n\"\r\n }\r\n ],\r\n \"html\": \"
                    \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Data: hierarchy of plain objects and arrays\\nvar person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n\\n// Render template against plain object hierarchy\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n\",\r\n \"height\": \"140\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template directly against plain objects...\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Now we'll convert the above sample to use *View Model* classes.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: JsRender with 'hand-coded' View Model objects\",\r\n \"text\": \"We'll convert the data to a corresponding hierarchy of simple 'hand-coded' *View Model* class instances. In each case we will replace properties by simple *getters*, and corresponding 'private' properties. \",\r\n \"anchor\": \"vm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model classes:\",\r\n \"text\": \"Here is the class definition for Person:\\n\\n```js\\n// Constructor\\nfunction Person(name, address, phones) {\\n // Initialize private properties\\n this._name = name;\\n this._address = address;\\n this._phones = phones;\\n}\\n\\n// Prototype\\nvar personProto = {\\n // Define a getter for each property \\n name: function() {\\n return this._name;\\n },\\n address: function() {\\n return this._address;\\n },\\n phones: function() {\\n return this._phones;\\n }\\n};\\n...\\n```\\n\\nWe define exactly similar classes for our Address and Phone objects too.\\n\\nThe above pattern for *View Model* classes will work well with *JsRender*. (It will also work seamlessly with *JsViews* data-binding, if at some point you choose to upgrade to use *JsViews* features).\\n\\n*Note:* The standard JsRender *View Model* pattern provided by `$.views.viewModels` is similar, but provides also setters (along with optional *'observability'* for two-way binding in *JsViews*).\",\r\n \"anchor\": \"handvm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter functions\",\r\n \"text\": \"Note that properties are now getter functions, which return the appropriate value (which may be of any type, including objects or arrays -- such as `address` and `phones` above).\\n\\nIn fact they are particular case of *[computed properties](#paths@computed)* -- a concept that can be used quite generally within *JsRender* and *JsViews*, not only for *View Model* properties.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Template\",\r\n \"text\": \"To convert our template from using plain objects to using *View Model* objects, the only change we need to make is to add parens for our properties, which are now getter functions:\\n\\n```jsr\\n... \\n{{:name()}}\\n...\\n{{:address().street()}}\\n...\\n{{for phones()}}\\n ... \\n {{:number()}}\\n ...\\n{{/for}}\\n...\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Instantiate and render:\",\r\n \"text\": \"Now all we need to do is to construct our root `person` object (with its underlying hierarchy of *View Model* instance objects) and render the template against that object in the usual way.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/mvvm/person-view-models-jsr.js\",\r\n \"label\": \"person-view-models-jsr.js\"\r\n }\r\n ],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n... {{:name()}} ...\\n```\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy\",\r\n \"code\": \"// Use previously defined View Model classes: Person, Address, Phone\\nvar person = new Person(\\n \\\"Pete\\\",\\n new Address(\\n \\\"1st Ave\\\"),\\n [\\n new Phone(\\\"111 111 1111\\\"),\\n new Phone(\\\"222 222 2222\\\")\\n ]\\n );\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                    \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Instantiate View Model hierarchy\\nvar person = new Person(\\n \\\"Pete\\\",\\n new Address(\\\"1st Ave\\\"),\\n [\\n new Phone(\\\"111 111 1111\\\"),\\n new Phone(\\\"222 222 2222\\\")\\n ]\\n );\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\",\r\n \"height\": \"140\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template against a View Model object hierarchy\",\r\n \"anchor\": \"vmsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the same function as both getter and setter\",\r\n \"text\": \"For properties which are read-write, the above *getter* functions can be replaced by a corresponding *getter/setter*, as follows: \\n\\n```js\\nname: function(val) {\\n if (!arguments.length) {\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is a value argument, treat as a setter\\n},\\n```\\n\\nNote that when *JsRender* renders a template using a *get/set* property `{{:name()}}` it will *always call the function as a getter, not as a setter*. However the *setter* feature lets you modify the value of `name()` from code, using:\\n\\n```js\\nsomePerson.name(\\\"newName\\\"); // setter\\n```\\n\\nAlso, if you use the same *View Model* class with *JsViews* then the *setter* will be called:\\n\\n- when the user modifies a value with two-way data-binding such as ``\\n- when using `$.observable(person).setProperty(\\\"name\\\", \\\"newName\\\")` from code
                    \\n(See [JsViews Data/View Model](#jsvmodel) for details, and alternative *setter* patterns.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding methods and computed properties to the View Model \",\r\n \"text\": \"Typically a *View Model* does not only provide *getter* (or *get/set*) properties -- but also other methods or computed properties corresponding to the appropriate logic at that point in the application. For example, a *View Model* for a *Person* might include a `selectPhone(...)` method or a `fullName()` computed property.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: Using JsRender compiled View Models, with $.view.viewModels(...)\",\r\n \"text\": \"The built-in support in both *JsRender* and *JsViews* for compiled *View Models* makes it extremely easy to define *View Model* classes that include *get/set* properties using the pattern described above, along with any desired additional methods and computed properties. Simple calls to `$.views.viewModels(...)` allow you to compile *View Model* classes conforming to these patterns without having to manually write repetitive code for multiple such *get/set* properties.\\n \\nAnother advantage of the compiled *View Model* classes is when working with (or migrating to) *JsViews*. In that context the classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates.\\n\\nFor details on `$.views.viewModels` see: *[Compiled View Models](#viewmodelsapi)*.\\n\\nTo illustrate, let's convert our [sample above](#jsrmodel@vm) to use compiled *View Models*. At the same time we will add a `person.addPhone(...)` custom method to the `Person` *View Model* class, and we'll illustrate calling a setter -- `name(...)`:\",\r\n \"anchor\": \"compilevm\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name()}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"], // get/set properties\\n extend: {addPhone: addPhone} // Additional methods or properties\\n});\\n...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy using constructors\",\r\n \"code\": \"var person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Call setter, call method...\",\r\n \"code\": \"...\\nperson.name(\\\"newName\\\"); // Use the name(...) setter\\n\\n...\\nperson.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n\\n
                    \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(Phone(phoneNo));\\n}\\n\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"],\\n extend: {addPhone: addPhone}\\n});\\n\\n// Compile Address View Model\\nvar Address = $.views.viewModels({getters: [\\\"street\\\"]});\\n\\n// Compile Phone View Model\\nvar Phone = $.views.viewModels({getters: [\\\"number\\\"]});\\n\\n// Instantiate View Model hierarchy using constructors\\nvar person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\",\r\n \"height\": \"190\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template against a hierarchy of compiled View Model objects\",\r\n \"anchor\": \"compilevmsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also the [corresponding sample](#jsvviewmodelsapi@compilevmsample) with JsViews and data-linking (and [this version](#jsvmodel@compilevmsample) with two-way binding).\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"For additional details and scenarios for compiled View Models, see:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"viewmodelsapi\",\r\n \"label\": \"Compiled View Models\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsv-model\",\r\n \"label\": \"JsViews: Data/View Model\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"computed\",\r\n \"label\": \"Computed Observables\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"helpersapi\": {\r\n \"title\": \"Registering helpers: $.views.helpers()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.views.helpers()` is used to register helpers, accessed within templates using the syntax `~myhelper`. See *[Using helpers](#helpers)* for information about what *helpers* are, and some additional ways of providing them to templates.\\n\\nThis topic provides more details.\\n\\nWith `$.views.helpers(...)` you can:\\n- register one or more helpers globally, to be used in any template\\n- add one or more helpers as [private resources](#helpersapi@private) for a parent template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering one or more helpers\",\r\n \"text\": \"\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.helpers(...)\",\r\n \"name\": \"helpers\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of helper - to be used in template path expressions as ~name...\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helper\",\r\n \"type\": \"any type\",\r\n \"optional\": false,\r\n \"description\": \"the helper - a function, object, or value\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers(\\\"format\\\", myFormatFunction);\",\r\n \"description\": \"Register a helper, for use in any template with the syntax:
                    ~name\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedHelpers\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of helper) and values (function, object, or value)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers({\\n format: myFormatFunction,\\n utilities: {},\\n mode: \\\"filtered\\\"\\n});\",\r\n \"description\": \"Register multiple helpers\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example using a 'hierarchy' of helpers...\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example using a 'hierarchy' of helpers...\\n\\n```js\\n$.views.helpers({\\n ...\\n utilities: {\\n maxCount: 23,\\n subtractMax: function(val) {\\n return val - this.maxCount;\\n },\\n errorMessages: {\\n msg1: \\\"not available\\\"\\n }\\n },\\n ...\\n});\\n```\\n\\n```jsr\\n{{:~utilities.subtractMax(sold) > 0\\n ? ~utilities.errorMessages.msg1\\n : \\\"immediate\\\"\\n}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\n$.views.helpers({\\n format: myFormatFunction,\\n utilities: {\\n maxCount: 23,\\n subtractMax: function(val) {\\n return val - this.maxCount;\\n },\\n errorMessages: {\\n msg1: \\\"not available\\\"\\n }\\n },\\n mode: \\\"filtered\\\"\\n});\\n\\nvar html = $(\\\"#myTemplate\\\").render({title: \\\"gizmo\\\", sold: 27});\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"title\": \"Register multiple helpers, including objects, etc.\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding helpers as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.helpers(...)`.\\n\\nIn that way the helper you are registering becomes a 'private helper resource' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"private\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.helpers(namedHelpers[, parentTemplate])\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedHelpers\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of helper) and values (function, object, or value)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these helper(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers({\\n format: myFormatFunction,\\n ...\\n}, parentTemplate);\",\r\n \"description\": \"Add one or more helpers as private resources for a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"helpers\",\r\n \"label\": \"Using helpers\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/helpers\",\r\n \"label\": \"Sample: Passing helpers to template.render()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"helpers\": {\r\n \"title\": \"Using helpers\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering helpers](#helpersapi): The `$.views.helpers()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What are helpers?\",\r\n \"text\": \"JsRender templates are made up of HTML markup, text, and *template tags*. *Template tags* are used to evaluate data-paths or computed expressions, and insert those values into the rendered output.\\n\\nBut often the values you will want to insert are not actually taken from the data, but rather from other parameters or *metadata* which you want to use. And often you will want to process the values, using helper functions or other code, e.g. for converting values to other formats, or for computed values.\\n\\n*Helpers*, in JsRender, refers to any functions, objects, parameters or metadata which you want to provide, in addition to the actual data you passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews).\\n\\nHelpers can also be objects, arrays, etc.\\n\\nYou access helpers by prepending the `~` character. Here are some examples:\\n\\n```jsr\\n{{:~myHelperValue}}\\n{{:~myHelperFunction(name, title)}}\\n{{for ~myHelperObject.mySortFunction(people, \\\"increasing\\\")}} ... {{/for}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Passing in helpers\",\r\n \"text\": \"There are three ways to provide helpers:\\n\\n- Global helpers -- registered using [`$.views.helpers(myHelpers)`](#helpersapi)\\n- Helpers registered for a specific template -- [`$.templates(\\\"mytmpl\\\", {markup: ..., helpers: myHelpers}`](#d.templates@resources)\\n- Helpers passed in on a specific render call -- [`tmpl.render(data, myHelpers)`](#tmplrender@helpers)
                    \\n(Similarly you can [pass helpers](#jsvhelpers-converters) to JsViews `link()` calls)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Contextual parameters\",\r\n \"text\": \"In addition to providing helpers as above, you can also define *[contextual parameters](#contextualparams)* within a template, which you access using the same `~someName` syntax as for regular helpers. \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.views.helpers(myHelpers);\\n```\\n\\n```jsr\\n{{:~format(name, true)}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Global helper: $.views.helpers(...)\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.views.helpers(myHelpers);\\n\\nvar html = $(\\\"#personTemplate\\\").render({name: \\\"Robert\\\"});\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.templates({\\n mytmpl: {\\n markup: \\\"#personTemplate\\\",\\n helpers: myHelpers\\n }\\n});\\n```\\n\\n```jsr\\n{{:~format(name)}}\\n{{:~format(name, true)}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Helper resource for a specific template\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.templates({\\n mytmpl: {\\n markup: \\\"#personTemplate\\\",\\n helpers: myHelpers\\n }\\n});\\n\\nvar html = $.render.mytmpl({name: \\\"Robert\\\"});\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\nvar html = $(\\\"#personTemplate\\\").render(data, myHelpers); \\n```\\n\\n```jsr\\n{{:~format(name, true)}}\\n{{:~format(name)}}\\n```\\n\\nSee [`template.render(...)`](#rendertmpl)\"\r\n }\r\n ],\r\n \"title\": \"Passing helpers with a render() call\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar data = {name: \\\"Robert\\\"};\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\nvar html = $(\\\"#personTemplate\\\").render(data, myHelpers); \\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                    \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering helpers](#helpersapi): The `$.views.helpers()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/helpers\",\r\n \"label\": \"Sample: Passing helpers to template.render()\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"settings/delimiters@passing\",\r\n \"label\": \"Sample: Passing in terms as helpers\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"convertersapi\": {\r\n \"title\": \"Registering converters: $.views.converters()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See *[Using converters](#converters)* for an overview of what *converters* are, and some examples.\\n\\nThis topic provided more details.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using custom or built-in converters\",\r\n \"text\": \"In JsRender, a converter is a convenient way of processing or formatting a data-value, or the result of expression evaluation.\\n\\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \\n\\n```jsr\\n{{html:movie.description}} - This data is HTML encoded\\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\\n\\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\\n```\\n\\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\\n\\n```jsr\\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \\n{{upper:name}} - This uses my 'upper' converter \\n```\\n\\n(See: [sample](#converters@simple).)\\n\\nYou can also use converters with any JsRender tag, not just the `{{: ...}}` tag, using the following syntax:\\n\\n```jsr\\n{{sometag convert='myconverter' ...}}\\n```\\n\\n(See: [sample](#converters@fortag).)\\n\\n***Note:*** With JsViews, you can use converters with two-way data-binding, and you will have a convert and a convertBack converter -- one for each direction.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering converters\",\r\n \"text\": \"`$.views.converters()` is used to register converters.\\n\\nWith `$.views.converters(...)` you can:\\n- register one or more converters globally, to be used in any template\\n- add one or more converters as [private resources](#convertersapi@private) for a parent template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering one or more converters\",\r\n \"text\": \"A simple sample of registering a converter is shown [here](#converters@simple).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.converters(...)\",\r\n \"name\": \"converters\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of converter - to be used in template markup: {{name: ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"converterFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Converter function. Takes val parameter and returns converted value\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n\\n{{upper: \\\"upper case: \\\" + nickname}}\",\r\n \"description\": \"Register a converter\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedConverters\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of converter) and values (converter functions)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters({\\n upper: function(val) {...},\\n lower: function(val) {...}\\n});\",\r\n \"description\": \"Register multiple converters\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding converters as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.converters(...)`.\\n\\nIn that way the converter you are registering becomes a 'private converter resource' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"private\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.converters(...) — adding to parent template\",\r\n \"name\": \"converters\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of converter - to be used in template markup: {{name: ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"converterFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Converter function. Takes val parameter and returns converted value (See API: function converterFn below for details)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this converter is being added as private resource\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters(\\n \\\"upper\\\",\\n function(val) { ... },\\n parentTemplate\\n);\",\r\n \"description\": \"Register a converter as private resources for a parent template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedConverters\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of converter) and values (converter functions)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these converter(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters({\\n upper: function(val) {...},\\n lower: function(val) {...}\\n}, parentTemplate);\",\r\n \"description\": \"Add one or more converters as private resources for a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregister a named converter\",\r\n \"text\": \"To unregister a previously registered converter, pass `null` to `$.views.converters()`:\\n\\n```js\\n$.views.converters(\\\"myCvt\\\", null);\\n// Named converter \\\"myCvt\\\" is no longer registered\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter functions\",\r\n \"text\": \"In most cases a converter function will return a computed value based on the input parameter `val`:\\n\\n```js\\nfunction myConverter(val) {\\n ... \\n return computedVal; // converted/encoded/formatted value for 'val'\\n}\\n```\\n\\nwhere `val` comes from the data value or expression passed to the tag `{{myconverter: someExpression}}`. \\n\\n(See: [sample](#converters@simple).)\\n\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter function signature\",\r\n \"text\": \"However a converter can access multiple [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag. (See for example `{{fullname: first last ...}}`, in the [fullname sample](#converters@fullname).)\\n\\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag parameters](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\\n\\n```js\\nfunction myConverter(arg1, arg2, arg3 ...) {\\n var tag = this;\\n var namedTagParameters = tag.tagCtx.props; \\n ...\\n return computedArg1; // converted value for 'arg1' passed to tag\\n}\\n```\\n\\nHere is the *converterFn* API definition:\",\r\n \"anchor\": \"signature\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"function converterFn(val, ...) {...}\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"val1\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"first tag argument\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"val2\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"additional tag arguments\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"function myConverterFn(val1, val2, ...) {\\n var tag = this;\\n var tagProperties = tag.tagCtx.props;\\n ...\\n return ...;\\n}\\n\\n$.views.converters(\\\"myconverter\\\", myConverterFn);\",\r\n \"description\": \"Converter function:
                    • parameters: one or more tag arguments
                    • this pointer: the tag instance
                    • computes return value: which is passed to tag as first argument
                    \"\r\n }\r\n ],\r\n \"description\": \"A converter function registered using $.views.converters(...)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using converters with other tags\",\r\n \"text\": \"A converter can be used on any tag, thanks to the syntax\\n\\n```jsr\\n{{sometag ... convert=...}}\\n```\\n\\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}` or `{{for}}`.\\n\\nSee the [sample](#converters@fortag) using `{{for people convert='extraItems'}}`, where the converter adds additional items to the array. \\n\\n(***Note:*** This syntax can actually be used with the `{{: ...}}` tag too -- by writing `{{:name convert='upper'}}`...)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: a converter for {{if}}\",\r\n \"text\": \"Here is an advanced sample: an `\\\"inlist\\\"` converter for `{{if}}`.\\n\\n- It accepts an `item` argument and a `list` argument, and an optional `field` *named property*\\n- It returns `true` if the `item` is found in the `list`\\n- If there is a `field` specified, it takes the value of that field (property) on the `item` and searches for it in the `list`\\n\\nNote that the converter gets called once for the first `{{if}}` tag block and once for each subsequent `{{else}}` block.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n ...\\n {{for people}}\\n ...\\n {{if #data ~root.team convert='inlist'}}\\n ...\\n {{else #data ~root.reserve field=\\\"name\\\"}}\\n ...\\n {{else}}\\n ...\\n {{/for}}\\n ...\\n
                  \\n```\\n\\n```js\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}.\\n ... // Return true\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n ... // Return true if found\\n\\n // If no field property, look for the item among the list items\\n ... // Return true if found\\n\\n return false; // Not found\\n}\\n\\n// Register 'inlist' converter just for the 'teamTmpl' template \\n$.views.converters({inlist: inlistConverter}, teamTmpl);\\n```\"\r\n }\r\n ],\r\n \"title\": \"'inlist' converter for {{if}} tag\",\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"var teamTmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}\\n if (!list) {\\n return true; // Final else, so return true\\n }\\n\\n var field = this.tagCtx.props.field;\\n var l = list.length;\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n if (field) {\\n while (l--) {\\n if (item[field] === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n\\n // If no field property, look for the item among the list items\\n else {\\n while (l--) {\\n if (item === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n return false; // Not found\\n}\\n\\n// Register 'inlist' converter just for the 'teamTmpl' template \\n$.views.converters({inlist: inlistConverter}, teamTmpl);\\n\\n// Define model \\nvar model= {people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Liza\\\"},\\n {name: \\\"Eli\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Zoey\\\"}\\n ],\\n // Specify list of reserves, by name\\n reserve: [\\\"Eli\\\", \\\"Liza\\\"]\\n};\\n\\n// Specify array of team members\\nmodel.team = [model.people[0], model.people[3]];\\n\\n$(\\\"#result\\\").html(teamTmpl.render(model));\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"anchor\": \"iftag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helper functions, or dynamically assigning converters\",\r\n \"text\": \"The `convert=...` syntax allows you to assign a converter function without it being registered by name. For example it can be a data method or a helper function -- such as `{{sometag ... convert=~myConverterHelper}}`.\\n\\n(You can do this with the `{{: ...}}` tag too -- by writing `{{: ... convert=~myConverterHelper}}`...)\\n\\nYou can even assign a converter dynamically. For example you can write: `{{sometag ... convert=~getConverter(...)}}`, where the `getConverter()` helper might return either a string (for a converter registered by name) or a function to be used as converter.\\n\\nTo illustrate, here is a modified version of the previous sample, using `{{if ... convert=~getConverter()}}`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Converter function\\nfunction inlistConverter(item, list) { ... }\\n\\n// Helper to dynamically assign converters\\nfunction getConverter() {\\n return inlistConverter; // For this sample just return `inlistConverter` every time\\n}\\n\\n// Register 'getConverter' helper just for the 'teamTmpl' template \\n$.views.helpers(\\\"getConverter\\\", getConverter, teamTmpl);\\n```\\n\\n```jsr\\n{{if #data ~root.team convert=~getConverter()}}\\n ...\\n{{/if}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"var teamTmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}\\n if (!list) {\\n return true; // Final else, so return true\\n }\\n\\n var field = this.tagCtx.props.field;\\n var l = list.length;\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n if (field) {\\n while (l--) {\\n if (item[field] === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n\\n // If no field property, look for the item among the list items\\n else {\\n while (l--) {\\n if (item === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n return false; // Not found\\n}\\n\\n// Helper to dynamically assign converters\\nfunction getConverter() {\\n return inlistConverter; // For this sample just return `inlistConverter` every time\\n}\\n\\n// Register 'getConverter' helper just for the 'teamTmpl' template \\n$.views.helpers(\\\"getConverter\\\", getConverter, teamTmpl);\\n\\n// Define model \\nvar model= {people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Liza\\\"},\\n {name: \\\"Eli\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Zoey\\\"}\\n ],\\n // Specify list of reserves, by name\\n reserve: [\\\"Eli\\\", \\\"Liza\\\"]\\n};\\n\\n// Specify array of team members\\nmodel.team = [model.people[0], model.people[3]];\\n\\n$(\\\"#result\\\").html(teamTmpl.render(model));\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"title\": \"Dynamically assigning a converter\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in converters:\",\r\n \"text\": \"JsRender has the following built-in converters/encoders:\\n\\n- Built-in HTML encoder: [`{{html: ...}}`](#convertersapi@html) -- accessed programmatically as [`$.views.converters.html()`](#convertersapi@html)\\n- Built-in attribute encoder: [`{{attr: ...}}`](#convertersapi@attr) -- accessed programmatically as [`$.views.converters.attr()`](#convertersapi@attr)\\n- Built-in URL encoder: [`{{url: ...}}`](#convertersapi@url) -- accessed programmatically as [`$.views.converters.url()`](#convertersapi@url)\\n- Basic [encode/unencode converters](#convertersapi@encode)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in HTML encoder\",\r\n \"text\": \"JsRender includes an HTML encoder, which you can use programmatically as follows:\\n\\n```js\\nvar myHtmlEncodedString = $.views.converters.html(myString);\\n```\\n\\nThe same encoder is accessed declaratively as a converter, as in the following two examples:\\n\\n```jsr\\n{{html:myExpression}}\\n\\n{{>myExpression}}\\n```\\n\\nIn fact [`{{>...}}`](#htmltag) is exactly equivalent to `{{html:...}}` and is provided as a simpler syntax for HTML encoding values taken from data or from expressions and rendered within HTML content. \\n\\n(***Note:*** the [`{{> ...}}`](#htmltag) tag should be used in place of the [`{{: ...}}`](#assigntag) tag whenever the data being rendered is not full trusted -- in order to prevent HTML injection attacks.)\",\r\n \"anchor\": \"html\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\n\\nvar result = $.views.converters.html(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\nvar result = $.views.converters.html(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the HTML encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"HTML encoder\",\r\n \"name\": \"html\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"HTML-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be HTML-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Encodes according to the following scheme:\\n

                  \\n`&` → `&`
                  \\n`<` → `<`
                  \\n`>` → `>`
                  \\n`\\\\x00` → `�`
                  \\n`'` → `'`
                  \\n`\\\"` → `"`
                  \\n\\\\` → ```
                  \\n`=` → `=`\\n\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.html;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the HTML-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in attribute encoder\",\r\n \"text\": \"JsRender includes an encoder intended for use when attribute encoding is needed. You can use it programmatically as follows:\\n\\n```js\\nvar myAttributeEncodedString = $.views.converters.attr(myString);\\n```\\n\\nThe same encoder is accessed by declaratively as a converter:\\n\\n```jsr\\n{{attr:myExpression}}\\n```\\n\\nA typical use case would be to encode an HTML attribute value in a template:\\n\\n```jsr\\n
                  ...
                  \\n```\",\r\n \"anchor\": \"attr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\n\\nvar result = $.views.converters.attr(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" & =\\\";\\nvar result = $.views.converters.attr(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the 'attribute' encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"Attribute encoder\",\r\n \"name\": \"attr\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"Attribute-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be attribute-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Encodes according to the following scheme:\\n

                  \\n`&` → `&`
                  \\n`<` → `<`
                  \\n`>` → `>`
                  \\n`\\\\x00` → `�`
                  \\n`'` → `'`
                  \\n`\\\"` → `"`
                  \\n\\\\` → ```
                  \\n`=` → `=`\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note that this scheme encodes more characters than is sometimes the case for attribute encoding. In fact currently `{{attr: ...}}` and `{{html: ...}}` are equivalent. This ensures that using attribute encoding when HTML encoding should have been used will not expose an injection attack risk from untrusted data.\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.attr;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the attribute-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in URL encoder\",\r\n \"text\": \"JsRender includes a URL encoder, which you can use programmatically as follows:\\n\\n```js\\nvar myUrlEncodedString = $.views.converters.url(myString);\\n```\\n\\nThe same encoder is accessed by declaratively as a converter:\\n\\n```jsr\\n{{url:myExpression}}\\n```\\n\\nA typical use case would be to encode a HTML URL attribute value in a template:\\n\\n```jsr\\n\\n```\",\r\n \"anchor\": \"url\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"<_>_\\\\\\\"_ \\\";\\n\\nvar result = $.views.converters.url(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"<_>_\\\\\\\"_ \\\";\\nvar result = $.views.converters.url(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the 'url' encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"URL encoder\",\r\n \"name\": \"url\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"URL-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be URL-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Internally encodes by calling the JavaScript function `encodeURI`.\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.url;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the URL-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Minimalist HTML encode/unencode converters\",\r\n \"text\": \"\\nIn addition JsRender and JsViews provide encode/unencode converters for minimal encoding to prevent HTML injection (see the JsViews topic: [*Encoding to avoid XSS*](#link2way@encode)), by encoding just `<` `>` and `&` by the corresponding HTML entities, and for unencoding back from entities to characters:\\n\\n`&` ↔ `&`
                  \\n`<` ↔ `<`
                  \\n`>` ↔ `>`
                  \\n\\n*Usage:*\\n\\n```js\\nencodedValue = $.views.converters.encode(unencodedValue);\\nunencodedValue = $.views.converters.unencode(encodedValue);\\n```\\n\\n*Declarative usage:*\\n\\n```jsr\\n{{encode:myExpression}}\\n```\",\r\n \"anchor\": \"encode\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Converters and encoding sample\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsapi@bindto\",\r\n \"label\": \"Custom tags: The bindTo / bindFrom options and converters\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"converters\": {\r\n \"title\": \"Using converters\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What are converters?\",\r\n \"text\": \"In JsRender, a converter is a convenient way of processing or formatting data-value, or the result of expression evaluation.\\n\\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \\n\\n```jsr\\n{{html:movie.description}} - This data is HTML encoded\\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\\n\\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\\n```\\n\\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\\n\\n```jsr\\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \\n{{upper:name}} - This uses my 'upper' converter \\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in converters\",\r\n \"text\": \"JsRender has the following built-in converters -- based on encoders:\\n\\n- Built-in HTML encoder: [`{{> ...}}`](#convertersapi@html)\\n- Built-in attribute encoder: [`{{attr ...}}`](#convertersapi@attr)\\n- Built-in URL encoder: [`{{url ...}}`](#convertersapi@url)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering a converter\",\r\n \"text\": \"You can register your own custom converters, using [`$.views.converters()`](#convertersapi) as in:\\n\\n```js\\n$.views.converters(\\\"upper\\\", function(val) {\\n // Convert data-value or expression to upper case\\n return val.toUpperCase();\\n});\\n```\\n\\nTo use the `\\\"upper\\\"` converter with the [`{{:...}}`](#assigntag) tag, you write:\\n\\n```jsr\\n{{upper:...}}\\n```\\n\\nHere it is in a sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n```\\n\\n```jsr\\nName: {{:name}}. Upper case nickname: {{upper:nickname}}\\n...\\n{{upper: \\\"This will be upper case too\\\"}} \\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n\\nvar person = {name: \\\"Robert\\\", nickname: \\\"Bob\\\"};\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                  \\n\\n\",\r\n \"height\": \"80\",\r\n \"title\": \"A simple converter\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"simple\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter arguments\",\r\n \"text\": \"A converter can access any number of [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag:\\n\\n```js\\n$.views.converters(\\\"myConverter\\\", function(arg1, arg2, arg3 ...) {\\n```\\n\\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag parameters](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\\n\\nThe following sample shows a `\\\"fullname\\\"` converter, which provides a computed ***full name*** based on the first two tag arguments (*first* and *last*) and an optional named tag parameter `reverse=true`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters(\\\"fullname\\\", function(first, last) {\\n var reverse = this.tagCtx.props.reverse; \\n if (reverse) {\\n return last.toUpperCase() + \\\" \\\" + first;\\n }\\n return first + \\\" \\\" + last;\\n});\\n```\\n\\n```jsr\\n... {{fullname:first last}}\\n... {{fullname:first last reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"$.views.converters(\\\"fullname\\\", function(first, last) {\\n var reverse = this.tagCtx.props.reverse; \\n if (reverse) {\\n return last.toUpperCase() + \\\" \\\" + first;\\n }\\n return first + \\\" \\\" + last;\\n});\\n\\nvar person = {first: \\\"Xavier\\\", last: \\\"Prieto\\\"};\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"80\",\r\n \"title\": \"Full name converter – accessing multiple arguments\",\r\n \"anchor\": \"fullname\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using converters with other tags\",\r\n \"text\": \"A converter can be used on any tag, thanks to the syntax\\n\\n```jsr\\n{{sometag ... convert=...}}\\n```\\n\\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}`.\\n\\n(*Note:* When using JsViews [two-way binding](#link2way@converters), similar syntax is available for *convertBack*: `convertBack=...`.)\\n\\nFor example, you could register an `\\\"inList\\\"` converter which returns true if `item` is found in `itemList` (see [sample](#convertersapi@iftag)):\\n\\n```jsr\\n{{if convert='inList' item itemList}}...{{/if}}\\n``` \\n\\nThe following sample shows the `{{for ...}}` tag used with a named converter which returns the array with additional appended and prepended items:\",\r\n \"anchor\": \"othertags\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters({\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n});\\n```\\n\\n```jsr\\n{{for people convert='extraItems'}}\\n ...\\n```\\n\\n\\n\"\r\n }\r\n ],\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"$.views.converters({\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n});\\n\\nvar model= {people: [\\n {name: \\\"Jo1\\\"},\\n {name: \\\"Jo2\\\"},\\n {name: \\\"Jo3\\\"}\\n]};\\n\\nvar html = $(\\\"#myTmpl\\\").render(model);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"Using converters with the {{for}} tag\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"anchor\": \"fortag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helper functions or data methods as converters\",\r\n \"text\": \"The `convert=...` syntax not only works on any tag, but also allows you to use not only registered converters, by name, as in\\n\\n```jsr\\n{{for people convert='odd'}}\\n```\\n\\nbut alternatively to use helpers, or data methods as in\\n\\n```jsr\\n{{for people convert=utility.extraItems}} // Using data method\\n```\\n\\nYou can also use that approach on `{{:..}}` tags as in\\n\\n```jsr\\n{{:name convert=~hlp.bold}} // Using a helper\\n```\\n\\nNote that the one tag which does not support this syntax is `{{>...}}` -- for which you would need instead to write:\\n\\n```jsr\\n{{>~hlp.bold(name)}} // Using helper \\n```\\n\\nHere is a modified version of the sample above, using helpers and data methods:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n{{for people convert=utility.extraItems}} {{!-- using data method --}}\\n
                1. \\n {{:name convert=~hlp.bold}} {{!-- using helper --}}\\n...\\n```\"\r\n }\r\n ],\r\n \"code\": \"var helpers = {\\n hlp: {\\n bold: function(val) {\\n return \\\"\\\" + val + \\\"\\\";\\n }\\n }\\n};\\n\\nvar model= {people: [\\n {name: \\\"Jo1\\\"},\\n {name: \\\"Jo2\\\"},\\n {name: \\\"Jo3\\\"}\\n ],\\n utility: {\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n }\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(model, helpers);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                  \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"convertersapi\",\r\n \"label\": \"Registering converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"link2way\",\r\n \"label\": \"Two-way binding (JsViews)\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also the following sample:\",\r\n \"text\": \"[Converters and encoding](#samples/jsr/converters)\\n\"\r\n }\r\n ]\r\n },\r\n \"nojqueryapi\": {\r\n \"title\": \"JsRender without jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender can be loaded in the browser with or without jQuery, as in these example pages:\\n\\n- [JsRender with jQuery](#download/pages-jsr-jq)\\n- [JsRender without jQuery](#download/pages-jsr)\\n\\nWhen jQuery is present:\\n\\n- JsRender loads as a jQuery plugin and adds APIs to the `jQuery` global namespace object -- usually aliased as `var $ = jQuery;`\\n- The JsRender APIs are\\n - `$.views...`\\n - `$.templates(...)`\\n - `$.render...`. \\n\\nIf jQuery is not present:\\n\\n- JsRender automatically creates its own `jsrender` global namespace variable \\n- JsRender APIs are the same as above, but they are now associated with the `jsrender` namespace variable: \\n - `jsrender.views...`\\n - `jsrender.templates(...)`\\n - `jsrender.render...`. \\n\\nFor convenience you can follow the jQuery approach of creating a global `$` -- set this time to `var $ = jsrender;`\\n\\nYou can then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy code from the regular browser examples/samples -- *as if* using JsRender with jQuery.\\n\\nFor example:\\n\\n```js\\nvar $ = jsrender; // Alias for the jsrender namespace object - referenced for convenience as var $\\n\\nvar tmpl = $.templates('Name: {{:first}} {{upper:last'); // Compile template from string\\n\\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\\n \\nvar data = {first: 'Jo', last: 'Ryan'};\\n\\nvar html = tmpl.render(data);\\n// result: \\\"Name: Jo RYAN\\\" \\n```\\n\\n***Note:*** The same approach can be used when using [JsRender on the server](#node/install@apis) with Node.js, where JsRender is also being used without jQuery. \"\r\n }\r\n ]\r\n },\r\n \"node/webpack\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Webpack support for JsRender and JsViews\\n JsRender and JsViews can be loaded using [webpack](https://webpack.github.io/).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender as a webpack module\",\r\n \"text\": \"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the webpack client script bundle, and loaded in the browser.\\n\\nThere are three options for loading JsRender in the browser as a webpack module:\\n\\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the webpack client script bundle:\\n ```js\\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\\n ```\\n- Load both jQuery and JsRender as modules in the webpack client script bundle:\\n ```js\\n var $ = require('jquery'); // Load jQuery as a module\\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\n ```\\n- Load JsRender as a module in the webpack client script bundle, without loading jQuery at all:\\n ```js\\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\\n ```\\n\\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \\n\\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \\n\\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\",\r\n \"anchor\": \"jsrender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded globally:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n \\n\\n
                  \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded as module:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                  \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar $ = require('jquery'); // Load jQuery as a module\\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – JsRender without jQuery:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                  \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\\nvar tmpl = jsrender.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\ndocument.querySelector('#container').innerHTML = html;\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsViews as a webpack module\",\r\n \"text\": \"JsViews can also be included in the webpack client-script bundle, and loaded in the browser.\\n\\nAfter installing on the server (using `$ npm install jsviews`), call:\\n\\n```js\\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\\n```\\n\\nor -- if also loading jQuery as a webpack module, use:\\n\\n```js\\nvar $ = require('jquery');\\n...\\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as parameter)\\n```\",\r\n \"anchor\": \"jsviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also:\",\r\n \"text\": \"*[Browserify support](#node/browserify)*\"\r\n }\r\n ]\r\n },\r\n \"viewmodelsapi\": {\r\n \"title\": \"Compiled View Models, using $.views.viewModels()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This topic provides details on using `$.views.viewModels()` to register/compile *View Models*.\\n\\nThis is the third of the alternative approaches discussed in *[Data / View Models](#jsrmodel)* -- namely:\\n- [using](#jsrmodel@plain) plain objects\\n- [using](#jsrmodel@vm) 'hand-coded' View Models\\n- [using](#jsrmodel@compilevm) `$.views.viewModels()` to compile and register View Models with specific *get/set* properties and methods.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advantages of compiled View Models\",\r\n \"text\": \"Using `$.views.viewModels()` to compile *View Models* brings some important advantages over plain object hierarchies or 'hand-coded' *View Models*:\\n\\n- Simple calls to `$.views.viewModels(...)` allow you to compile these *View Model* classes without having to manually write repetitive code for multiple such *get/set* properties\\n- Using compiled *View Models* rather than plain objects makes it easier to have clean well-designed modular code, since each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state\\n- The compiled *View Models* provide a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\\n- They also provide a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server\\n- When working with (or migrating to) *JsViews* the compiled classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates. Updates to the *View Model* hierarchy, and calls to the *View Model* setters both trigger observable changes, with corresponding incremental updates to the *Views*. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using compiled View Models\",\r\n \"text\": \"The basic *use scenarios* of compiled *View Models* are as follows:\\n- Using `$.views.viewModels(...)` to [register/compile](#viewmodelsapi@compile) *View Models* (`myVM`)\\n- Using a compiled View Model `myVM` as [constructor/factory](#viewmodelsapi@construct) method -- `MyVM(...)` -- to create View Model instances (`myVmInstance`)\\n- Using `MyVM.map(...)` to [convert](#viewmodelsapi@map) a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances\\n- Using `myVMInstance.merge(...)` to incrementally [update](#viewmodelsapi@merge) a *View Model* hierarchy, using updated plain data\\n- Using `myVMInstance.unmap()` to [convert](#viewmodelsapi@unmap) a *View Model* hierarchy back to a plain object hierarchy\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"API: $.views.viewModels(...)\",\r\n \"text\": \"To register a *View Model*, you call the `$.views.viewModels(...)` API -- with four alternative signatures:\\n- `var MyVM = $.views.viewModels(viewModelOptions);`
                  returning a compiled *View Model* \\n- `$.views.viewModels(\\\"MyVM\\\", viewModelOptions);`
                  registering a named *View Model*, accessible as `$.views.viewModels.MyVM`\\n- `$.views.viewModels(namedViewModels);`
                  where `namedViewModels` is a hash, declaring multiple *View Models*\\n- `$.views.viewModels(namedViewModels, myViewModels);`
                  where `namedViewModels` is a hash, declaring multiple *View Models* and `myViewModels` is a *View Models* collection (hash) which will provide access to the compiled *View Models*, as `myViewModels.MyVM`\\n\\nIn each case, the compiled *View Model* is specified by a `viewModelOptions` object, with a `getters: gettersArray` (specifying an array of *get/set* properties), and/or an `extend: extendObject` (specifying additional methods or properties).\\n\\nExample:\\n\\n```js\\nvar Book = $.views.viewModels({ // Compile a Book View Model\\n getters: [\\\"title\\\", \\\"price\\\"], // getters array - signature of constructor\\n extend: { // extend object - additional methods \\n placeOrder: function() { ... }\\n }\\n});\\n\\nvar book1 = Book(\\\"Hope\\\", \\\"1.50\\\"); // Construct a Book View Model instance\\nbook.price(\\\"2.50\\\"); // Modify price\\nbook.placeOrder(); // Call method\\n```\\n\",\r\n \"anchor\": \"compile\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.viewModels(...)\",\r\n \"name\": \"viewModels\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModelOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A viewModelOptions object which can include:
                  • a 'getters' array (details below)
                  • an 'extend' hash - with additional methods or properties
                  • an 'id' specifier
                  \"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var Book = $.views.viewModels({\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n\\nvar bk1 = Book(\\\"Hope\\\", \\\"$1.50\\\");\",\r\n \"description\": \"Return a compiled View Model (constructor/factory method) with specific get/set properties and methods\",\r\n \"returns\": \"View Model constructor\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered View Model\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModelOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A viewModelOptions object which can include:
                  • a 'getters' array (details below)
                  • an 'extend' hash - with additional methods or properties
                  • an 'id' specifier
                  \"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.viewModels(\\\"Book\\\", {\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n\\nvar bk1 = $.views.viewModels.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Register (and return) a named View Model\",\r\n \"returns\": \"View Model constructor\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedViewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"hash of viewModelOptions objects - each of which can include:
                  • a 'getters' array (details below)
                  • an 'extend' hash - with additional methods or properties
                  • an 'id' specifier
                  \"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.viewModels({\\n Book: {getters: [\\\"title\\\", \\\"price\\\"]},\\n ...\\n});\\n\\nvar bk1 = $.views.viewModels.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Register multiple named View Models\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedViewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"hash of viewModelOptions objects - each of which can include:
                  • a 'getters' array (details below)
                  • an 'extend' hash - with additional methods or properties
                  • an 'id' specifier
                  \"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"View Model collection object (hash)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Specifying **viewModelOptions** – details:*\\n\\n- The (optional) `getters` array.
                  -- Each item in the array corresponds to a *get/set* property (and also a constructor argument, which initializes that *get/set* property).
                  -- It must be either\\n - a string -- the `getterName`, or\\n - an object, which must have a *getter* property: `{getter: getterName}`.

                  If an object, it can additionally specify:

                  \\n - a *type* property: `type: viewModelName` -- specifying the name of another *View Model* type (declared in the same View Model collection). In this case then when using `map()` to map from data to a generated *View Model* hierarchy (see below), data values for the *get/set* property will be mapped to instances of that *View Model*.\\n - a *defaultVal* property -- specifying the value to be used at initialization if `undefined` -- such as\\n - `defaultVal: null` (a value) or,\\n - `defaultVal: function() { return ...; }` (a function, to return a computed value. The this pointer is the data item.) \\n- The (optional) `extend` hash has additional members (methods or properties) to be included in the View Model prototype. The prototype will extend this object\\n- The (optional) `id` is either a string (the name of a *View Model* property to be treated as **id**) or\\na function. The specified *id* or the function call will be used for determining identity when `merge(...)` updates a *View Model* hierarchy (see below)\"\r\n }\r\n ],\r\n \"example\": \"var myVms = {};\\n\\n$.views.viewModels({\\n Book: {getters: [\\\"title\\\", \\\"price\\\"]},\\n ...\\n}, myVms);\\n\\nvar bk1 = myVms.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Add one or more named View Models to a View Model collection (hash)\",\r\n \"returns\": \"View Model collection (hash)\"\r\n }\r\n ],\r\n \"description\": \"Register one or more View Models\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Creating View Model instances, using the View Model constructor\",\r\n \"text\": \"*View Models* compiled/registered/returned by `$.view.viewModels(...)` are in fact constructors for instances of the *View Model* class.\\n\\n```js\\nvar Book = $.views.viewModels({ // Constructor\\n getters: [\\\"title\\\", \\\"price\\\"] // getters array - signature of constructor\\n ...\\n});\\n\\nvar book1 = Book(\\\"Hope\\\", \\\"$1.50\\\"); // Create Book instance\\n```\\n\\nNote that:\\n- The `new` keyword is not necessary when calling the constructor. (It is in effect a factory method, that calls `new` internally.)\\n- The signature of the constructor call (parameters used to initialize the instance) corresponds to the array of getters specified in the `viewModelOptions` - in this case `[\\\"title\\\", \\\"price\\\"]`\",\r\n \"anchor\": \"construct\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model hierarchies\",\r\n \"text\": \"The `Book` View Model example above has simple *get/set* properties `[\\\"title\\\", \\\"price\\\"]` which are simple primitive types (string in this case).\\n\\nBut consider the `Person` *View Model*, used in the overview topic *[Data / View Model](#jsrmodel)*. Here a `person` object (whether a plain object or a *View Model* instance) is in fact a hierarchy of objects, since the `address` and `phones` properties of a `Person` are themselves objects (an `Address` object and a `Phone` array)\\n\\nHere is a `person` plain object/hierarchy (obtained perhaps by 'evaluating' JSON data from the server): \\n\\n```js\\nvar person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n```\\n\\nTo map this object hierarchy to the corresponding *View Model* hierarchy we need to define three *View Models*:\\n\\n```js\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"],\\n extend: {addPhone: addPhone}\\n});\\n\\n// Compile Address View Model\\nvar Address = $.views.viewModels({getters: [\\\"street\\\"]});\\n\\n// Compile Phone View Model\\nvar Phone = $.views.viewModels({getters: [\\\"number\\\"]});\\n```\\n\\nWe can then instanciate the corresponding *View Model* hierarchy, using constructors:\\n\\n```js\\nvar person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n```\\n\\nSee the [sample](#jsrmodel@compilevmsample) in the *[Data / View Model](#jsrmodel)* topic.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Creating View Model instances by mapping from data\",\r\n \"text\": \"The process of manually writing code to map from JSON data to a corresponding *View Model* hierarchy, as above, can be complex and inconvenient. It requires traversing the data hierarchy and using appropriate *View Model* constructors to instantiate corresponding *View Model* instances. \\n\\nFortunately *JsRender/JsViews* compiled *View Models* provide a `map(data)` feature which when used together with *View Model* typed hierarchies makes this process quite trivial.\\n\",\r\n \"anchor\": \"map\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"API: MyViewModel.map(...)\",\r\n \"text\": \"Any compiled *View Model*, `MyViewModel`, provides a `MyViewModel.map(...)` method, which can be used to convert a plain object or an array of plain objects (or the equivalent JSON string) to the corresponding *View Model* instance (or array of *View Model* instances).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"MyViewModel.map(...)\",\r\n \"name\": \"map\",\r\n \"object\": \"MyViewModel\",\r\n \"method\": true,\r\n \"returns\": \"View Model instance or array or instances\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object, array of objects, or JSON string\",\r\n \"optional\": false,\r\n \"description\": \"The data (typically from JSON request)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"// View Model\\nvar Person = $.views.viewModels.Person;\\n\\n// View Model instance\\nvar person = Person.map(personData);\",\r\n \"description\": \"Generate a View Model instance/hierarchy/array by mapping from data (a plain object instance/hierarchy/array, or JSON string)\"\r\n }\r\n ],\r\n \"description\": \"Generate a View Model hierarchy from data\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Example:\\n\\n```js\\nvar Book = $.views.viewModels({ // Constructor\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n```\\n\\nMap from `bookData` plain object to `book` View Model instance:\\n\\n```js\\nvar bookData1 = {title: \\\"Hope\\\", price: \\\"$1.50\\\"}; // book (plain object)\\nvar book1 = Book.map(bookData1); // book (instance of Book View Model)\\n```\\n \\nMap from `bookDataArray` array of plain objects to `bookArray` array of View Model instances:\\n\\n```js\\nvar bookDataArray1 = [ // book array (plain objects)\\n {title: \\\"Hope\\\", price: \\\"$1.50\\\"},\\n {title: \\\"Courage\\\", price: \\\"$2.50\\\"}\\n];\\nvar booksArray1 = Book.map(bookDataArray1); // book array (instances of Book View Model)\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model typed hierarchies\",\r\n \"text\": \"When specifying `getters` in the `$.views.viewModels(...)` call, you can declare the type of a *get/set* property. For example an `address` *get/set* property can be specified as being of type `Address` -- where `Address` is another *View Model* declared on the same collection.\\n\\nBy specifying View Model types for properties (and declaring those View Models in the same collection) you obtain a *'View Model typed hierarchy'*.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using MyViewModel.map(...) to map a whole object hierarchy to a View Model instance hierarchy\",\r\n \"text\": \"In the case of a *'View Model typed hierarchy'*, simply pass the top-level plain object to the `map()` method for the top-level *View Model* class, and all *View Model* instances in the hierarchy will be correctly instantiated:\\n\\n*Compile View Model classes (typed hierarchy):* \\n\\n```js\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // Declare 'name' as being a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // Declare 'address' as being an Address (View Model) type\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Declare 'phones' as being (an array) of Phone (View Model) types\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone: ...\\n});\\n```\\n\\n*Person data (plain object hierarchy, or JSON string):*\\n\\n```js\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, ...]\\n };\\n```\\n\\n*Use map() to convert from `personData` plain object hierarchy (or JSON string) to `person` *View Model* hierarchy:*\\n\\n```js\\nvar person = $.views.viewModels.Person.map(personData);\\n```\\n\\nThe getter properties then let you traverse the hierarchy, call methods, etc.\\n\\n```\\nperson.name(\\\"newName\\\"); // Use setter: change name\\nperson.addPhone(...); // Call method: add phone\\nvar phone2 = person.phones()[1].number(); // Traverse and use getter: get number\\n```\\n\\nLet's modify the [sample](#jsrmodel@compilevmsample) in *[Data / View Model](#jsrmodel)* to use the `map(...)` approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name()}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: ...\\n Phone: ...\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy using Person.map(data)\",\r\n \"code\": \"var personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\nvar person = vmCollection.Person.map(personData);\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Call setter, call method...\",\r\n \"code\": \"...\\nperson.name(\\\"newName\\\"); // Use the name(...) setter\\n\\n...\\nperson.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n\\n
                  \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone:{\\n getters: [\\\"number\\\"]\\n }\\n});\\n\\nvar vmCollection = $.views.viewModels;\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(vmCollection.Phone(phoneNo));\\n}\\n\\n// person plain object hierarchy:\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\n// Instantiate View Model hierarchy using map()\\nvar person = vmCollection.Person.map(personData);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\",\r\n \"height\": \"190\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Using map() to convert from a plain object hierarchy to a View Model hierarchy\",\r\n \"anchor\": \"mapsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also the [corresponding sample](#jsvviewmodelsapi@mapsample) with JsViews and data-linking.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Along with the map() feature – merge() and unmap()\",\r\n \"text\": \"When working with View Model typed hierarchies, there are two additional features that can be used together with the `map()` feature:\\n\\n- If later you obtain updated JSON data, `personData2`, you can use `merge()` ([below](#viewmodelsapi@merge)) to trigger an incremental update to the *View Model* hierarchy:\\n ```js\\n person.merge(personData2);\\n ```\\n- If values are modified (using setters, or methods) you can at any time can use `unmap()` ([below](#viewmodelsapi@unmap)) to convert back to plain data, but with updated values:\\n ```js\\n var updatedPersonData = person.unmap();\\n ```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using myVMobjectOrArray.merge(...) to update a View Model hierarchy\",\r\n \"text\": \"If a *View Model* hierarchy (or array of *View Model* instances) was created using the `map()` feature above to map from data, then the *View Model* instances (and arrays) will each have a `merge()` method available:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.merge(personData2); // Incrementally update person (hierarchy)\\n```\\n\\nor for an array:\\n\\n```js\\nvar peopleArray = Person.map(peopleDataArray1);\\npeopleArray.merge(peopleDataArray2); // Incrementally update people array\\n```\\n\\nOr, deeper in the hierarchy:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.phones.merge(phonesDataArray2); // Update just the person.phones array\\n```\",\r\n \"anchor\": \"merge\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Updating with merge() makes minimal incremental changes, and preserves state\",\r\n \"text\": \"Note that the `merge()` update process does not replace the whole hierarchy of *View Model* instances, but works incrementally to add/remove/modify instances as appropriate. So if most of the data in `personData2` is the same as `personData1`, calling `merge(personData2)` will make only minimal changes to the hierarchy. \\n\\nThis means that if *View Model* instances have state (such as additional properties that were set programmatically and are not driven by data) then that state can be maintained across the `merge()` update. \"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"myVMobjectOrArray.merge(...)\",\r\n \"name\": \"merge\",\r\n \"object\": \"myVMobjectOrArray\",\r\n \"method\": true,\r\n \"returns\": \"View Model instance or array\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object, array of objects, or JSON string\",\r\n \"optional\": false,\r\n \"description\": \"The updated data (typically from JSON request)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"person.merge(personData2);\\n// person (View Model hierarchy) has now\\n// been updated, with modified data...\",\r\n \"description\": \"Update a previously generated View Model instance/hierarchy/array by mapping from updated data\"\r\n }\r\n ],\r\n \"description\": \"Update a View Model hierarchy, from modified data\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using myVMobjectOrArray.unmap() to convert back to a plain object hierarchy\",\r\n \"text\": \"If a *View Model* hierarchy (or array of *View Model* instances) was created by mapping from data, using the `map()` feature above, then the View Model instances (and arrays) will each have an `unmap()` method (in addition to the `merge()` method mentioned above):\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.addPhone(newPhone);\\nperson.name(newName)\\nvar modifiedPersonData = person.unmap(); // Convert back to a plain object hierarchy\\n```\\n\\nor for an array:\\n\\n```js\\nvar peopleArray = Person.map(peopleDataArray1);\\npeopleArray[1].address.street(newStreet) // Make changes anywhere in the peopleArray\\nvar modifiedPeopleDataArray = people.unmap(); // Convert back to a plain object array\\n```\\n\\nOr, deeper in the hierarchy:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.addPhone(newPhone);\\nvar modifiedPhonesArray = person.phones.unmap(); // Get a plain object array for person.phones\\n```\",\r\n \"anchor\": \"unmap\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"myVMobjectOrArray.unmap()\",\r\n \"name\": \"unmap\",\r\n \"object\": \"myVMobjectOrArray\",\r\n \"method\": true,\r\n \"returns\": \"object or array\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"// Convert back to a plain object hierarchy\\nvar modifiedPersonData = person.unmap();\\n\",\r\n \"description\": \"Obtain an updated plain object instance/hierarchy/array, from a previously generated View Model instance/hierarchy/array\"\r\n }\r\n ],\r\n \"description\": \"Get a plain object hierarchy from a View Model hierarchy\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an updated version of our [previous](#viewmodelsapi@mapsample) sample, where now we have added the use of `merge()` and `unmap()`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: ...\\n Phone: ...\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy, using map()\",\r\n \"code\": \"var personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\nvar person = vmCollection.Person.map(personData);\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Update View Model hierarchy, using merge()\",\r\n \"code\": \"$(\\\"#update\\\").on(\\\"click\\\", function() {\\n person.merge(personData2); // Update person View Model hierarchy\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Get current data, using unmap()\",\r\n \"code\": \"$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n var updatedPersonData = person.unmap(); // Get plain object hierarchy from current View Model hierarchy\\n window.alert(JSON.stringify(updatedPersonData));\\n});\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone:{\\n getters: [\\\"number\\\"]\\n }\\n});\\n\\nvar vmCollection = $.views.viewModels;\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(vmCollection.Phone(phoneNo));\\n}\\n\\n// First version of data (e.g. from JSON request):\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\n// Second version of data (e.g. new JSON request):\\nvar personData2 = {\\n name: \\\"Peter\\\",\\n address: {street: \\\"2nd Ave\\\"},\\n phones: [{number: \\\"111 111 9999\\\"},{number: \\\"333 333 9999\\\"}]\\n};\\n\\n// Instantiate View Model hierarchy, using map()\\nvar person = vmCollection.Person.map(personData);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n // Update View Model hierarchy, using merge()\\n person.merge(personData2);\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#revert\\\").on(\\\"click\\\", function() {\\n // Revert View Model hierarchy, using merge()\\n person.merge(personData);\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n // Get current data, using unmap()\\n var updatedPersonData = person.unmap();\\n window.alert(JSON.stringify(updatedPersonData));\\n});\",\r\n \"html\": \"\\n\\n\\n\\n
                  \\n\\n\\n\\n
                  \\n\\n\",\r\n \"height\": \"230\",\r\n \"title\": \"Using merge() to update View Models, and unmap() to return to plain objects\",\r\n \"anchor\": \"mergesample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also the [corresponding sample](#jsvviewmodelsapi@mergesample) using JsViews and data-linking.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Overriding generated get/set functions\",\r\n \"text\": \"To override a generated get/set property provided by a compiled View Model you can provide an implementation in the `extend` hash, with the same name as the *get/set* in the `getters` array:\\n\\n```js\\n// Define a myNameGetSet(...)function, to override the compiled name(...) get/set function\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Declare a Person View Model with an overridden name() get/set property\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", ...}, // Compiled name() get/set\\n ...\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n ...\\n }\\n ...\\n },\\n ...\\n});\\n```\\n\\nThe above is equivalent to the generated version except that it adds custom logging to the getter/setter function.\\n\\n**Note:** In the context of JsViews, the View Model get/set properties can be data-linked (one-way or two-way data-binding) -- and will then be invoked automatically during observable changes to the property. (This applies also to overridden properties -- using a variant of the above pattern, described in [the corresponding JsViews topic](#jsvviewmodelsapi@override)).\",\r\n \"anchor\": \"override\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sample showing some of the advanced View Model features\",\r\n \"text\": \"The next sample is similar to the [previous](#viewmodelsapi@mergesample) one, but specifically highlights some of the advanced features of compiled *View Models*.\\n\\n- It stores compiled *View Models* on a `myVmCollection` hash, as a *View Model typed collection*, rather than on
                  `$.views.viewModels`\\n- It maps from an array of 'people' rather than a single person:
                  \\n `var people = Person.map(peopleData);`\\n- It specifies an `id` key for `Person`. When updating the `phones` array the `id` value is treated as 'primary key', and used to map 'identity':
                  \\n `id: \\\"id\\\"`\\n- It provides an `id()` callback on `Person`, for determining identity -- allowing identification of corresponding *View Model* instances within the people array, and hence preventing unnecessary disposal and re-instantiation (which would destroy state, such as the `comment` value).\\n- It has a `comment()` get/set property that is added as part of the `extend` definition, not the `getters`, so it is not initialized from data, in the constructor. Note therefore that if you set a *comment* on each `person` instance, then click *Update*, then *Revert*, one *comment* is conserved (since that instance is never disposed -- based on the 'identity' determination) but the other is lost since the instance is disposed and then re-created by *Revert*:
                  \\n `extend: {...comment: comment...}`\\n- It has `defaultVal` specified for `name`, `address` and `phones`, either as 'static' values or computed by a callback function:
                  \\n `address: {type: \\\"Address\\\", defaultVal: defaultStreet}`\\n- It overrides the generated `person.name()` *get/set* by a `myNameGetSet` function which includes logging\\n- It passes a JSON string to `merge()` or `map()`\\n(See also the [same sample](#jsvviewmodelsapi@mergesampleadv) using JsViews and data-linking.)\",\r\n \"anchor\": \"mergesampleadv\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myVmCollection = {};\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", defaultVal: \\\"No name\\\"}, // Compiled name() get/set\\n {getter: \\\"address\\\", type: \\\"Address\\\", defaultVal: defaultAddress},\\n {getter: \\\"phones\\\", type: \\\"Phone\\\", defaultVal: []}\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n addPhone: addPhone,\\n comment: comment // Additional get/set property, not initialized by data)\\n },\\n id: function(vm, plain) { // Callback function to determine 'identity'\\n return vm.personId === plain.personId;\\n }\\n },\\n ...\\n Phone: {\\n getters: [\\\"number\\\"],\\n id: \\\"phoneId\\\" // Treat phoneId as 'primary key', for identity\\n }\\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\\n\\n// Override generated name() get/set\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\\n this.phones().push(myVmCollection.Phone(phoneNo));\\n}\\n\\n// get/set for comment (state on View Model instance, not initialized from data)\\nfunction comment(val) {\\n if (!arguments.length) {\\n return this._comment;\\n }\\n this._comment = val;\\n}\\n\\nfunction defaultAddress() { // Function providing default address if undefined in data\\n return {street: 'No street for \\\"' + this.name + '\\\"'};\\n}\\n\\n// First version of data - array of objects (e.g. from JSON request):\\nvar peopleData = [{personId: \\\"1\\\", ...}, {personId: \\\"2\\\", name: \\\"Pete\\\",...}];\\n\\n// Second version of data - JSON string (e.g. new JSON request):\\nvar peopleData2 = '[{\\\"personId\\\":\\\"2\\\",\\\"name\\\":\\\"Peter\\\",\\\"address\\\":...}]';\\n\\n// Instantiate View Model hierarchy using map()\\nvar people = myVmCollection.Person.map(peopleData);\\n\\n// Render template against people (array of Person instances)\\n$(\\\"#result\\\").html(tmpl.render(people));\\n...\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData2);\\n ...\\n});\\n...\"\r\n }\r\n ],\r\n \"code\": \"var tmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar myVmCollection = {};\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", defaultVal: \\\"No name\\\"}, // Compiled name() get/set\\n {getter: \\\"address\\\", type: \\\"Address\\\", defaultVal: defaultAddress},\\n {getter: \\\"phones\\\", type: \\\"Phone\\\", defaultVal: []}\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n addPhone: addPhone,\\n comment: comment // Additional get/set property, not initialized by data)\\n },\\n id: function(vm, plain) { // Callback function to determine 'identity'\\n return vm.personId === plain.personId;\\n }\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone: {\\n getters: [\\\"number\\\"],\\n id: \\\"phoneId\\\" // Treat phoneId as 'primary key', for identity\\n }\\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\\n\\n// Override generated name() get/set\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\\n this.phones().push(myVmCollection.Phone(phoneNo));\\n}\\n\\n// get/set for comment (state on View Model instance, not initialized from data)\\nfunction comment(val) {\\n if (!arguments.length) {\\n return this._comment; // If there is no argument, use as a getter\\n }\\n this._comment = val;\\n}\\n\\nfunction defaultAddress() { // Function providing default address if undefined in data\\n return {street: 'No street for \\\"' + this.name + '\\\"'};\\n}\\n\\n// First version of data - array of objects (e.g. from JSON request):\\nvar peopleData = [\\n {\\n personId: \\\"1\\\",\\n address: {\\n street: \\\"2nd Ave\\\"\\n }\\n },\\n {\\n personId: \\\"2\\\",\\n name: \\\"Pete\\\",\\n phones: [\\n {number: \\\"333 333 3333\\\", phoneId: \\\"2a\\\"}\\n ]\\n }\\n];\\n\\n// Second version of data - JSON string (e.g. new JSON request):\\nvar peopleData2 = '[{\\\"personId\\\":\\\"2\\\",\\\"name\\\":\\\"Peter\\\",\\\"address\\\":{\\\"street\\\":\\\"11 1st Ave\\\"},'\\n+ '\\\"phones\\\":[{\\\"number\\\":\\\"111 111 9999\\\",\\\"phoneId\\\":\\\"1a\\\"},{\\\"number\\\":\\\"333 333 9999\\\",\\\"phoneId\\\":\\\"2a\\\"}]}]';\\n\\n// Instantiate View Model hierarchy using map()\\nvar people = myVmCollection.Person.map(peopleData);\\n\\n// Render template against people (array of Person instances)\\n$(\\\"#result\\\").html(tmpl.render(people));\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData2);\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#revert\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData);\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n people[0].name(\\\"newName\\\");\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n people[0].addPhone(\\\"xxx xxx xxxx\\\");\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#result\\\").on(\\\"change\\\", \\\".comment\\\", function(val) {\\n // If comment is modified, update View Model state with new value\\n people[this.getAttribute(\\\"data-index\\\")].comment(this.value);\\n});\\n\\n$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n var updatedPeopleData = people.unmap();\\n window.alert(JSON.stringify(updatedPeopleData));\\n});\\n\",\r\n \"html\": \"\\n\\n\\n\\n
                  \\n\\n\\n\\n
                  \\n\\n\",\r\n \"height\": \"350\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"\",\r\n \"title\": \"Mapping from JSON data to View Model hierarchy – further features\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding a custom get/set property to a compiled View Model \",\r\n \"text\": \"Finally, here is a sample which extends a compiled *View Model* with a custom `Person.isManager() `*get/set* property. The property is coupled to the `Team.manager()` property -- so setting `Person.isManager(...)` will update the `Team.manager()` correspondingly (and conversely when setting `Team.manager(...)`.\\n\\n`Person.isManager` is not included in the `getters` declaration, so that the constructor for `Person` will not expect an `isManager` parameter to be provided for initialization.\\n\\n(See also the [related sample](#jsvviewmodelsapi@ismanagersample) using JsViews and data-linking.)\",\r\n \"anchor\": \"ismanagersample\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Custom function for Person.isManager get/set property\\nfunction myIsManager(val) {\\n if (!arguments.length) {\\n return this === team.manager(); // If there is no argument, use as a getter\\n }\\n if (val) {\\n // Make this team member manager\\n team.manager(this);\\n } else if (this.isManager()) {\\n // Set team manager to null\\n team.manager(null);\\n }\\n}\\n\\n// Compile View Models\\n$.views.viewModels({\\n Team: {...},\\n Person: {\\n getters: [\\n \\\"name\\\",\\n ...\\n ],\\n extend: {\\n isManager: myIsManager // use custom function\\n }\\n },\\n Address: {...}\\n});\\n\\n...\\n\\n//Initialize second team member to be manager.\\nvar manager = team.members()[1];\\nmanager.isManager(true);\\n\\n...\\n\\n// Attach handler for checkbox\\n$(\\\"#result\\\")\\n .on(\\\"change\\\", \\\".isManager\\\", function() {\\n ...\\n member.isManager(this.checked);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"// Compile template\\nvar tmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Custom function for Person.isManager get/set property\\nfunction myIsManager(val) {\\n if (!arguments.length) {\\n return this === team.manager(); // If there is no argument, use as a getter\\n }\\n if (val) {\\n // Setting this.isManager() to true\\n // So make this team member manager\\n team.manager(this);\\n } else if (this.isManager()) {\\n // Setting this.isManager to false, and this team member is currently manager.\\n // So set team manager to null\\n team.manager(null);\\n }\\n}\\n\\n// Compile View Models\\n$.views.viewModels({\\n Team: {\\n getters: [\\n {\\n getter: \\\"manager\\\",\\n type: \\\"Person\\\"\\n },\\n {\\n getter: \\\"members\\\",\\n type: \\\"Person\\\"\\n }\\n ]\\n },\\n Person: {\\n getters: [\\n \\\"name\\\",\\n {\\n getter: \\\"address\\\",\\n type: \\\"Address\\\"\\n }\\n ],\\n extend: {\\n isManager: myIsManager // use custom function\\n }\\n },\\n Address: {\\n getters: [\\\"street\\\", \\\"ZIP\\\"]\\n }\\n});\\n\\n// Initial data \\nvar teamData = {\\n manager: null,\\n members: [{\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\",\\n ZIP: \\\"12345\\\"\\n }\\n },{\\n name: \\\"Bess\\\",\\n address: {\\n street: \\\"Central Way\\\",\\n ZIP: \\\"98765\\\"\\n }\\n },\\n {\\n name: \\\"Henry\\\",\\n address: {\\n street: \\\"Main St\\\",\\n ZIP: \\\"54321\\\"\\n }\\n }]\\n };\\n\\n// Instantiate View Models\\nvar team = $.views.viewModels.Team.map(teamData);\\n\\n//Initialize second team member to be manager.\\nvar manager = team.members()[1];\\nmanager.isManager(true);\\n\\nfunction renderTemplate() {\\n // Refresh template rendering completely\\n $(\\\"#result\\\").html(tmpl.render(team));\\n}\\n\\nrenderTemplate();\\n\\n// Attach handlers for checkbox and buttons\\n$(\\\"#result\\\")\\n .on(\\\"change\\\", \\\".isManager\\\", function() {\\n var memberIndex = $(this).data(\\\"index\\\"),\\n member = team.members()[memberIndex];\\n member.isManager(this.checked);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n .on(\\\"click\\\", \\\".changeManager\\\", function() {\\n var memberIndex = $(this).data(\\\"index\\\"),\\n member = team.members()[memberIndex];\\n member.isManager(true);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n .on(\\\"click\\\", \\\".noManager\\\", function() {\\n team.manager(null);\\n renderTemplate(); // Refresh rendering, with modified data\\n }\\n);\",\r\n \"title\": \"Sample: extending Person with an isManager property\",\r\n \"height\": \"294\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvviewmodelsapi\",\r\n \"label\": \"Compiled View Models (JsViews)\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"lifecycle\": {\r\n \"title\": \"Life-cycle events\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"paragraph\"\r\n }\r\n ]\r\n },\r\n \"globals\": {\r\n \"title\": \"globals\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender\\n\\n- render()\\n- templates()\\n- views\\n\\nJsViews\\n\\n- link()\\n- observe()\\n- observable()\\n- unlink()\\n- unobserved()\\n- view()\\n\\n\"\r\n }\r\n ]\r\n },\r\n \"tagsapi\": {\r\n \"title\": \"Registering custom tags: $.views.tags()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.views.tags()` is used to register custom tags. See *[Using custom tags](#tags)* for an overview, and simple examples.\\n\\nThis topic provides more details.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What is a custom tag?\",\r\n \"text\": \"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\\n\\nA custom tag can optionally use arguments (*args*) and named parameters (*props*), [as in](#tagsyntax@tagparams):\\n\\n```jsr\\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\\n```\\n\\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying tag options for a custom tag\",\r\n \"text\": \"The following tag declaration registers a `{{mytag}}` custom tag:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagOptions);\\n```\\n\\nThe `tagOptions` object (hash) specifies the tag options and determines how the tag will function. It can include:\\n\\n- An [init()](#tagsapi@init) method: `init: tagInitFn`\\n- A [render()](#tagsapi@render) method: `render: tagRenderFn`\\n- A [template](#tagsapi@template): `template: tagTemplate`\\n\\nIn addition `tagOptions` can specify tag inheritance (so that the custom tag derives from a base tag):\\n\\n- [`baseTag: ...`](#tagsapi@basetag)\\n\\nIt can also specify the following more advanced options:\\n\\n- [`contentCtx: ...`](#tagsapi@contentctx)\\n- [`convert: ...`](#tagsapi@convert)\\n- [`argDefault: ...`](#tagsapi@argdefault)\\n- [`bindTo: ...` / `bindFrom: ...`](#tagsapi@bindto)\\n- [`flow: ...`](#tagsapi@flow)\\n- [`ctx: ...`](#tagsapi@ctx)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering custom tags: $.views.tags(...)\",\r\n \"text\": \"To register a custom tag, you call the `$.views.tags(...)` API.\\n\\nThere are four alternative signatures:\\n\\n- `$.views.tags(\\\"mytag\\\", tagOptions);` -- where the properties of the `tagOptions` object will typically include a `render: tagRenderFn` (specifying a render() method), and/or a `template: tagTemplate` (specifying a template to be rendered)\\n- `$.views.tags(\\\"mytag\\\", tagRenderFn);` -- simplified form, when the only option being specified is a render() method\\n- `$.views.tags(\\\"mytag\\\", tagTemplate);` -- simplified form, when the only option being specified is a tag template to be rendered\\n- `$.views.tags(namedTags);` This version is for declaring multiple custom tags, and `namedTags` is a hash (with custom tag names as keys and `tagOption` objects as values)\\n\\nHere are the details:\",\r\n \"anchor\": \"register\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.tags(...)\",\r\n \"name\": \"tags\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A tagOptions object with a render() method and/or a template property, and optionally other properties or methods\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", {\\n render: function(...) {...},\\n template: ...\\n});\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a custom tag, specifying chosen tag options\",\r\n \"returns\": \"Compiled tag object\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagRenderFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Tag render() method. Returns the rendered tag\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", function(...) {\\n ...return rendered content\\n});\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a simple 'render' function as a custom tag\",\r\n \"returns\": \"Compiled tag object\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"A string containing template markup to be rendered by the tag (or a selector for a script block template definition, or a compiled template object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", \\\"templateMarkup...\\\");\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a template as a custom tag\",\r\n \"returns\": \"Compiled tag object\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTags\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of tag) and values (render function, template, or tagOptions object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags({\\n mytag1: {\\n render: function(val) {...},\\n template: ...\\n },\\n mytag2: function(val) {...},\\n mytag3: tag3TemplateString,\\n});\",\r\n \"description\": \"Register multiple custom tags\",\r\n \"returns\": \"\"\r\n }\r\n ],\r\n \"description\": \"Register one or more custom tags\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"For simple samples showing the above alternative `$.views.tags(...)` signatures, see the [*Using custom tags*](#tags) overview topic:\\n\\n- [A custom tag using just a render() method](#tags@render-sample)\\n- [A custom tag using just a template](#tags@template-sample)\\n- [Accessing context within the render() method](#tags@context-sample)\\n- [Accessing context from the tag template](#tags@tmplcontext-sample)\\n\\nThe [*Using custom tags*](#tags) overview also provides samples of custom tags which render block content -- `{{mytag}}...{{/mytag}}`:\\n\\n- [Rendering block content from a custom tag render() method](#tags@renderblock-sample)\\n- [Rendering block content from a custom tag template](#tags@tmplblock-sample)\\n- [A {{runningTotal}} custom tag, using a render() method](#tags@runningtotal-sample)\\n- [A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"](#tags@renderplustmpl-sample)\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag options: Specifying init(), render(), template, baseTag:\",\r\n \"text\": \"A custom tag in JsRender has a very simple *'life-cyle'* consisting of two events for which you can optionally provide event handlers: the `init()` event, followed by the `render()` event. (If the custom tag is used in the context of JsViews, additional lifecycle events will also come into play, for data-binding, disposal, etc.)\",\r\n \"anchor\": \"options\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing an init() method\",\r\n \"text\": \"The *init()* method acts as a handler for the *init* event of the custom tag, and is called with the tag instance as `this` parameter.\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx, linkCtx, ctx) { ... },\\n ...\\n});\\n``` \\n\\nThe *init()* method arguments are:\\n- `tagCtx`: the [tagCtx object](#tagcontextobject), also available as `this.tagCtx`\\n- `linkCtx`: always 0 unless using [data-linked tags](#linked-tag-syntax) with *JsViews* (See [linkCtx object](#linkctxobject).)\\n- `ctx`: [View context object](#ctxobject)\\n\\nThe following example uses the *init()* method to set the tag template based on the value of the `mode` prop:\",\r\n \"anchor\": \"init\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.template = tagCtx.props.mode === \\\"a\\\"\\n ? \\\"template A ...\\\"\\n : \\\"template B ...\\\";\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{mytag name mode='a' /}}\\n{{mytag name mode='b' /}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                  \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.template = tagCtx.props.mode === \\\"a\\\"\\n ? \\\"template A: {{:}} aaa
                  \\\"\\n : \\\"template B: {{:}} bbb
                  \\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render({name: \\\"Jo\\\"});\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"anchor\": \"initsample\",\r\n \"title\": \"Providing init()\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a render() method\",\r\n \"text\": \"The *render()* method acts as a handler for the *render* event of the custom tag, and is called with the tag instance as `this` parameter, and with arguments `arg1, arg2, ...`, corresponding to the unnamed arguments passed in the tag markup, `{{mytag expression1 expression2 ... }}`.\\n\\nIf no arguments are passed in the markup, then the `render()` method will be called with the current data context as argument (unless modified by the [argDefault](#tagsapi@argdefault) option.)\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function(value1, value2) { ... return ...; },\\n ...\\n});\\n```\\n\\nThe *render()* method can optionally be used to define how the tag renders, by returning an HTML markup string.\\n\\nSee the example: [*A custom tag using just a render() method*](#tags@render-sample).\\n\",\r\n \"anchor\": \"render\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a template\",\r\n \"text\": \"The *template* option is used for declarative rendering, as an alternative to providing a *render()* method.\\n\\nSee the example: [*A custom tag using just a template*](#tags@template-sample).\\n\",\r\n \"anchor\": \"template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Data context of a tag template\",\r\n \"text\": \"If the custom tag is called with an argument: `{{mytag someArgument ...}}` then the template will be rendered using the value of that argument as data context.\\n\\nOtherwise, the data context will be the same as the outer data context.\\n\\n(*Note:* This behavior can be changed using [contentCtx](#tagsapi@contentctx)) \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using both a template and a render() method\",\r\n \"text\": \"If the tag has both a *render()* method and a *template*, then the *render()* method is used to render the tag. But if *render()* returns `undefined` (or has no return value), then the *template* is used. \\n\\nSee example: [*A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"*](#tags@renderplustmpl-sample).\\n\\nIt is also possible to provide both a *template* and a *render()* method, and to make use of the rendered template within the content returned by the render method. (In fact `this.tagCtx.render(...)` will return the rendered template). \",\r\n \"anchor\": \"tmpl-fallback\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying tag inheritance: the baseTag option\",\r\n \"text\": \"A custom tag can inherit from another tag (either built-in or custom).\\n\\nFor example the `{{runningTotal}}` sample, linked above, can be rewritten in a more powerful but compact form, by making it inherit from the `{{for}}` tag (since the functionality of iterating over an array is common to both).\\n\\nTo inherit from another tag, set the `baseTag` option to the name of the tag you want to derive from (or to the compiled tag object):\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ...\\n});\\n```\\n\\nCustom tag methods (*init()* or *render()*) can invoke the corresponding base tag method by calling one of the following API variants:\\n\\n```js\\nthis.base(a, b, ...); // Pass chosen arguments\\nthis.baseApply(arguments); // Pass on the calling arguments (or an array of args)\\n```\\n\\nThis is illustrated in the following sample, which takes the *Providing init()* [sample](#tagsapi@initsample) above, and defines a derived `{{mytag2}}` which overrides *init()* and adds an error message when no valid `mode` was specified:\\n\",\r\n \"anchor\": \"basetag\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"mytag2\\\", {\\n baseTag: \\\"mytag\\\",\\n init: function() { // Override the init() method\\n this.baseApply(arguments); // Call the base method\\n this.template = this.template || \\\"Error: Specify mode 'a' or 'b'\\\"; // If no template was assigned, render error message\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{mytag2 name mode='a' /}}\\n{{mytag2 name mode='b' /}}\\n{{mytag2 name /}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                  \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.templates = {\\n a: \\\"template A: {{:}} aaa
                  \\\",\\n b: \\\"template B: {{:}} bbb
                  \\\"\\n }; \\n this.template = this.templates[tagCtx.props.mode];\\n }\\n});\\n\\n$.views.tags(\\\"mytag2\\\", {\\n baseTag: \\\"mytag\\\",\\n init: function() { // Override the init() method\\n this.baseApply(arguments); // Call the base method\\n // If no template was assigned, render error message\\n this.template = this.template || \\\"Error: Specify mode 'a' or 'b'\\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render({name: \\\"Jo\\\"});\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"75\",\r\n \"anchor\": \"basetagsample\",\r\n \"title\": \"baseTag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The previous `{{runningTotal}}` [sample](#tags@renderplustmpl-sample) was relatively complex. Here is an updated version rewritten to derive from `{{for}}`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This version is much simpler and supports sorting, filtering, etc. as well as `start=... end=... step=...`, without any additional code (thanks to the inherited features of `{{for}}`).\\n\\nAlso the fallback rendering for *No line items* is no longer hard-coded in the tag, but instead uses the `{{runningTotal}}...{{else}}...` pattern.\\n\\nNote that `~total()` is a function. The call to `~total()` increments the value and returns the running total.\\n\\n*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function() { // A ~total() helper (now a function)\\n ...\\n tag.totalVal += this.data[totalCol]; // Compute running total\\n return tag.totalValue; // Return value from ~total()\\n }\\n },\\n render: function() {\\n this.totalVal = 0; // Initialize total before rendering\\n return this.baseApply(arguments); // Render\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{runningTotal lineItems start=1 end=4 totalColumn=\\\"quantity\\\"}} \\n ...{{:~total()}}...\\n{{else}}\\n ...No line items...\\n{{/runningTotal}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"244\",\r\n \"title\": \"A {{runningTotal}} custom tag derived from {{for}}\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"html\": \"
                  \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function() { // A ~total() helper (now a function)\\n var tag = this.ctx.tag,\\n totalCol = tag.tagCtx.props.totalColumn\\n tag.totalVal += this.data[totalCol]; // Compute running total\\n return tag.totalVal; // Return value from ~total()\\n }\\n },\\n render: function() {\\n this.totalVal = 0; // Initialize total before rendering\\n return this.baseApply(arguments); // Render\\n }\\n});\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ],\\n lineItems2: []\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(data, {\\n category: function(item, index, items) {\\n return item.category === this.props.category;\\n }\\n});\\n\\n$(\\\"#lineItems\\\").html(html);\",\r\n \"anchor\": \"derivedfor\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Our `{{runningTotal}}` [samples](#tagsapi@derivedfor) so far have initialized the running total to `0` in the render method, and then relied on the rendering process to do the incrementing of the running total. This approach would fail if the rendering sequence was changed for any reason.\\n\\nThe sample below takes the `{{runningTotal}}` tag above, and converts it to a more complete and more powerful \\n `{{purchases}}` tag, again deriving from the `{{for}}` tag. The `{{purchases}}` tag, which is more flexible and more robust, and supports any number of running total columns.\\n\\nThe `~total(expression)` helper function now allows you to provide any expression as parameter. Here, running total values are recomputed for each line, separately, so no longer depend on the render processing sequence:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `~total(expr)` helper function now accepts an *expression* parameter for each running total -- to be used to compute the incremental amount for each row.\\n\\n*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"purchases\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function(expr) { // A ~total(expression) helper\\n var tmpl = $.templates[expr] // Get named compiled template for expression, or else...\\n || $.templates(expr, \\\"{{:\\\" + expr + \\\"}}\\\"), // ...if this is first call, create it\\n\\n runningTotal = 0,\\n view = this, // The content view with the ~total(...) helper call\\n items = view.get(\\\"array\\\").data,\\n rowIndex = view.getIndex();\\n\\n for (var i = 0; i <= rowIndex; i++) {\\n runningTotal += +tmpl(items[i]); // Compute running total up to this row, using render function\\n } // of compiled tmpl (either tmpl() or tmpl.render()...)\\n return runningTotal; // Return value from ~total(...)\\n }\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{purchases lineItems sort=\\\"category\\\" ...}} \\n ...{{:~total('quantity*price')}}...\\n{{else}}\\n ...No items...\\n{{/purchases}}\\n```\\n\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"550\",\r\n \"url\": \"samples/jsrender/tags/extend-for/sample\",\r\n \"title\": \"A {{purchases}} tag supporting totals for any expression\",\r\n \"anchor\": \"totals-expr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The above `{{purchases}}` custom tag can be easily updated to support data-binding. See [purchases sample](#samples/tag-controls/purchases@jsv).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag context\",\r\n \"text\": \"When a custom tag is used in a template then the rendered template instance will be part of the [view hierarchy](#views).\\n\\nThe instance of the tag is an object with properties and methods:\\n\\n- [tag object](#tagobject)\\n\\nAssociated with the tag instance is a [tag context object](#tagcontextobject), `tagCtx`, providing most of the useful context for a tag, in particular:\\n\\n- context passed down through the view hierarchy:\\n\\n - current view\\n - current data\\n - parent tags\\n - contextual parameters\\n\\n- additional context coming from the tag itself, or its markup:\\n\\n - arguments (*args*) and named parameters (*props*)\\n - rendered tag template\\n - block content\\n - content of else blocks\\n\",\r\n \"anchor\": \"context\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag instance object\",\r\n \"text\": \"From a tag method (*init()* or *render()*), the `this` pointer is the instance of the tag (a [tag object](#tagobject).)\\n\\nFrom a tag template, the tag instance can be accessed as `~tag`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag context object: tagCtx\",\r\n \"text\": \"From a tag method the `tagCtx` object is available as `this.tagCtx`.\\n\\nIn the [*init()*](#tagsapi@render) method it is also passed directly as an argument (`function(tagCtx ...)`).\\n\\nFrom a tag template, `tagCtx` can be accessed as `~tag.tagCtx`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag arguments or named parameters\",\r\n \"text\": \"The values of arguments can be accessed as `tagCtx.args`, and named parameters as `tagCtx.props`.\\n\\nFor example, if we have the following tag, which has two arguments and one named parameter:\\n\\n```jsr\\n{{sometag title name mode=\\\"edit\\\"}}\\n```\\n\\nthen from within the *init()* or *render()* method of `sometag`, the arguments and named parameters can be accessed as:\\n\\n```js\\nvar title = this.tagCtx.args[0];\\nvar name = this.tagCtx.args[1];\\nvar mode = this.tagCtx.props.mode;\\n```\\n\\nand from the tag template, the values can be accessed as `~tagCtx.args` or `~tagCtx.props`, and so might be rendered as: \\n\\n```jsr\\n...title: {{>~tagCtx.args[0]}}
                  name: {{>~tagCtx.args[1]}}
                  mode: {{>~tagCtx.props.mode}}...\\n```\\n\\nIn addition to being available as `tagCtx.args`, arguments are also passed directly as arguments to the *render()* method, so `sometag` might use the following *render()* method, rather than a template, to render similar content:\\n\\n```js\\nfunction sometagRenderMethod(title, name) {\\n return \\\"...title: \\\" + title + \\\"
                  name: \\\" + name + \\\"
                  mode: \\\" + this.tagCtx.props.mode ...;\\n}\\n```\\n\\nThe `tagCtx` object also provides access to the markup expression for arguments and named parameters, as `tagCtx.params.args` and `tagCtx.params.props`.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the parent view and the current data\",\r\n \"text\": \"The contextual (parent) view for the tag instance is accessed as `tagCtx.view`. The corresponding (parent) data context is `tagCtx.view.data`.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag child views\",\r\n \"text\": \" \",\r\n \"anchor\": \"childviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag rendering with template: \\\"mytag\\\" child view\",\r\n \"text\": \"A custom tag template instance will be part of the [view hierarchy](#views), and the rendered tag may add additional child views to the view hierarchy.\\n\\nIf `{{mytag members}}` renders using its *template*, that template will render as a child view (of type `\\\"mytag\\\"`). The default data context within the *template* will be the first argument passed to the tag (`members` in this case) which will be the `view.data` property of the child view.\\n\\nIf the *template* markup includes template tags (other custom tags, or built-in tags) then there will be corresponding additional child views below the *mytag* view. \\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering wrapped block content\",\r\n \"text\": \"- Any tag can wrap [block content](#tagsyntax@blocktag), or use `tmpl=...` to reference external content:\\n ```jsr\\n {{mytag}}...{{/mytag}}\\n\\n {{mytag tmpl=... /}}\\n ```\\n- By default, a custom tag with no *render()* method or tag template will render its block content unchanged. A tag with an argument will move data context to the data passed in the argument: `{{mytag somedata ...}}`.\\n- For a custom tag rendering using a *render()* method, wrapped block content can be included using `tagCtx.render()`.

                  *Note:* To set the inner data context, pass in data as argument: `tagCtx.render(someData)`. Otherwise inner and outer data context are the same.\\n ```js\\n $.views.tags(\\\"mytag\\\", {\\n ...\\n render: function() {\\n return ... + this.tagCtx.render() + ...;\\n },\\n ...\\n });\\n ```\\n See the sample: [*Rendering block content from a custom tag render() method*](#tags@renderblock-sample).

                  \\n (For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See the [template as fallback](#tags@tmpl-fallback) sample).

                  \\n- For a custom tag rendering using a tag template, wrapped block content can be included using:\\n ```jsr\\n {{include tmpl=#content/}}\\n ```\\n or equivalently:\\n ```jsr\\n {{include tmpl=~tagCtx.content/}}\\n ```\\n where in each case the inner data context can be modified by passing an argument, `{{include someData tmpl=... /}}`.\\n See the sample: [*Rendering block content from a custom tag template*](#tags@tmplblock-sample).\\n\\nNote that if a custom tag has an external `tmpl=...` reference, **_and_** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (see: [*Wrapping content*](#tagsyntax@wrap)).\\n\\nThis can provide for cascading content, as in the following sample:\\n\\n```jsr\",\r\n \"anchor\": \"wrapping\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.tags(\\\"mytag\\\", {\\n template: \\\"mytagStart...{{include tmpl=#content/}}.../mytagEnd\\\"\\n});\\n```\\n```jsr\\n{{mytag tmpl='#external'}}wrappedContent{{/mytag}}\\n```\\n\\n```jsr\\n\\n\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n\\n\\n
                  \\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n template: \\\"mytagStart
                  {{include tmpl=#content/}}
                  /mytagEnd\\\"\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {},\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"106\",\r\n \"title\": \"Cascading content\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering else blocks\",\r\n \"text\": \"Any tag can use [`{{else}}`](#elsetag) blocks. We might for example create a custom tag for rendering lists:\\n\\n```jsr\\n{{list}}\\n First item\\n{{else}}\\n Second item\\n{{else}}\\n Last item\\n{{/list}}\\n```\\n\\nA custom tag can provide specific behavior/rendering for `{{else}}` blocks:\\n\\n- For a tag with a render method, *render()* will be called once for the initial block and once for each `{{else}}` block.\\n- Similarly, for a custom tag with a tag template, the template will be rendered once for the initial block and once for each `{{else}}` block.\\n- During rendering a custom tag can detect which block is being rendered, using `tagCtx.index` (see below), and can then output the content corresponding to the desired functionality.\\n\",\r\n \"anchor\": \"elseblocks\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag context objects for {{else}} blocks: the tagCtxs array\",\r\n \"text\": \"A tag with multiple blocks (initial block plus 1 or more `{{else}}` blocks) will have a `tagCtxs` array of `tagCtx` objects, one for each block.\\n\\n- From a tag method the `tagCtxs` array is available as `this.tagCtxs`.\\n- From a tag template, `tagCtxs` can be accessed as `~tag.tagCtxs`.\\n\\nEach `tagCtx` object in `tagCtxs` has an `index` property (`0` for the initial block), as well as the other properties (`args`, `props` etc.) corresponding to the markup (arguments, named properties...) on the corresponding tag (`{{mytag ...}}` or `{{else ...}}`).\\n\\n- Within a tag *render()* method, `this.tagCtx` will be the current tag context object for that block.\\n- Similarly, during rendering of the tag template, `~tag.tagCtx` will be the current `tagCtx`.\\n\\nTo determine the index of the block being rendered, use `tagCtx.index`. \\n\\nThese features are illustrated in the following sample:\",\r\n \"anchor\": \"tagctxs\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Custom `{{list}}` tag:*\\n\\n```js\\n$.views.tags(\\\"list\\\", function() {\\n // render() method\\n var ret = \\\"\\\", // Return value\\n index = this.tagCtx.index, // block index\\n listElem = this.tagCtxs[0].props.numbered ? \\\"ol\\\" : \\\"ul\\\"; // Wrapper
                    or
                      element, based on numbered=true property \\n\\n if (index===0) {\\n ret += \\\"<\\\" + listElem + \\\">\\\"; // First block: add opening wrapper\\n }\\n ret += \\\"
                    • \\\" + this.tagCtx.render() + \\\"
                    • \\\"; // Add li element and block content\\n if (index===this.tagCtxs.length-1) {\\n ret += \\\"\\\"; // Last block: add closing wrapper\\n }\\n return ret;\\n});\\n```\\n\\n*Usage*:\\n\\n```jsr\\n{{list numbered=true}}First{{else}}Second{{else}}Last{{/list}}\\n{{list}}first{{else}}last{{/list}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"// Define custom {{list}} tag\\n$.views.tags(\\\"list\\\", function() {\\n // render() method\\n var ret = \\\"\\\", // Return value\\n index = this.tagCtx.index, // block index\\n listElem = this.tagCtxs[0].props.numbered ? \\\"ol\\\" : \\\"ul\\\"; // Wrapper
                        or
                          element, based on numbered=true property \\n\\n if (index===0) {\\n ret += \\\"<\\\" + listElem + \\\">\\\"; // First block: add opening wrapper\\n }\\n ret += \\\"
                        • \\\" + this.tagCtx.render() + \\\"
                        • \\\"; // Add li element and block content\\n if (index===this.tagCtxs.length-1) {\\n ret += \\\"\\\"; // Last block: add closing wrapper\\n }\\n return ret;\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render();\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"height\": \"130\",\r\n \"title\": \"Custom {{list}} tag using {{else}} blocks\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is a version of the sample with the same tag implemented using a tag template, rather than a *render()* method.\\n\\nHere we use the *init()* method to assign a tag template dynamically, using a different wrapper (`ol` or `ul`) based on the `numbered` named property:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Custom `{{list}}` tag:*\\n \\n```js\\n$.views.tags(\\\"list\\\", {\\n init: function() {\\n var listElem = this.tagCtx.props.numbered ? 'ol' : 'ul'; // Wrapper ol or ul element\\n this.template = \\n // First block: add opening wrapper\\n \\\"{{if ~tagCtx.index===0}}<\\\" + listElem + \\\">{{/if}}\\\"\\n // Add li element and block content\\n + \\\"
                        • {{include tmpl=#content/}}
                        • \\\"\\n // Last block: add closing wrapper\\n + \\\"{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}\\\";\\n }\\n});\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"130\",\r\n \"title\": \"Custom {{list}} tag: Rendering {{else}} blocks from a tag template\",\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"code\": \"// Define custom {{list}} tag\\n$.views.tags(\\\"list\\\", {\\n init: function() {\\n var listElem = this.tagCtx.props.numbered ? 'ol' : 'ul'; // Wrapper ol or ul element\\n this.template = \\n // First block: add opening wrapper\\n \\\"{{if ~tagCtx.index===0}}<\\\" + listElem + \\\">{{/if}}\\\"\\n // Add li element and block content\\n + \\\"
                        • {{include tmpl=#content/}}
                        • \\\"\\n // Last block: add closing wrapper\\n + \\\"{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}\\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render();\\n\\n$(\\\"#page\\\").html(html);\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Custom tags with no *render()* method and no tag template can also render multiple blocks, using `{{else}}`. Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Custom `{{mytag}}` which simply renders each block as is:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {});\\n```\\n\\nThe default data context of each block is the value passed to the first argument.\\n\\n```jsr\\n{{mytag last}}\\n First: {{:}}...\\n{{else first}}\\n ...\\n{{else phone}}\\n ...\\n{{/mytag}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"code\": \"// Define custom {{mytag}} tag\\n$.views.tags(\\\"mytag\\\", {});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {first: \\\"Jo\\\", last: \\\"Blow\\\", phone: \\\"111-111-1111\\\"},\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\\n\",\r\n \"title\": \"Default behavior for custom tag with {{else}} blocks\",\r\n \"height\": \"72\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag hierarchy – Accessing parent tags\",\r\n \"text\": \"Nested custom tags can determine parent tags, and can be designed with functionality or rendering that is based on parent or child tags, as in the following example where a `{{layout}}` tag determines the layout for child `{{cell}}` tags:\\n\",\r\n \"anchor\": \"parents\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{layout 'vertical'}}\\n {{cell}}one{{/cell}}\\n {{cell}}two{{/cell}}\\n{{/layout}}\\n
                          \\n{{layout 'horizontal'}}\\n {{cell}}one{{/cell}}\\n {{cell}}two{{/cell}}\\n{{/layout}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"$.views.tags({\\n layout: {\\n render: function(mode) {\\n if (mode === \\\"vertical\\\") {\\n this.vertical = true;\\n return \\\"\\\" + this.tagCtx.render() + \\\"
                          \\\";\\n } else {\\n return \\\"\\\" + this.tagCtx.render() + \\\"
                          \\\";\\n }\\n }\\n },\\n cell: {\\n render: function() {\\n return this.parents.layout.vertical\\n ? \\\"\\\" + this.tagCtx.render() + \\\"\\\"\\n : \\\"\\\" + this.tagCtx.render() + \\\"\\\";\\n }\\n }\\n})\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = { name: \\\"Jo\\\" },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"140\",\r\n \"header\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following properties provide access to ancestor custom tags:\\n\\n**parents property:**\\n\\nThe `parents` property is a hash of all the ancestor custom tags. In the above sample the `{{cell}}` instances have a `parents.layout` property, used to determine whether the assigned layout is vertical, and to render accordingly:\\n\\n```js\\nrender: function() {\\n return this.parents.layout.vertical\\n ? \\\"\\\" + this.tagCtx.render() + \\\"\\\"\\n : \\\"\\\" + this.tagCtx.render() + \\\"\\\";\\n}\\n```\\n\\n**parent property:**\\n\\nThe tag instance also has a `parent` property - in the above sample, the `parent` of the `{{cell}}` instance is the `{{layout}} instance`.\\n\\n**~parentTags contextual parameter:**\\n\\nThe `ctx` property of a tag instance also has a `parentTags` property, equivalent to the `parents` hash. This can be used in the following alternative implementation of the `{{cell}}` tag above, using a tag template rather than a *render()* method:\\n\\n```js\\n$.view.tags(\\\"cell\\\", {\\n template:\\n \\\"{{if ~parentTags.layout.vertical}}{{include tmpl=#content/}}\\\"\\n + \\\"{{else}}{{include tmpl=#content/}}{{/if}}\\\"\\n});\\n```\\n\\nIn fact, in a tag template `~parentTags` and `~tag.parents` are equivalent.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing contextual parameters and helpers\",\r\n \"text\": \"- From a tag template:\\n - Contextual parameters and helpers can be accessed using `~myParamOrHelper`\\n- From a tag method:\\n - Contextual parameters and helpers can be accessed using `this.ctxPrm(\\\"myParamOrHelper\\\")`\\n - (Note: contextual parameters can also be accessed using `this.ctx.myParamOrHelper`, and global helpers can be accessed using `$views.helpers(\\\"myHelper\\\")`)\\n\\nAs an advanced example of custom tag rendering based on contextual parameters, here is a modified version of the above *layout* sample, where instead of wrapping `{{cell}}` tags in a `{{layout}}` tag, we instead wrap in a simple `{{include}}` on which we set a contextual parameter specifying layout: `layout='vertical'`:\",\r\n \"anchor\": \"ctxparams\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{include ~layout='vertical'}}\\n {{cell}}one{{/cell}}\\n {{cell last=true}}two{{/cell}}\\n{{/include}}\\n
                          \\n{{include ~layout='horizontal'}}\\n {{cell}}one{{/cell}}\\n {{cell last=true}}two{{/cell}}\\n{{/include}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"$.views.tags({\\n cell: {\\n render: function() {\\n var res = \\\"\\\",\\n vertical = this.ctxPrm(\\\"layout\\\") === \\\"vertical\\\",\\n parentView = this.tagCtx.view.parent,\\n cellIndex = parentView.cellIndex = parentView.cellIndex === undefined ? 0 : parentView.cellIndex +1;\\n if (vertical) {\\n if (cellIndex===0) {\\n res += \\\"\\\";\\n }\\n res += \\\"\\\";\\n if (this.tagCtx.props.last) {\\n res += \\\"
                          \\\" + this.tagCtx.render() + \\\"
                          \\\";\\n }\\n } else {\\n if (cellIndex===0) {\\n res += \\\"
                          \\\";\\n }\\n res += \\\"\\\";\\n if (this.tagCtx.props.last) {\\n res += \\\"
                          \\\" + this.tagCtx.render() + \\\"
                          \\\";\\n }\\n }\\n return res;\\n }\\n }\\n})\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = { name: \\\"Jo\\\" },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"header\": \"\",\r\n \"height\": \"140\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"### Advanced options\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying data context within tag content: the contentCtx option\",\r\n \"text\": \"*__Default behavior:__*\\n\\nBy default the data context within the tag is the value of the first argument. (See [View hierarchy -- inner data context](#views@innerdata)).\\n\\nSo if `{{mytag}}` uses a `template` then `{{mytag members/}}` will render the template with `members` as data context. \\n\\nSimilarly if `{{mytag}}` is used as a block tag, then the block content within `{{mytag members}}...{{/mytag}}` will render with `members` as data context.\\n\\n*__Modified behavior:__*\\n\\nTo make the data context for tag content the same as parent context, set the `contentCtx` option to `true`:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n contentCtx: true, // The data context inside {{mytag}} will be the same as the outer context\\n ...\\n});\\n```\\n\\nTo specify a different data context for tag content, set the `contentCtx` option to a function returning the chosen data. (The `this` pointer of the `contentCtx` function is the tag instance. The default data context, `arg0` is passed to it as argument.) \\n\\nFor example, with the following tag option setting, the inner data context is given by the `dataCtx` named property:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n contentCtx: function(arg0) {\\n return this.tagCtx.props.dataCtx; // The returned value will be the data context inside {{mytag}}\\n },\\n ...\\n});\\n```\\n\\nUsage:\\n\\n```jsr\\n{{mytag ... dataCtx=.../}}\\n``` \",\r\n \"anchor\": \"contentctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a default converter: the convert option\",\r\n \"text\": \"On any tag, including custom tags, a converter can be specified directly on the tag (see [*Using converters with other tags*](#converters@othertags)):\\n\\n```jsr\\n{{mytag name convert='toUpperCase'/}}\\n```\\n\\nTo provide a default converter on a custom tag (used as fallback if no converter is specified on the tag), set the `convert` tag option to a function, or to a registered converter name:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n convert: 'toLowerCase', // Default converter. (A function or a registered converter name)\\n ...\\n});\\n```\\n\\n\\n\\n\",\r\n \"anchor\": \"convert\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying a default argument: the argDefault option\",\r\n \"text\": \"If a custom tag uses a *render()* method, then the arguments of the tag are passed to the render method:\\n\\n```jsr\\n{{mytag arg0 arg1/}}\\n```\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function(arg0, arg1) {...}\\n});\\n```\\n\\nIf the tag is called without arguments, then the render method will be called with the current data context as first argument, so therefore writing `{{mytag/}}` is equivalent to writing `{{mytag #data/}}` \\n\\nTo override this behavior, set the `argDefault` option to `false`. The first argument will then not default to current data, and the render method will instead be called without arguments.\\n\\n```jsr\\n{{mytag/}}\\n```\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function() {\\n // arguments.length is 0\\n },\\n argDefault: false\\n});\\n```\\n\",\r\n \"anchor\": \"argdefault\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying bound arguments and properties: the bindTo and bindFrom options\",\r\n \"text\": \"The `bindTo` and `bindFrom` options are designed primarily for use with data binding, with JsViews, and allow specifying which arguments/properties are data-bound for two-way binding.\\n\\nIn JsRender, the `bindTo` or `bindFrom` option can be used in conjunction with converters. Set the `bindFrom` option (or the `bindTo` option if there is no `bindFrom` setting) to an array, such as `[0, 1, 2]`, or `[\\\"title\\\", 1]` -- where integers refer to arguments and strings to named properties -- to determine what values are passed to the converter. (If neither `bindFrom` nor `bindTo` are set, then the values of all the [arguments](#tagsyntax@tagparams) will be passed to the converter.)\\n\\nBy default the value returned by the converter will be passed as first argument to the *render()* method. However, if the converter returns an array, then the values will be used to convert each of the targeted arguments or properties specified in `bindTo`/`bindFrom`.\\n\\nSee also [*JsViews* `bindTo`](#tagoptions@bindto)\\n\",\r\n \"anchor\": \"bindto\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying flow behavior: the flow option\",\r\n \"text\": \"A 'flow' tag -- which has the `flow` option set to `true` -- is a tag that does not appear in the [parent tags](#tagsapi@parents) hierarchy, so is not accessed via `this.parent`, `~tagParents` etc.\\n\\nThe built-in tags such as `{{for}}`, `{{props}}` and `{{if}}` are *flow tags*.\",\r\n \"anchor\": \"flow\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying default context: the ctx option\",\r\n \"text\": \"The `ctx` option of a tag can be used to provide default values of [contextual parameters](#contextualparams):\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n template: \\\"{{:~mode}}\\\",\\n ctx: {mode: \\\"readonly\\\"}, // Specify default ~mode if not provided by a helper or as a contextual parameter, \\n ...\\n});\\n```\\n\",\r\n \"anchor\": \"ctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Methods and properties available on a custom tag instance\",\r\n \"text\": \"A custom tag instance can access the following methods and properties\\n\\n- tag.ctxPrm()\\n- tag.cvt()\\n- tag.cvtArgs()\\n- tag.bndArgs() \\n- tag.ctx\\n- tag.parent\\n- tag.parents\\n- tag.tagCtx\\n- tag.tagCtxs\\n- tag.tagName\\n- tag.base\\n- rendering\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding tags as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.tags(...)`.\\n\\nIn that way the tag (or tags) you are registering become 'private tag resources' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"privatetags\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"\",\r\n \"name\": \"tags\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Add one or more tags as private resources for a parent template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTags\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of tag) and values (render function or tagOptions)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template – to which this/these tag(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags({\\n mytag1: ...,\\n mytag2: ...\\n}, parentTemplate);\",\r\n \"description\": \"Add multiple tags as resources, to a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregistering tags\",\r\n \"text\": \"To unregister a previously registered tag, pass `null` to `$.views.tags()`:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", null);\\n// Tag \\\"mytag\\\" is no longer registered\\n```\",\r\n \"anchor\": \"unregister\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags and 'tag controls'\",\r\n \"text\": \"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tags\",\r\n \"label\": \"Using custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls\",\r\n \"label\": \"Samples: JsViews tag controls\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvtagcontrols\",\r\n \"label\": \"JsViews tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n};"]} \ No newline at end of file +{"version":3,"sources":["contents-jsrapi.js"],"names":["content","$","views","documentation","jsrapi","useStorage","parseJSON","localStorage","getItem","title","path","sections","_type","text","links","topics","hash","label","jsrtags","assigntag","typeLabel","name","signatures","params","args","type","optional","description","example","variant","sectionTypes","para","data","template","code","markup","height","jsrJsvJqui","address","city","htmltag","includetag","propName","html","codetabs","friends","fortag","members","sample","manager","anchor","people","firstName","lastName","street","header","action","propstag","ZIP","country","p1","p2","p3","iftag","standby","elsetag","commenttag","allowcodetag","customtagsapi","rendertmpl","tmplrender","object","method","tag","returns","d.render","db.render","compiletmpl","url","d.templates","jsrregister","tags","jsrobjects","viewsobject","settingsobject","subobject","templateobject","viewobject","tagobject","ctxobject","tagctxobject","node/browserify","node/renderfile","node/filetmpls","jsrnode","node/install","node/express-hapi","node/server-browser","tagsyntax","paths","tmplsyntax","settings","settings/delimiters","settings/onerror","settings/dbgmode","settings/debugmode","settings/allowcode","onerror","advanced","apps","getindex","contextualparams","parentdata","jsrmodel","helpersapi","helpers","convertersapi","converters","nojqueryapi","node/webpack","viewmodelsapi","lifecycle","globals","tagsapi"],"mappings":"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","file":"contents-jsrapi.min.js","sourcesContent":["var content = $.views.documentation.content;\r\n\r\ncontent.jsrapi = content.useStorage && $.parseJSON(localStorage.getItem(\"JsViewsDocTopics/jsrapi\")) ||\r\n{\r\n \"jsrapi\": {\r\n \"title\": \"JsRender API topics\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See [*JsRender Quickstart*](#jsr-quickstart) for an introductory overview.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Topics:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tmplsyntax\",\r\n \"label\": \"Template syntax and structure\"\r\n },\r\n {\r\n \"hash\": \"jsrtags\",\r\n \"label\": \"Template tags\"\r\n },\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"hash\": \"apps\",\r\n \"label\": \"Building apps\"\r\n },\r\n {\r\n \"hash\": \"nojqueryapi\",\r\n \"label\": \"JsRender without jQuery\"\r\n },\r\n {\r\n \"hash\": \"settings\",\r\n \"label\": \"Settings\"\r\n },\r\n {\r\n \"hash\": \"advanced\",\r\n \"label\": \"Advanced\"\r\n },\r\n {\r\n \"hash\": \"jsrnode\",\r\n \"label\": \"JsRender on Node.js\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrtags\": {\r\n \"title\": \"Template tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Tag syntax\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"JsRender and JsViews tag syntax\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tags without content\",\r\n \"text\": \"- [`{{: ...}}`](#assigntag) (Evaluate)\\n- [`{{> ...}}`](#htmltag) (HTML encode)\\n- [`{{!-- ... --}}`](#commenttag) (Comment)\\n- [`{{* ...}} and {{*: ...}}`](#allowcodetag) (Allow code)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags\",\r\n \"text\": \"- [`{{include ...}}`](#includetag) (Template composition -- partials)\\n- [`{{for ...}}`](#fortag) (Template composition, with iteration over arrays)\\n- [`{{props ...}}`](#propstag) (Iteration over properties of an object)\\n- [`{{if ...}}`](#iftag) (Conditional inclusion)\\n- [`{{mytag ...}}`](#customtagsapi) (Custom tags)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternative content blocks\",\r\n \"text\": \"- [`{{else ...}}`](#elsetag) (Content block separator)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Additional tags in JsViews\",\r\n \"text\": \"When using data-linked templates, with *JsViews*, the following additional template tags are available:\\n\\n- [`{^{radiogroup ...}}`](#jsvradiogrouptag) (Radio button group)\\n- [`{^{on ...}}`](#jsvontag) (Button, or event binding)\\n\\n*See: [Template tags in JsViews](#jsvtags)*\"\r\n }\r\n ]\r\n },\r\n \"assigntag\": {\r\n \"title\": \"Template tag: {{: ...}} (Evaluate)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{: ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert data value or calculated value\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Data-path or expression, to be evaluated and inserted as a string in the rendered output\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{:address.street}}\",\r\n \"description\": \"Evaluate the data-path or expression\",\r\n \"variant\": \"{{:pathOrExpr}}\"\r\n }\r\n ],\r\n \"description\": \"Get the value of the data path or expression, and insert it into the rendered output as a string\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Here are some examples:\",\r\n \"text\": \"(Note the use of different kinds of data-path and expression in the different examples)\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Data:\",\r\n \"code\": \"{name: \\\"Pete\\\"}\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Template:\",\r\n \"markup\": \"{{:name}}\"\r\n }\r\n ],\r\n \"data\": {\r\n \"name\": \"Pete\"\r\n },\r\n \"markup\": \"{{:name}}\",\r\n \"height\": \"38\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:dataproperty}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n{\\n name: \\\"Pete\\\",\\n address: {\\n city: \\\"Seattle\\\"\\n }\\n}\\n```\\n\\n`~root` is the top-level data, and `#data` is the current data item\\n\\n```jsr\\n{{:name}} ... {{:address.city}}\\n\\n... {{:~root.address.city}}\\n\\n... {{:#data.address.city}}\\n```\"\r\n }\r\n ],\r\n \"data\": {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n \"markup\": \"{{:name}}: lives in {{:address.city}}.
                          \\n\\nHere is ~root.address.city: {{:~root.address.city}}
                          \\n\\nHere is #data.address.city: {{:#data.address.city}}\",\r\n \"height\": \"74\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:data.paths}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n[\\n {name: \\\"Pete\\\", ...},\\n {name: \\\"Heidi\\\", ...}\\n]\\n```\\n\\n`#xxx` is the `xxx` property of the current view -- so `#index` is the `view.index` \\n\\n```jsr\\n{{:#index+1}}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"{{:#index+1}}:\\n{{:name}}: lives in {{:address.city}}.
                          \",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ],\r\n \"height\": \"56\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{:#index ...}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"***Note:*** When rendering data which is not fully trusted, such as `{{:untrustedValue}}` it would be preferable from a security point of view to use the `{{>untrustedValue}}` -- since the [`{{> ...}}`](#htmltag) tag will HTML encode the data, and thus prevent HTML injection attacks.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Sample: Converters and encoding\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvassigntag\",\r\n \"label\": \"JsViews: {^{: ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"htmltag\": {\r\n \"title\": \"Template tag: {{> ...}} (HTML encode)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{>...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert HTML-encoded data value or calculated value\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Data-path or expression, to be evaluated and inserted as an HTML-encoded string in the rendered output\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{>address.street}}\",\r\n \"description\": \"Evaluate the data-path or expression, and HTML encode the result\",\r\n \"variant\": \"{{>pathOrExpr}}\"\r\n }\r\n ],\r\n \"description\": \"Get the HTML-encoded value of the data path or expression, and insert it into the rendered output\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Data:\",\r\n \"code\": \"{description: \\\"A very nice apartment\\\"}\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Template:\",\r\n \"markup\": \"{{:description}}\\n...\\n{{>description}}\"\r\n }\r\n ],\r\n \"data\": {\r\n \"description\": \"A very nice apartment\"\r\n },\r\n \"markup\": \"{{:description}}
                          \\n{{>description}}\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"title\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{> ...}} for preventing HTML injection attacks\",\r\n \"text\": \"The [`{{> ...}}`](#htmltag) tag should be used instead of the [`{{: ...}}`](#assigntag) whenever *data being rendered is not fully trusted* -- in order to protect against HTML injection attacks. \\n\\nUsing `{{>untrustedValue}}` ensures appropriate HTML encoding.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"convertersapi@html\",\r\n \"label\": \"HTML encoder\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Sample: Converters and encoding\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvhtmltag\",\r\n \"label\": \"JsViews: {^{> ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"includetag\": {\r\n \"title\": \"Template tag: {{include tmpl=... /}} (Template composition – partials)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{include tmpl=... /}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Include an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{include tmpl=\\\"insertedPersonTemplate\\\" /}}\",\r\n \"description\": \"Include the specified template\",\r\n \"variant\": \"{{include tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Include the referenced template: tmpl, rendered using the current data context.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:name}} lives in {{include tmpl=\\\"#addressTemplate\\\"/}}\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Seattle\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Sidney\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"\\n\\n\\n\\n
                          \",\r\n \"title\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{include}} to move to a new data context\",\r\n \"text\": \"`{{include}}` is similar to `{{for}}` in that it can take an argument for moving to a new data context -- as in the following examples: \\n\\n*Block tag with inline content:*\\n\\n```jsr\\n{{include address}}\\n {{:street}}\\n{{/include}}\\n```\\n\\n*Self-closing tag, referencing block content as `tmpl=...` :*\\n\\n```jsr\\n{{include address tmpl=\\\"#addressTemplate\\\"/}}\\n```\\n\\n```jsr\\n\\n```\\n\\nThe above two examples are equivalent to:\\n\\n```jsr\\n{{:address.street}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{include pathOrExpr}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{include pathOrExpr}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{include}}` block is the object returned by the path or expression.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If the object returned is an array, then the block is rendered once for each item, and the data context for each rendered block is the data item from the array.\"\r\n }\r\n ],\r\n \"example\": \"{{include billing.address}}\\n {{:city}}\\n{{/include}}\",\r\n \"description\": \"Render the block content of the tag, with the given object or array as data context\",\r\n \"variant\": \"{{include pathOrExpr}}...{{/include}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{include pathOrExpr}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{include billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template, with the given object or array as data context\",\r\n \"variant\": \"{{include pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Render the block content of the {{include}} (or the referenced external template), using the object or array specified by the path or expression as data context.

                          (Similar to {{for pathOrExpr}} but with no iteration over arrays...)\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Unlike `{{for objectOrArray}}`, `{{include objectOrArray}}` does not iterate over arrays.\\n\\nConsider this example:\\n\\n```jsr\\nNumber of friends: {{:friends.length}} {{!-- Get 'length' of 'friends' array --}}\\nFriends:\\n{{for friends}} {{!-- Iterate over 'friends' array --}}\\n {{name:}} {{!-- Current data context (#data) is a 'friend'. Get 'name' --}} \\n{{/for}}\\n```\\n\\nThe example could actually be rewritten, equivalently, as follows:\\n\\n```jsr\\n{{include friends}} {{!-- Move to 'friends' array as data context, no iteration --}}\\n Number of friends: {{:length}} {{!-- Current data context (#data) is 'friends'. Get 'length' --}}\\n Friends:\\n {{for}} {{!-- or {{for #data}} ... --}} {{!-- Iterate over current data context (friends array) --}}\\n {{name:}} \\n {{/for}}\\n{{/include}}\\n```\\n\\nHere it is as a running sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{include friends}}:\\n Number of friends {{:length}}\\n ...\\n{{/include}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"markup\": \"{{include friends}} {{!-- move to friends array as data context --}}\\n\\n Number of friends: {{:length}}. {{!-- length of friends array --}}\\n\\n
                          Friends:\\n\\n {{for}} {{!-- Iterate over current data context (friends array) --}}\\n {{:name}} \\n {{/for}}\\n\\n{{/include}}\",\r\n \"title\": \"{{include array}} does not iterate\",\r\n \"data\": {\r\n \"friends\": [\r\n {\r\n \"name\": \"Jeff\"\r\n },\r\n {\r\n \"name\": \"Fabien\"\r\n }\r\n ]\r\n },\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"55\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvincludetag\",\r\n \"label\": \"JsViews: {^{include ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"fortag\": {\r\n \"title\": \"Template tag: {{for ...}} (Template composition, with iteration over arrays)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{for ...}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{for}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{for}}` block is the object returned by the path or expression.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If the object returned is an array, then the block is rendered once for each item, and the data context for each rendered block is the data item from the array.\"\r\n }\r\n ],\r\n \"example\": \"{{for billing.address}}\\n {{:city}}\\n{{/for}}\",\r\n \"description\": \"Render the block content of the tag for the given object, or iterate over the given array\",\r\n \"variant\": \"{{for pathOrExpr}}...{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{for}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{for billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template for the given object, or iterate over the given array\",\r\n \"variant\": \"{{for pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Render the block content of the {{for}} (or the referenced external template), using the object or array specified by the path or expression as data context. If it is an array, iterate over the array, rendering once for each item.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here are some examples:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:name}} lives in \\n{{for address}}\\n {{>city}}\\n{{/for}}\\n\"\r\n }\r\n ],\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"html\": \"\",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ],\r\n \"markup\": \"
                          \\n {{:name}} lives in\\n {{for address}}\\n {{>city}}\\n {{/for}}\\n
                          \",\r\n \"title\": \"{{for object}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:name}} lives in {{for address tmpl=\\\"#addressTemplate\\\" /}}\\n```\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                          \",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Seattle\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"city\\\": \\\"Sidney\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"title\": \"{{for object tmpl=... /}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{:title}}\\n
                            \\n {{for members}}\\n
                          • {{:name}} ...
                          • \\n {{/for}}\\n
                          \"\r\n }\r\n ],\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"data\": {\r\n \"title\": \"The A team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"city\": \"Seattle\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"city\": \"Sidney\"\r\n }\r\n }\r\n ]\r\n },\r\n \"markup\": \"{{:title}}\\n
                            \\n {{for members}}\\n
                          • {{:name}} lives in {{:address.city}}
                          • \\n {{/for}}\\n
                          \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"90\",\r\n \"title\": \"{{for array}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{for}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{for}}` and `{{/for}}`, allows alternate rendering based on the object or array returned from the path or expression `{{for pathOrExpr}}`\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{for ...}}...{{else}}...{{/for}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on whether an array is empty or not\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"Path or expression for an object or array\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{for members}}\\n Name: {{:name}}\\n{{else}}\\n No members...\\n{{/for}}\",\r\n \"description\": \"Render first block if array is not empty, otherwise render second block\",\r\n \"variant\": \"{{for pathOrExpr}...{{else}}...{{/for}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional blocks: – Render the block content of the {{for}} tag (or referenced template) if the object is defined and is not an empty array, otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{for members}}\\n
                          {{:name}}
                          \\n{{else}}\\n
                          No members!
                          \\n{{/for}}\\n\"\r\n }\r\n ],\r\n \"markup\": \"{{:title}}\\n
                            \\n {{for members}}\\n
                          • Name: {{:name}}
                          • \\n {{else}}\\n
                          • No members!
                          • \\n {{/for}}\\n
                          \",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team\",\r\n \"members\": []\r\n },\r\n {\r\n \"title\": \"The B team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\"\r\n }\r\n ]\r\n }\r\n ],\r\n \"height\": \"134\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"{{for array}}...{{else}}...{{/for}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{for manager}}\\n
                        • Manager: {{:name}}
                        • \\n{{else}}\\n
                        • There is no team manager!
                        • \\n{{/for}}\"\r\n }\r\n ],\r\n \"markup\": \"{{:title}}\\n
                            \\n {{for manager}}\\n
                          • Manager: {{:name}}
                          • \\n {{else}}\\n
                          • There is no team manager!
                          • \\n {{/for}}\\n
                          \",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team2\",\r\n \"manager\": {\r\n \"name\": \"Pete\"\r\n }\r\n },\r\n {\r\n \"title\": \"The B team\"\r\n }\r\n ],\r\n \"title\": \"{{for object}}...{{else}}...{{/for}}\",\r\n \"height\": \"134\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Note:* A `{{for}}` tag (like an `{{if}}` tag) can have multiple `{{else}}` blocks. See for example [this sample](#jsvelsetag@for-else-multiple).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{for array}} with sorting and filtering, or specifying a range of items\",\r\n \"text\": \"When using the `{{for}}` tag to render arrays, built-in features allow sorting, filtering and 'slicing' the rendered list:\",\r\n \"anchor\": \"sortfilterrange\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The reverse property: specifying reverse ordering (or reverse sorting) on {{for array}}\",\r\n \"text\": \"To iterate over an array in reverse order, set the `reverse` property to `true`:\\n\\n```jsr\\n{{for array reverse=true }}...{{/for}}\\n```\\n\\nSetting `reverse=true` can be combined with using the [`sort`](#fortag@sort), [`filter`](#fortag@filter), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties, to reverse the order of iteration (for example to sort in *descending* order rather than *ascending* order).\",\r\n \"anchor\": \"reverse\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The sort property: specifying sorting on {{for array}}\",\r\n \"text\": \"To specify sorting, set the `sort` property: \\n\\n```jsr\\n{{for array sort=\\\"firstName\\\" }}...{{/for}}\\n```\\n\\n- If the array is an array of objects, the `sort=...` property of `{{for}}` is usually set to an object property to be sorted by, such as `firstName`, or to a data path, such as `sort=\\\"address.street\\\"`\\n- To sort an array of numbers, strings or `Date`s, set the `sort` property to the empty string: `sort=\\\"\\\"`\\n- For advanced scenarios you can provide your own sort function: `sort=~mySortFunction`\\n\\nSetting `sort=...` can be combined with using the [`reverse`](#fortag@reverse), [`filter`](#fortag@filter), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties.\\n\\nThe following three samples illustrate the above scenarios, using the `reverse` and `sort` properties:\",\r\n \"anchor\": \"sort\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                          Template:
                          *\\n```jsr\\n{{for colors sort=\\\"\\\" reverse=true}}...{{/for}} {{!-- (Reverse) sort array of strings --}}\\n{{for amounts sort=\\\"\\\"}}...{{/for}} {{!-- Sort array of Numbers --}}\\n{{for dates sort=\\\"\\\"}}...{{/for}} {{!-- Sort array of Dates --}}\\n```\\n\\n*
                          Data:
                          *\\n```js\\ncolors: [\\\"red\\\", ...],\\namounts: [33.001, ...],\\ndates: [new Date(2000, 0, 1), ...]\\n```\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"$.views.converters(\\\"formatDate\\\", function(date) {\\n // Converter to format Dates\\n return date.toLocaleDateString(\\\"en-US\\\");\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\n \\\"red\\\",\\n \\\"white\\\",\\n \\\"blue\\\"\\n ],\\n amounts: [\\n 33,\\n -2.333,\\n 2.4,\\n -22,\\n 22\\n ],\\n dates: [\\n new Date(2000, 0, 1),\\n new Date(1998, 6, 30),\\n new Date(2000, 11, 31)\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"110\",\r\n \"title\": \"Sorting an array of strings/Numbers/Dates\",\r\n \"anchor\": \"sortvalues\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                          Template:
                          *\\n```jsr\\n{{for people sort=\\\"firstName\\\"}}...{{/for}} {{!-- Sort by first name --}}\\n{{for people sort=\\\"lastName\\\" reverse=true}}...{{/for}} {{!-- Sort by last name, decreasing --}}\\n{{for people sort=\\\"address.street\\\"}} {{!-- Sort by address.street --}}\\n```\\n\\n*
                          Data:
                          *\\n```js\\npeople: [\\n {firstName: \\\"Jo\\\", ... address: {street: \\\"1st Street\\\" ...}},\\n ...\\n]\\n```\"\r\n }\r\n ],\r\n \"markup\": \"Sort by first name\\n
                            \\n {{for people sort=\\\"firstName\\\"}}\\n
                          • {{:firstName}} {{:lastName}}
                          • \\n {{/for}}\\n
                          \\n\\nSort by last name, decreasing\\n
                            \\n {{for people sort=\\\"lastName\\\" reverse=true}}\\n
                          • {{:firstName}} {{:lastName}}
                          • \\n {{/for}}\\n
                          \\n\\nSort by street\\n
                            \\n {{for people sort=\\\"address.street\\\"}}\\n
                          • {{:firstName}}: {{:address.street}}
                          • \\n {{/for}}\\n
                          \",\r\n \"data\": {\r\n \"people\": [\r\n {\r\n \"firstName\": \"Jo\",\r\n \"lastName\": \"Blow\",\r\n \"address\": {\r\n \"street\": \"1st Street\"\r\n }\r\n },\r\n {\r\n \"firstName\": \"Adriana\",\r\n \"lastName\": \"Zhang\",\r\n \"address\": {\r\n \"street\": \"1st Avenue\"\r\n }\r\n },\r\n {\r\n \"firstName\": \"Xavier\",\r\n \"lastName\": \"Rossi\",\r\n \"address\": {\r\n \"street\": \"2nd Street\"\r\n }\r\n }\r\n ]\r\n },\r\n \"height\": \"294\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Sorting an array of objects\",\r\n \"anchor\": \"sortobjects\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people sort=~multilevel}}...{{/for}} {{!-- Sort using a custom helper function: ~multilevel --}}\\n```\\n\\nThe custom sort function takes arguments `(a, b)` for the two objects being compared. The `this` pointer is the current `view` object.\\n\\n```js\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n return ... // Return 1, -1 or 0 to specify relative position of `a` and `b` in the sort order\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"// Helper function for multi-level sort\\nfunction level(aField, bField) {\\n return aField > bField ? 1 : aField < bField ? -1 : 0;\\n}\\n\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n // Sort by role, then by age (descending) then by name\\n return level(a.details.role.toLowerCase(), b.details.role.toLowerCase()) // by role\\n || level(b.details.age, a.details.age) // by age\\n || level(a.name.toLowerCase(), b.name.toLowerCase()); // by name\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: [\\n {name: \\\"Bill\\\", details: {age: 22, role: \\\"Lead\\\"}},\\n {name: \\\"Anne\\\", details: {age: 32, role: \\\"Assistant\\\"}},\\n {name: \\\"Emma\\\", details: {age: 19.1, role: \\\"Team member\\\"}},\\n {name: \\\"Jeff\\\", details: {age: 33.5, role: \\\"Lead\\\"}},\\n {name: \\\"Xavier\\\", details: {age: 32, role: \\\"Team member\\\"}},\\n {name: \\\"Julia\\\", details: {age: 18, role: \\\"Assistant\\\"}},\\n {name: \\\"Bill\\\", details: {age: 32, role: \\\"Team member\\\"}}\\n ]},\\n\\n html = myTmpl.render(data, { \\n multilevel: multilevelSort\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"150\",\r\n \"title\": \"Using a custom sort function: multi-level sort \",\r\n \"anchor\": \"sortcustom\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The filter property: specifying filtering on {{for array}}\",\r\n \"text\": \"To filter the rendered items, use the `filter` property to specify a filter function: \\n\\n```jsr\\n{{for array filter=~myfilter}}...{{/for}}\\n```\\n\\n```js\\nfunction myfilter(item, index, items) {\\n return ...; // Return true/false to include/exclude any item from the result\\n}\\n```\\n\\nThe filter function is called with the `tagCtx` object as `this` pointer, and with arguments:\\n\\n- `item`: The current item being processed in the array\\n- `index`: The index of the current item being processed in the array\\n- `array`: The array being filtered\\n\\nSetting `filter=...` can be combined with using the [`sort`](#fortag@sort), [`reverse`](#fortag@reverse), [`start`](#fortag@start-end), [`end`](#fortag@start-end) or [`step`](#fortag@start-end) properties (to filter the items after sorting or reversing, or before 'slicing').\\n\\nThe following sample renders a subset of an array of `people`, filtered by age:\",\r\n \"anchor\": \"filter\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction ageRangeFilter(item, index, items) {\\n return item.details.age > this.props.minAge ...\\n}\\n```\\n\\n```jsr\\n{{for people filter=~ageRange minAge=20 maxAge=40 sort=\\\"name\\\"}}...{{/for}}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"function ageRangeFilter(item, index, items) {\\n return item.details.age > this.props.minAge && item.details.age < this.props.maxAge;\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: [\\n {name: \\\"Bill\\\", details: {age: 25}},\\n {name: \\\"Anne\\\", details: {age: 32}},\\n {name: \\\"Emma\\\", details: {age: 19.1}},\\n {name: \\\"Jeff\\\", details: {age: 33.5}},\\n {name: \\\"Xavier\\\", details: {age: 52}},\\n {name: \\\"Julia\\\", details: {age: 18}},\\n {name: \\\"Jo\\\", details: {age: 30}}\\n ]},\\n\\n html = myTmpl.render(data, { \\n ageRange: ageRangeFilter\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample renders an array of `people` in a two row layout -- by filtering for the items with even (first row) and odd (second row) index.\\n\\n(See also an alternative approach using `step=...`, in the [section](#fortag@start-end) below).\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people filter=~evenOdd odd=false sort=\\\"name\\\"}}...{{/for}}\\n...\\n{{for people filter=~evenOdd odd=true sort=\\\"name\\\"}}...{{/for}}\\n``` \\n\\n```js\\nevenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data, {\\n evenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n }\\n });\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"100\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The start, end and step properties: limiting range and/or selecting every n'th item of {{for array}}\",\r\n \"text\": \"To limit the range of an array ('slice' the array) of rendered items, use the `start` and/or `end` properties to specify the starting and ending index. In addition, the `step` property lets you take every other *n'th* item in the array.\\n\\nThe behavior of start and end corresponds to the [array.slice(start, end)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) JavaScript method: \\n\\n- `start`: zero-based index at which to begin rendering\\n - A negative index indicates an offset from the end of the sequence\\n - If `start` is undefined, begins from index `0`\\n- `end`: zero-based index before which to end rendering (render up to but not including `end`)\\n - A negative index indicates an offset from the end of the sequence\\n - If `end` is undefined, render through the end of the array\\n- `step`: A positive integer *'n'*, in order to include every *nth* item, beginning with `start`. Defaults to `1`\\n\\n```jsr\\n{{for colors start=1 end=-1 step=2}}...{{/for}}\\n```\\n\\nSetting `start=...`, `end=...` and/or `step=...` can be combined with using the [`sort`](#fortag@sort), [`reverse`](#fortag@reverse), [`filter`](#fortag@filter) to limit the item selection, after sorting, reversing or filtering.\\n\\n```jsr\\n{{for colors sort=\\\"name\\\" start=1 end=-1}}...{{/for}}\\n```\\n\\nThe following sample illustrates the use of `start=...` and `end=...` with or without sorting:\",\r\n \"anchor\": \"start-end\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for colors}}...{{/for}}\\n{{for colors start=1 end=-1}}...{{/for}}\\n{{for colors step=2}}...{{/for}}\\n{{for colors step=2 start=1}}...{{/for}}\\n{{for colors sort=\\\"\\\"}}...{{/for}}\\n{{for colors sort=\\\"\\\" start=1 end=-1}}...{{/for}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\\"red\\\", \\\"orange\\\", \\\"yellow\\\", \\\"green\\\", \\\"blue\\\", \\\"indigo\\\", \\\"violet\\\"]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"200\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample uses `step=...` to render multi-row layouts of an array of people:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people step=3 start=0 sort=\\\"name\\\" end=-2}}\\n{{for people step=3 start=1 sort=\\\"name\\\" end=-2}}\\n{{for people step=3 start=2 sort=\\\"name\\\" end=-2}}\\n```\\n\\n```jsr\\n{{for people step=2 start=0 sort=\\\"name\\\" reverse=true}}\\n{{for people step=2 start=1 sort=\\\"name\\\" reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"220\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sorting, filtering, 'slicing' operations in any order\",\r\n \"text\": \"Some of the above samples include applying a sort operation followed by a 'slice' operation. It is also possible reverse the order of operations, and to limit the range **_before_** sorting the result, as in the following two examples:\",\r\n \"anchor\": \"anyorder\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people end=-2 noIteration=true}} {{!-- slice (remove last two) --}}\\n ...\\n {{for #data step=3 start=0 sort=\\\"name\\\"}} {{!-- sort ... --}}\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"height\": \"132\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for colors start=1 end=-1 noIteration=true}} {{!-- slice (remove first and last) --}}\\n {{for #data sort=\\\"\\\"}}...{{/for}} {{!-- sort ... --}}\\n{{/for}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: [\\\"red\\\", \\\"orange\\\", \\\"yellow\\\", \\\"green\\\", \\\"blue\\\", \\\"indigo\\\", \\\"violet\\\"]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"42\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A similar approach can be used to apply any desired `filter`, `sort`, `reverse`, or 'slice' operations in any order. For example:\\n\\n```jsr\\n{{for colors filter=~preSort noIteration=true}}\\n {{for #data sort=... noIteration=true}}\\n {{for #data filter=~afterSort}}...{{/for}}\\n {{/for}}\\n{{/for}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{for start=... end=... step=...}} to iterate over a range of numbers\",\r\n \"text\": \"The `{{for}}` tag can be used to iterate over a range of numbers, rather than iterating over a data array.\\n\\nFor example:\\n\\n```jsr\\n{{for start=0 end=4}}{{:}}, {{/for}}\\n```\\n\\nwill render the result `0, 1, 2, 3, `.\\n\\nBy setting the `start` and `end` properties (and optionally the `step` property) to appropriate `Numbers`, *but without providing any argument as data array*, the `{{for}}` tag will in fact generate a corresponding array of numbers (usually integers), and will iterate over that generated array.\\n\\n- `start`: Initial number for generated array. If undefined, defaults to `0`\\n- `end`: Number before which to end the array (generate numbers up to but not including `end`)\\n- `step`: Optional: the incremental amount for subsequent numbers in the array. Defaults to `1`\\n\\nFor example:\\n\\n```jsr\\n{{for start=4.5 end=-2 step=-1.5}}{{:}}, {{/for}}\\n```\\n\\nwill output `4.5, 3, 1.5, 0, -1.5, `\\n\\nThe following sample uses generated arrays to render table layouts of `people` 'by rows':\",\r\n \"anchor\": \"number-range\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Sorted table, by rows:*\\n\\n```jsr\\n{{for end=people.length/2 itemVar='~row'}}\\n \\n {{for ~root.people start=~row*2 end=(~row+1)*2 sort=\\\"name\\\"}}\\n \\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"240\",\r\n \"title\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Use of itemVar with noIteration=true, to reference the array\",\r\n \"text\": \"Note the use of `itemVar='~row'` in the above examples. [`itemVar`](#contextualparams@itemvar) is used to provide an alias for the current data in the wrapped content, so in this case it is the current integer as we iterate over the generated array.\\n\\nSo the following:\\n\\n```jsr\\n{{for start=0 end=4 itemVar='row'}}{{:~row}} {{/for}}\\n```\\n\\n```jsr\\n{{for start=0 end=4}}{{:}} {{/for}}\\n```\\n\\nare equivalent, and each render the result `\\\"0 1 2 3\\\"`.\\n\\nBy setting `noIteration=true` we can instead use `itemVar` for the array itself, as in the following sample:\",\r\n \"anchor\": \"itemvar\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for start=1 end=7 noIteration=true itemVar=\\\"~cols\\\"}} {{!-- ~rows is an array from 1 to 6 --}}\\n {{for start=1 end=5 noIteration=true itemVar=\\\"~rows\\\"}} {{!-- ~cols is an array from 1 to 4 --}}\\n
                          ...{{:name}}
                          \\n {{for ~rows itemVar=\\\"~j\\\"}} {{!-- iterate over ~rows array --}}\\n \\n {{for ~cols itemVar=\\\"~i\\\"}} {{!-- iterate over ~cols array --}}\\n \\n```\"\r\n }\r\n ],\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n html = myTmpl.render({});\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"title\": \"itemVar - passing arrays around then iterating over them\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following more advanced approach to sorting by columns uses the `noIteration=true itemVar=\\\"~sorted\\\"` technique:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people sort=\\\"name\\\" noIteration=true itemVar=\\\"~sorted\\\"}} {{!-- ~sorted is the sorted people array --}}\\n ...\\n {{for end=length step=2 itemVar=\\\"~col\\\"}} {{!-- iterate over even integers from 0 to ~sorted.length--}}\\n {{!-- render the person.name for ~sorted items with index 0, 2, 4... --}}\\n ...\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"100\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Xavier\\\"},\\n {name: \\\"Juanita\\\"},\\n {name: \\\"Adeline\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Jeff\\\"},\\n {name: \\\"Paul\\\"}\\n ]\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also the ['range' sample](#jsvfortag@jsvsortfilterrange), for an example of dynamic use of the `start` and `end` properties of `{{for}}`, along with JsViews data-linking.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/paths\",\r\n \"label\": \"Sample: Paths\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvfortag\",\r\n \"label\": \"JsViews: {^{for ...}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"getindex\",\r\n \"label\": \"getIndex(): accessing array index\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"propstag\": {\r\n \"title\": \"Template tag: {{props ...}} (Iteration over properties of an object)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{props ...}}\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{props}} using an inline block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{props}}` block is an object with properties `key` and `props`:\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"{\\n key: propertyName,\\n prop: propertyValue // could be a string, number, object, etc.\\n}\"\r\n }\r\n ],\r\n \"example\": \"{{props billing.address}}\\n {{>key}}: {{>prop}}\\n{{/props}}\",\r\n \"description\": \"Render the block content of the tag for each property of the given object\",\r\n \"variant\": \"{{props pathOrExpr}}...{{/props}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"{{props}} using an external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered instead of block content\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{props billing.address tmpl=\\\"addressTmpl\\\" /}}\",\r\n \"description\": \"Render the specified template once for each property of the given object\",\r\n \"variant\": \"{{props pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Template composition: – Iterate over the properties of the object, and render the block content of the {{props}} tag (or the referenced external template) once for each property – using as data context: {key: propertyName, prop: propertyValue}.\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here are some examples:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"...\\n{{props address}}\\n {{>key}}: {{>prop}}
                          \\n{{/props}}\\n\"\r\n }\r\n ],\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"200\",\r\n \"html\": \"\",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"street\": \"12 Pike Place\",\r\n \"city\": \"Seattle\",\r\n \"ZIP\": \"98101\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {\r\n \"street\": \"5000 Broadway\",\r\n \"city\": \"Sidney\",\r\n \"country\": \"Australia\"\r\n }\r\n }\r\n ],\r\n \"markup\": \"
                          {{:~i}}, {{:~j}}... {{:~sorted[~col].name}}
                          \\n \\n \\n
                          name: {{:name}}
                          \\n {{props address}}\\n {{>key}}: {{>prop}}
                          \\n {{/props}}\\n
                          \",\r\n \"title\": \"{{props object}}\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props address tmpl=\\\"#addressTemplate\\\" /}}\\n```\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                          \",\r\n \"code\": \"var people = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },\\n {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"5000 Broadway\\\",\\n \\\"city\\\": \\\"Sidney\\\",\\n \\\"country\\\": \\\"Australia\\\"\\n }\\n }\\n];\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"200\",\r\n \"title\": \"{{props object tmpl=... /}}\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{props}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{props}}` and `{{/props}}`, allows alternate rendering based on the object returned from the path or expression `{{props pathOrExpr}}`\",\r\n \"anchor\": \"else\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{props ...}}...{{else}}...{{/props}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on whether an object is empty or not\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"A data path, or an object\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{props address}}\\n Key: {{:key}} Value: {{:prop}}\\n{{else}}\\n No properties...\\n{{/for}}\",\r\n \"description\": \"Render first block if object is not empty, otherwise render second block\",\r\n \"variant\": \"{{for pathOrExpr}...{{else}}...{{/for}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional blocks: – Render the block content of the {{prop}} tag (or referenced template) if the object is defined and is not an empty object (no properties), otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"{{props address}}\\n {{>key}}: {{>prop}}
                          \\n{{else}}\\n The address is blank (no properties)!\\n{{/props}}\"\r\n }\r\n ],\r\n \"markup\": \"\\n \\n \\n
                          name: {{:name}}
                          \\n {{props address}}\\n {{>key}}: {{>prop}}
                          \\n {{else}}\\n The address is blank (no properties)!\\n {{/props}}\\n
                          \",\r\n \"data\": [\r\n {\r\n \"name\": \"Pete\",\r\n \"address\": {\r\n \"street\": \"12 Pike Place\",\r\n \"city\": \"Seattle\",\r\n \"ZIP\": \"98101\"\r\n }\r\n },\r\n {\r\n \"name\": \"Heidi\",\r\n \"address\": {}\r\n }\r\n ],\r\n \"height\": \"160\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props USaddress}}\\n {{>key}}: {{>prop}}
                          \\n{{else UKaddress}}\\n {{>key}}: {{>prop}}
                          \\n{{else}}\\n The address is blank (no properties)!\\n{{/props}}\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = [\\n {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"USaddress\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },{\\n \\\"name\\\": \\\"Jeff\\\",\\n \\\"UKaddress\\\": {\\n \\\"street\\\": \\\"3a Upton Place\\\",\\n \\\"city\\\": \\\"London\\\",\\n \\\"code\\\": \\\"W2 1JA\\\"\\n }\\n },{\\n \\\"name\\\": \\\"Heidi\\\",\\n }\\n ],\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"240\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The noFunctions property\",\r\n \"text\": \"By default `{{props}}` will iterate over all members of an object, including members of type: *function* (methods). To prevent outputting members of type *function*, set the `noFunctions` property to `true`:\\n\\n```jsr\\n{{props ... noFunctions=true}}\\n```\\n\\n\",\r\n \"anchor\": \"nofunctions\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props person noFunctions=true}}\\n {{>key}}: {{>prop}}
                          \\n{{/props}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {\\n person: {\\n first: \\\"Jo\\\",\\n last: \\\"Blow\\\",\\n fullName: function() {\\n return this.first + \\\" \\\" + this.last;\\n }\\n }\\n },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"120\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{props}} to iterate over a top-level dictionary/hash data-collection\",\r\n \"text\": \"If the data (obtained for example, from the server) is a collection, but in the form of an object (dictionary/hash) rather than an array, then *__`{{props}}`__* without arguments (or equivalently *__`{{props #data}}`__*) can be used to iterate over the collection, as shown in the next sample:\\n\\n(When using JsViews, see also [`{^{props}}`](#jsvpropstag@load-hash) for loading and providing complete editability of a top-level dictionary/hash.)\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Dictionary/hash -- collection of people:*\\n\\n```js\\nvar people = {\\n pt1: {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n ...\\n }\\n },\\n Hd1: {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n ...\\n }\\n }\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n
                          \",\r\n \"code\": \"var people = {\\n pt1: {\\n \\\"name\\\": \\\"Pete\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"12 Pike Place\\\",\\n \\\"city\\\": \\\"Seattle\\\",\\n \\\"ZIP\\\": \\\"98101\\\"\\n }\\n },\\n Hd1: {\\n \\\"name\\\": \\\"Heidi\\\",\\n \\\"address\\\": {\\n \\\"street\\\": \\\"5000 Broadway\\\",\\n \\\"city\\\": \\\"Sidney\\\",\\n \\\"country\\\": \\\"Australia\\\"\\n }\\n }\\n};\\n\\nvar html = $(\\\"#peopleTemplate\\\").render(people);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"height\": \"194\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using {{props}} with specific sorting, filtering or range of the rendered properties\",\r\n \"text\": \"When using the `{{props}}` tag to render properties, built-in features allow sorting, filtering and 'slicing' of the rendered list. (These features correspond exactly to the equivalent [sorting and filtering](#fortag@sortfilterrange) features provided by the`{{for}}` tag):\",\r\n \"anchor\": \"sortfilterrange\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The reverse property: specifying reverse ordering (or reverse sorting) on {{props object}}\",\r\n \"text\": \"To iterate over the object properties in reverse order, set the `reverse` property to `true`:\\n\\n```jsr\\n{{props object reverse=true }}...{{/props}}\\n```\\n\\nSetting `reverse=true` can be combined with using the [`sort`](#propstag@sort), [`filter`](#propstag@filter), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties, to reverse the order of iteration (for example to sort in *descending* order rather than *ascending* order).\",\r\n \"anchor\": \"reverse\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The sort property: specifying sorting on {{props object}}\",\r\n \"text\": \"To specify sorting, set the `sort` property: \\n\\n```jsr\\n{{props object sort=\\\"prop.firstName\\\" }}...{{/props}}\\n```\\n\\n- To sort the properties by *key*, set `sort=\\\"key\\\"`\\n- If the properties are objects (a 'hash' of objects), the `sort=...` property of `{{props}}` is usually set to an object property to be sorted by, such as `prop.firstName`, or to a data path, such as `sort=\\\"prop.address.street\\\"`\\n- To sort a hash of numbers, strings or `Date`s, set the `sort` property to: `sort=\\\"prop\\\"`\\n- For advanced scenarios you can provide your own sort function: `sort=~mySortFunction`\\n\\nSetting `sort=...` can be combined with using the [`reverse`](#propstag@reverse), [`filter`](#propstag@filter), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties.\\n\\nThe following three samples illustrate the above scenarios, using the `reverse` and `sort` properties:\",\r\n \"anchor\": \"sort\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                          Template:
                          *\\n```jsr\\n{{props colors sort=\\\"prop\\\" reverse=true}} {{!-- (Reverse) sort string properties --}}\\n{{props amounts sort=\\\"key\\\"}} {{!-- Sort Number properties by key --}}\\n{{props dates sort=\\\"prop\\\"}} {{!-- Sort Date properties --}}\\n```\\n\\n*
                          Data:
                          *\\n```js\\ncolors: {c1: \\\"red\\\", ...},\\namounts: {\\\"1st quarter\\\": 111.2, ...},\\ndates: {Created: new Date(2000, 0, 1), ...}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"$.views.converters(\\\"formatDate\\\", function(date) {\\n // Converter to format Dates\\n return date.toLocaleDateString(\\\"en-US\\\");\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"white\\\",\\n c3: \\\"blue\\\"\\n },\\n amounts: {\\n \\\"1st quarter\\\": 111.2,\\n \\\"3rd quarter\\\": -2.33,\\n \\\"4th quarter\\\": 2.4,\\n \\\"2nd quarter\\\": -22\\n },\\n dates: {\\n Created: new Date(2000, 0, 1),\\n Deleted: new Date(2000, 11, 31),\\n Edited: new Date(1998, 6, 30)\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"110\",\r\n \"title\": \"Sorting strings/Numbers/Date properties\",\r\n \"anchor\": \"sortvalues\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*
                          Template:
                          *\\n```jsr\\n{{props people sort=\\\"prop.lastName\\\" reverse=true}}...{{/props}} {{!-- Sort by last name, decreasing --}}\\n{{props people sort=\\\"prop.address.street\\\"}} {{!-- Sort by address.street --}}\\n{{props people sort=\\\"key\\\" reverse=true}} {{!-- Reverse sort by key --}}\\n```\\n\\n*
                          Data:
                          *\\n```js\\npeople: {\\n p1: {firstName: \\\"Jo\\\", ... address: {street: \\\"1st Street\\\" ...}},\\n ...\\n}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"Sort by last name, decreasing\\n
                            \\n {{props people sort=\\\"prop.lastName\\\" reverse=true}}\\n
                          • {{:prop.firstName}} {{:prop.lastName}}
                          • \\n {{/props}}\\n
                          \\n\\nSort by street\\n
                            \\n {{props people sort=\\\"prop.address.street\\\"}}\\n
                          • {{:prop.firstName}}: {{:prop.address.street}}
                          • \\n {{/props}}\\n
                          \\n\\nReverse sort by key\\n
                            \\n {{props people sort=\\\"key\\\" reverse=true}}\\n
                          • {{:key}}: {{:prop.firstName}} {{:prop.lastName}}
                          • \\n {{/props}}\\n
                          \",\r\n \"data\": {\r\n \"people\": {\r\n \"p1\": {\r\n \"firstName\": \"Jo\",\r\n \"lastName\": \"Blow\",\r\n \"address\": {\r\n \"street\": \"1st Street\"\r\n }\r\n },\r\n \"p2\": {\r\n \"firstName\": \"Adriana\",\r\n \"lastName\": \"Zhang\",\r\n \"address\": {\r\n \"street\": \"1st Avenue\"\r\n }\r\n },\r\n \"p3\": {\r\n \"firstName\": \"Xavier\",\r\n \"lastName\": \"Rossi\",\r\n \"address\": {\r\n \"street\": \"2nd Street\"\r\n }\r\n }\r\n }\r\n },\r\n \"height\": \"290\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Sorting a hash of objects\",\r\n \"anchor\": \"sortobjects\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people sort=~multilevel}}...{{/props}} {{!-- Sort using a custom helper function: ~multilevel --}}\\n```\\n\\nThe custom sort function takes arguments `(a, b)` for the two objects being compared. The `this` pointer is the current `view` object.\\n\\n```js\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n return ... // Return 1, -1 or 0 to specify relative position of `a` and `b` in the sort order\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"// Helper function for multi-level sort\\nfunction level(aField, bField) {\\n return aField > bField ? 1 : aField < bField ? -1 : 0;\\n}\\n\\n// Custom sort function\\nfunction multilevelSort(a, b) {\\n // Sort by role, then by age (descending) then by name\\n return level(a.prop.details.role.toLowerCase(), b.prop.details.role.toLowerCase()) // by role\\n || level(b.prop.details.age, a.prop.details.age) // by age\\n || level(a.prop.name.toLowerCase(), b.prop.name.toLowerCase()); // by name\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {people: {\\n p1: {name: \\\"Bill\\\", details: {age: 22, role: \\\"Lead\\\"}},\\n p2: {name: \\\"Anne\\\", details: {age: 32, role: \\\"Assistant\\\"}},\\n p3: {name: \\\"Emma\\\", details: {age: 19.1, role: \\\"Team member\\\"}},\\n p4: {name: \\\"Jeff\\\", details: {age: 33.5, role: \\\"Lead\\\"}},\\n p5: {name: \\\"Xavier\\\", details: {age: 32, role: \\\"Team member\\\"}},\\n p6: {name: \\\"Julia\\\", details: {age: 18, role: \\\"Assistant\\\"}},\\n p7: {name: \\\"Bill\\\", details: {age: 32, role: \\\"Team member\\\"}}\\n }},\\n\\n html = myTmpl.render(data, { \\n multilevel: multilevelSort\\n });\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"150\",\r\n \"title\": \"Using a custom sort function: multi-level sort \",\r\n \"anchor\": \"sortcustom\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The filter property: specifying filtering on {{props object}}\",\r\n \"text\": \"To filter the rendered properties, use the `filter` property to specify a filter function: \\n\\n```jsr\\n{{props object filter=~myfilter}}...{{/props}}\\n```\\n\\n```js\\nfunction myfilter(item, index, items) {\\n return ...; // Return true/false to include/exclude any item from the result\\n}\\n```\\n\\nThe filter function is called with the `tagCtx` object as `this` pointer, and with arguments:\\n\\n- `item`: The current `{key:..., prop:...}` 'property' object being processed\\n- `index`: The index of the current item being processed in the (sorted) array of 'property' objects\\n- `array`: The (sorted) array of 'property' objects being filtered\\n\\nSetting `filter=...` can be combined with using the [`sort`](#propstag@sort), [`reverse`](#propstag@reverse), [`start`](#propstag@start-end), [`end`](#propstag@start-end) or [`step`](#propstag@start-end) properties (to filter the items after sorting or reversing, or before 'slicing').\\n\\n\\nThe following sample renders a subset of a hash of `people`, filtered by age:\",\r\n \"anchor\": \"filter\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction ageRangeFilter(item, index, items) {\\n return item.prop.details.age > this.props.minAge ...\\n}\\n```\\n\\n```jsr\\n{{props people filter=~ageRange minAge=20 maxAge=40 sort=\\\"prop.name\\\"}}...{{/props}}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"120\",\r\n \"code\": \"function ageRangeFilter(item, index, items) {\\n return item.prop.details.age > this.props.minAge && item.prop.details.age < this.props.maxAge;\\n}\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Bill\\\", details: {age: 25}},\\n p2: {name: \\\"Anne\\\", details: {age: 32}},\\n p3: {name: \\\"Emma\\\", details: {age: 19.1}},\\n p4: {name: \\\"Jeff\\\", details: {age: 33.5}},\\n p5: {name: \\\"Xavier\\\", details: {age: 52}},\\n p6: {name: \\\"Julia\\\", details: {age: 18}},\\n p7: {name: \\\"Jo\\\", details: {age: 30}}\\n }\\n },\\n\\n html = myTmpl.render(data, { \\n ageRange: ageRangeFilter\\n });\\n\\n$(\\\"#page\\\").html(html);\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample renders a hash of `people` in a two row layout -- by filtering for the items with even (first row) and odd (second row) index.\\n\\n(See also an alternative approach using `step=...`, in the [section](#propstag@start-end) below).\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people filter=~evenOdd odd=false sort=\\\"prop.name\\\"}}...{{/props}}\\n...\\n{{props people filter=~evenOdd odd=true sort=\\\"prop.name\\\"}}...{{/props}}\\n``` \\n\\n```js\\nevenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data, {\\n evenOdd: function(item, index, items) {\\n return this.props.odd === (index%2 === 1); // Include only items with even/odd index\\n }\\n });\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"100\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The start, end and step properties: limiting range and/or selecting every n'th item of {{props object}}\",\r\n \"text\": \"To limit the range of rendered properties, use the `start` and/or `end` properties to specify the starting and ending index. In addition, the `step` property lets you take every other *n'th* item in the array of 'property' objects.\\n\\nThe behavior of start and end corresponds to the [array.slice(start, end)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) JavaScript method: \\n\\n- `start`: zero-based index at which to begin rendering\\n - A negative index indicates an offset from the end of the sequence\\n - If `start` is undefined, begins from index `0`\\n- `end`: zero-based index before which to end rendering (render up to but not including `end`)\\n - A negative index indicates an offset from the end of the sequence\\n - If `end` is undefined, render through the end of the array\\n- `step`: A positive integer *'n'*, in order to include every *nth* item, beginning with `start`. Defaults to `1`\\n\\n```jsr\\n{{props colors start=1 end=-1 step=2}}...{{/props}}\\n```\\n\\nSetting `start=...`, `end=...` and/or `step=...` can be combined with using the [`sort`](#propstag@sort), [`reverse`](#propstag@reverse), [`filter`](#propstag@filter) to limit the range, after sorting, reversing or filtering.\\n\\n```jsr\\n{{props colors sort=\\\"name\\\" start=1 end=-1 step=2}}...{{/props}}\\n```\\n\\nThe following sample illustrates the use of `start=...` and `end=...` with or without sorting:\",\r\n \"anchor\": \"start-end\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props colors}}...{{/props}}\\n{{props colors start=1 end=-1}}...{{/props}}\\n{{props colors step=2}}...{{/props}}\\n{{props colors step=2 start=1}}...{{/props}}\\n{{props colors sort=\\\"name\\\"}}...{{/props}}\\n{{props colors sort=\\\"name\\\" start=1 end=-1}}...{{/props}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"header\": \"\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"orange\\\",\\n c3: \\\"yellow\\\",\\n c4: \\\"green\\\",\\n c5: \\\"blue\\\",\\n c6: \\\"indigo\\\",\\n c7: \\\"violet\\\"\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"height\": \"200\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following sample uses `step=...` to render multi-row layouts of a hash of people:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people step=3 start=0 sort=\\\"name\\\" end=-2}}\\n{{props people step=3 start=1 sort=\\\"name\\\" end=-2}}\\n{{props people step=3 start=2 sort=\\\"name\\\" end=-2}}\\n```\\n\\n```jsr\\n{{props people step=2 start=0 sort=\\\"name\\\" reverse=true}}\\n{{props people step=2 start=1 sort=\\\"name\\\" reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"height\": \"220\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sorting, filtering, 'slicing' operations in any order\",\r\n \"text\": \"Some of the above samples include applying a sort operation followed by a 'slice' operation. It is also possible reverse the order of operations, and to limit the range **_before_** sorting the result, as in the following two examples:\",\r\n \"anchor\": \"anyorder\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props people end=-2 noIteration=true}} {{!-- slice (remove last two) --}}\\n ...\\n {{for #data step=3 sort=\\\"prop.name\\\"}} {{!-- sort ... --}}\\n ...\\n```\"\r\n }\r\n ],\r\n \"height\": \"132\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n people: {\\n p1: {name: \\\"Jo\\\"},\\n p2: {name: \\\"Adriana\\\"},\\n p3: {name: \\\"Xavier\\\"},\\n p4: {name: \\\"Juanita\\\"},\\n p5: {name: \\\"Adeline\\\"},\\n p6: {name: \\\"Pete\\\"},\\n p7: {name: \\\"Jeff\\\"},\\n p8: {name: \\\"Paul\\\"}\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{props colors start=1 end=-1 noIteration=true}} {{!-- slice (remove first and last) --}}\\n {{for #data sort=\\\"prop\\\"}}...{{/for}} {{!-- sort ... --}}\\n{{/props}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\"#myTmpl\\\"),\\n\\n data = {\\n colors: {\\n c1: \\\"red\\\",\\n c2: \\\"orange\\\",\\n c3: \\\"yellow\\\",\\n c4: \\\"green\\\",\\n c5: \\\"blue\\\",\\n c6: \\\"indigo\\\",\\n c7: \\\"violet\\\"\\n }\\n },\\n\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"42\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A similar approach can be used to apply any desired `filter`, `sort`, `reverse`, or 'slice' operations in any order. For example:\\n\\n```jsr\\n{{props colors filter=~preSort noIteration=true}}\\n {{for #data sort=... noIteration=true}}\\n {{for #data filter=~afterSort}}...{{/for}}\\n {{/for}}\\n{{/props}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/paths\",\r\n \"label\": \"Sample: Paths\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvpropstag\",\r\n \"label\": \"JsViews: {^{props ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"iftag\": {\r\n \"title\": \"Template tag: {{if ...}} (Conditional inclusion)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Conditional block\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{if}}` block is the same as the outer context\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{/if}}\",\r\n \"description\": \"Render the block only if the expression is true\",\r\n \"variant\": \"{{if pathOrExpr}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Conditional inclusion of external template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{if nickname tmpl=\\\"nicknameTemplate\\\" /}}\",\r\n \"description\": \"Render the specified template only if the expression is true\",\r\n \"variant\": \"{{if pathOrExpr tmpl=nameOrExpr /}}\"\r\n }\r\n ],\r\n \"description\": \"Conditional inclusion: – Render the block content of the {{if}} tag (or the referenced external template) only if the data-path or expression evaluates to true (or a 'truthy' value)\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the {{else}} tag with {{if}}\",\r\n \"text\": \"Using the `{{else}}` tag between `{{if}}` and `{{/if}}`, allows alternate rendering based on 'if ... else ...' logic:\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ...}}...{{else}}...{{/if}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on an expression\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: The data context inside the `{{if}}` and `{{else}}` blocks is the same as the outer context\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{else}}\\n No nickname...\\n{{/if}}\",\r\n \"description\": \"Render first block if condition is true, otherwise render second block\",\r\n \"variant\": \"{{if pathOrExpr}...{{else}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render different templates depending on one or more expressions\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"nameOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"The name of a template, or a template object, to be rendered\",\r\n \"propName\": \"tmpl\"\r\n }\r\n ],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"pathOrExpr\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"The data-path or expression to be tested\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{if nickname tmpl=\\\"nicknameTemplate\\\"}}\\n{{else tmpl=\\\"noNicknameTemplate\\\"}}\\n{{/if}}\",\r\n \"description\": \"Render first template if condition is true, otherwise render second template\",\r\n \"variant\": \"{{if pathOrExpr1 tmpl=nameOrExpr1 }}{{else tmpl=nameOrExpr2 }}{{/if}}\"\r\n }\r\n ],\r\n \"description\": \"Alternative conditional blocks: – Render the block content of the {{if}} tag (or referenced template) if the expression is true, otherwise render the {{else}} block (or template)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"else and elseif\",\r\n \"text\": \"You can add more than one `{{else}}` tag between `{{if}}` and `{{/if}}`, to get alternate rendering based on 'if ... elseif ... else ...' logic. For elseif, just include an expression...:\\n\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{if ....}}...{{else ...}}...{{else}}...{{/if}}\",\r\n \"name\": \"name\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Render alternate blocks depending on one or more expressions\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note: Any of the `{{if}}` or `{{else}}` tags can have a `tmpl=nameOrExpr` parameter. The external template will be used instead of block content for that tag.\"\r\n }\r\n ],\r\n \"example\": \"{{if nickname}}\\n Nickname: {{:nickname}}\\n{{else altnickname}}\\n Alternate nickname: {{:altnickname}}\\n{{else}}\\n No nickname...\\n{{/if}}\",\r\n \"description\": \"Render first block for which condition is true, otherwise last block\",\r\n \"variant\": \"{{if pathOrExpr1}}...{{else pathOrExpr2}}...{{else}}...{{/if}\"\r\n }\r\n ],\r\n \"description\": \"Multiple alternative conditional blocks: – Render the first {{if}} or {{else}} block for which the expression is true. If none are true, and there is an {{else}} without an expression, render that block\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n[\\n {title: \\\"The A team\\\", members: [...], standby: [...]},\\n {title: \\\"The B team\\\", members: [], standby: [...]},\\n {title: \\\"The C team\\\", standby: []}\\n]\\n```\\n\\n```jsr\\n{{if members && members.length}}\\n ...\\n{{else standby && standby.length}}\\n Standby only:\\n ...\\n{{else}}\\n No members!\\n{{/if}}\\n```\"\r\n }\r\n ],\r\n \"markup\": \"

                          {{:title}}

                          \\n{{if members && members.length}}\\n
                            \\n {{for members}}\\n
                          • {{:name}}
                          • \\n {{/for}}\\n
                          \\n{{else standby && standby.length}}\\n Standby only:\\n
                            \\n {{for standby}}\\n
                          • {{:name}}
                          • \\n {{/for}}\\n
                          \\n{{else}}\\n No members!\\n{{/if}}\",\r\n \"data\": [\r\n {\r\n \"title\": \"The A team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Pete\"\r\n },\r\n {\r\n \"name\": \"Heidi\"\r\n }\r\n ],\r\n \"standby\": [\r\n {\r\n \"name\": \"Xavier\"\r\n }\r\n ]\r\n },\r\n {\r\n \"title\": \"The B team\",\r\n \"members\": [],\r\n \"standby\": [\r\n {\r\n \"name\": \"Robert\"\r\n },\r\n {\r\n \"name\": \"Adriana\"\r\n }\r\n ]\r\n },\r\n {\r\n \"title\": \"The C team\",\r\n \"standby\": []\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"300\",\r\n \"title\": \"{{if}}...{{else}}...{{/if}}\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsviftag\",\r\n \"label\": \"JsViews: {^{if ...}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"elsetag\": {\r\n \"title\": \"Template tag: {{else ...}} (Content blocks separator)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"{{else}} can be used with {{if}}, {{for}}, {{props}} or any custom tag!\",\r\n \"text\": \"The `{{else}}` tag acts as a separator, for block tags, to divide the content of a tag into two or more different content blocks.\\n\\nSo it allows a block tag to provide specific behavior involving more than one content block.\\n\\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\\n\\n```jsr\\n{{if firstExpression}}\\n render this if the firstExpression is true\\n{{else secondExpression}}\\n else render this if the secondExpression is true\\n{{else}}\\n else render this\\n{{/if}}\\n```\\n\\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\\n\\n```jsr\\n{{for members}}\\n Member Name: {{:name}}\\n{{else}}\\n There are currently no members...\\n{{/for}}\\n```\\n\\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\\n\\n```jsr\\n{{tabs caption=\\\"First Tab\\\"}}\\n first tab content\\n{{else caption=\\\"Second Tab\\\"}}\\n second tab content\\n{{/tabs}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"iftag\",\r\n \"label\": \"{{if}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"fortag\",\r\n \"label\": \"{{for}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"propstag\",\r\n \"label\": \"{{props}}\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls/tabs\",\r\n \"label\": \"Sample: tabs control\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvelsetag\",\r\n \"label\": \"JsViews: {{else}}\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"commenttag\": {\r\n \"title\": \"Template tag: {{!-- ... --}} (Comment)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{!-- a comment --}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Adding comments\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{!-- this is a comment --}}\",\r\n \"description\": \"The comment will be ignored during template rendering – and will produce no output\",\r\n \"variant\": \"\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Commenting out sections of a template\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"{{!-- this section will be omitted \\n\\nDo I really want to show this? {{:password}}\\n\\n--}}\",\r\n \"description\": \"The comment can be multiline. All content will be ignored during template rendering - and will produce no output\",\r\n \"variant\": \"\"\r\n }\r\n ],\r\n \"description\": \"Adding comments to templates, or commenting out sections of a template\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender comment tags versus HTML comments\",\r\n \"text\": \"You can include \\n\\n```jsr\\n\\n```\\n\\n— but unlike the JsRender comment tag, the HTML comment will not be ignored by JsRender or JsViews. It will be included in the rendered output, and will get inserted into the DOM along with other rendered markup.\"\r\n }\r\n ]\r\n },\r\n \"allowcodetag\": {\r\n \"title\": \"Template tags: {{*... }} and {{*: ... }} (Allow code)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\\n\\n```jsr\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n```\\n\\nNevertheless, in order to improve encapsulation and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \\n\\nIf you want complete freedom to insert any code into a compiled template, you can [set **allowCode**](#settings/allowcode) to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the `{{* ...}}` tag, or you can return (render into the template output) the result of evaluating any expression, using the `{{*: ...}}` tag.\\n\\n(*Note:* these ***allow code*** tags are not recommended for use within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\"\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{* ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Insert code\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"anyJavascriptCode \",\r\n \"type\": \"code\",\r\n \"optional\": false,\r\n \"description\": \"\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{* window.myvar=2; myvar+=4; }}\",\r\n \"description\": \"If allowCode is set to true, include any code in the compiled template.\",\r\n \"variant\": \"{{* anyJavascriptCode /}}\"\r\n }\r\n ],\r\n \"description\": \"Insert code into the template\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"tag\",\r\n \"typeLabel\": \"Tag:\",\r\n \"title\": \"{{*: ...}}\",\r\n \"name\": \"for NAME\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Evaluate expression\",\r\n \"params\": [],\r\n \"args\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"anyJavascriptExpression \",\r\n \"type\": \"code\",\r\n \"optional\": false,\r\n \"description\": \"\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"{{*: myvar/2 }}\",\r\n \"description\": \"If allowCode is set to true, evaluate any expression, and insert the result into the rendered output.\",\r\n \"variant\": \"{{*: anyJavascriptExpression /}}\"\r\n }\r\n ],\r\n \"description\": \"Evaluate any code expression\",\r\n \"sectionTypes\": {}\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example, with `allowCode` set to `true` globally:\\n\\n```js\\n$.views.settings.allowCode(true);\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Enable `allowCode` in all templates:\\n\\n```js\\n$.views.settings.allowCode(true);\\n```\\n\\nDefine a global variable, then increment it:\\n\\n```jsr\\n{{* window.myvar=2; myvar+=4; }}\\n```\\n\\nInsert the value into the rendered output:\\n\\n```jsr\\n
                          Initial value: {{*:myvar}}
                          \\n```\\n\\nIncrement the value again, and output the new value:\\n\\n```js\\n{{* window.myvar+=11; }}\\n\\n
                          New value: {{*:myvar}}
                          \\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"code\": \"$.views.settings.allowCode(true); \\n\\nvar html = $(\\\"#myTemplate\\\").render();\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"title\": \"allowCode\",\r\n \"markup\": \"\",\r\n \"anchor\": \"sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is an example that uses both regular JsRender tags, like `{{for}}`, and allowCode tags:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(true);\\n```\\n\\nDefine a global variable:\\n\\n```jsr\\n{{* window.total = 0}}\\n```\\n\\nIterate through a list, and use `{{* ...}}` to increment the `total`, and `{{*:}}` to return each value:\\n\\n```js\\n{{for list}}\\n {{* total += data}}\\n
                        • \\n Amount {{:}} (Running total: {{*: total}})\\n
                        • \\n{{/for}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"144\",\r\n \"code\": \"var data = {\\n title: \\\"My list\\\",\\n list: [2, 10.3, 77, -44, -5.5]\\n };\\n\\n$.views.settings.allowCode(true);\\n\\nvar html = $(\\\"#myTemplate\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"title\": \"allowCode and regular tags\",\r\n \"anchor\": \"plusreg\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is another example, in which we will replace the `{{for list}}` iteration by pure code-based iteration using `{{* ...}}`. This makes it easy to iterate only over the odd members of the array.\\n\\n
                          This time we will allow code ***just for this template***:\\n\\n```js\\n$.templates(..., {\\n markup: ...,\\n allowCode: true,\\n ...\\n})\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Enable allowCode just for this template:\\n\\n```js\\nvar tmpl = $.templates({\\n markup: \\\"#myTemplate\\\",\\n allowCode: true\\n });\\n \\nvar html = tmpl.render(data);\\n```\\n\\nInsert template code to iterate over odd numbers:\\n\\n```jsr\\n{{* for (i=0; ifor
                          block, {{* } }} into the template code:\\n\\n```jsr\\n {{* } }}\\n```\\n\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"110\",\r\n \"code\": \"var data = {\\n title: \\\"My list\\\",\\n list: [2, 10.3, 77, -44, -5.5]\\n };\\n\\nvar tmpl = $.templates({\\n markup: \\\"#myTemplate\\\",\\n allowCode: true\\n });\\n \\nvar html = tmpl.render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"title\": \"allowCode for template\",\r\n \"anchor\": \"tmpl\"\r\n }\r\n ]\r\n },\r\n \"customtagsapi\": {\r\n \"title\": \"Custom tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining custom tags\",\r\n \"text\": \"JsRender deliberately has only a small number of built-in tags -- each of which is very flexible and useful. This is intended to reduce the 'learning curve'. And at the same time JsRender makes it very easy to create your own custom tags:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tags\",\r\n \"label\": \"Using custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsapi\",\r\n \"label\": \"Registering custom tags: $.view.tags()\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"rendertmpl\": {\r\n \"title\": \"Render a template\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A template is rendered by calling the `render()` method.\\n\\nThe `render(data, helpersOrContext)` method takes as parameters the data (used as the 'data context' during the rendering), and optionally additional metadata or contextual helpers. It returns a string -- which is the rendered template -- typically HTML markup with data values or computed values inserted at appropriate points in the string.\\n\\nThere are three ways of calling the `render()` method:\\n- If you have a reference to the template object -- `myTmpl`, call [myTmpl.render(...)](#tmplrender)\\n- If you have registered the template by name -- `\\\"myTmpl\\\"`, call [$.render.myTmpl(...)](#d.render)\\n- If the template is declared in a script block, with selector `\\\"#myTmpl\\\"`, you can also call [$(\\\"#myTmpl\\\").render(...)](#db.render)\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tmplrender\",\r\n \"label\": \"myTmpl.render()\"\r\n },\r\n {\r\n \"hash\": \"d.render\",\r\n \"label\": \"$.render.myTmpl()\"\r\n },\r\n {\r\n \"hash\": \"db.render\",\r\n \"label\": \"$(\\\"#myTmpl\\\").render()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tmplrender\": {\r\n \"title\": \"Render a template against data objects or arrays\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"myTmpl.render()\",\r\n \"text\": \"If `myTmpl` is the compiled template object for your template, you can render it using the `myTmpl.render()` method -- which takes a data object or array (as well as an optional helpersOrContext object), and returns the rendered template as a string.\\n\\nThere is also a shortcut version of the `render()` method: you can call the template object itself as a function: `var html = myTmpl(data)` -- which is equivalent to `var html = myTmpl.render(data)`.\\n\\nTo get a template object from a template string, a template declared in a script block, or a previously registered *named template*, see [`$.templates()`](#d.templates).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(myData);\",\r\n \"description\": \"Render template against data\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, and return a string.\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing an object to the `render()` method.\\n\\n*--- The template is rendered once, with the object as data context:*\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar html = myTmpl.render(person);\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"template.render(object):\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"50\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing an array to the `render()` method.\\n\\n*--- The template is rendered once for each item in the array:*\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var html = myTmpl.render(people);\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\\n\\nvar html = myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"template.render(array):\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Passing helpers to the `render()` method.\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data, helpersOrContext)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(myData, myHelpers);\",\r\n \"description\": \"Render template against data, and pass in helpers\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, along with helper objects or context, and return a string\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"helpers\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"You can pass in any JavaScript type (object, string, number, function...) as helpers on the `helpersOrContext` object, and use them as metadata, or as helper functions for formatting etc.\\n\\nNote: By passing in helpers in this way, you are making them specific to this render call. Alternatively, you can declare helpers globally, -- and you can also declare helpers that are private to a specific template. See *[Registering helpers: `$.views.helpers()`](#helpers)* for details...\\n\\nWithin the template, helpers (whether global, or passed in to the `render()` method) are accessed by *helper paths*: `~keyName`. \\n\\nFor example you might pass in an object with some utility functions:\\n\\n```js\\nvar myHelpers = {\\n util: {\\n split: function(val, part) {...},\\n ...\\n },\\n ...\\n};\\n\\nvar html = myTmpl.render(myData, myHelpers);\\n```\\n\\n-- and access them in the template using a *helper path* such as:\\n\\n```jsr\\n{{:~util.split(fullName, 0)}}\\n```\\n\\nSee *[Registering helpers](#helpers)*.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nfunction toUpper(val) {...}\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = myTmpl.render(person, myHelpers);\\n```\\n\\n```jsr\\n\\n {{:~format(name)}}\\n\\n```\\n\\nClick Try it and change the color to \\\"green\\\"...\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"function toUpper(val) { return val.toUpperCase(); }\\n\\nvar myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = myTmpl.render(person, myHelpers);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"template.render(object, myHelpers):\",\r\n \"height\": \"52\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Passing an array to render(), but without iteration.\",\r\n \"text\": \"When rendering an array, an additional optional boolean parameter, `true`, can be passed to the `render()` method, in order to prevent iteration.\\n\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"template.render(data, helpersOrContext, noIteration)\",\r\n \"name\": \"render\",\r\n \"object\": \"template\",\r\n \"method\": true,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var html = myTmpl.render(data, helpers, true);\",\r\n \"description\": \"Render template against data, pass in helpers, and specify iteration behavior\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data, along with helpers/context (and determine iteration behavior with array data). Return a string. \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"noiteration\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"By passing in `true` as the third *'noIteration'* parameter (or as second parameter if no `helpersOrContext` are passed), the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\\n\\nWithin the template, `{{for}}` (or equivalently `{{for #data}}`) can be used to iterate over the array, as in the following example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Code:\\n\\n```js\\nvar html = myTmpl.render(people, true);\\n```\\n\\nTemplate:\\n\\n```jsr\\n\\n \\n \\n {{for}}\\n \\n {{/for}}\\n \\n
                          \\n {{:#data.length}} people\\n
                          \\n {{:name}}\\n
                          \\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"110\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\\n\\nvar html = myTmpl.render(people, true);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"template.render(array, helpers, noIteration):\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Alternative compact syntax for render() call\",\r\n \"text\": \"The compiled template is in fact *itself a function*, equivalent to its own `render()` method. \\n\\nThis means that any `render()` call can be replaced by an equivalent (but more compact) syntax, as shown in the following example:\\n\\n```js\\nvar html = myTmpl(people, helpers, true);\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"d.render\": {\r\n \"title\": \"Render a named template without needing the template object\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"$.render.myTmpl()\",\r\n \"text\": \"If a template has been [registered](#d.templates) as a named template:\\n\\n```js\\n$.templates(\\\"myTmpl\\\", \\\"#personTmpl\\\");\\n```\\n\\nor\\n\\n```js\\n$.templates(\\\"myTmpl\\\", \\\"some markup string\\\");\\n```\\n\\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates).\\n\\nJust call `$.render.myTmpl(...)`, or `$.render[\\\"myTmpl\\\"](...)`\\n\\n(**Note:** there is also an alternative syntax for rendering a named template: `$.templates.myTmpl(...);`)\\n\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.render.myTmpl(data, helpersOrContext, noIteration)\",\r\n \"name\": \"myTmpl\",\r\n \"object\": \"$.render\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = $.render.myTmpl(data, helpers, true);\",\r\n \"description\": \"Render template against data. Optionally pass in helpers and specify iteration behavior.\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data. Return a string.
                          (Optionally provide helpers/context, and specify iteration behavior). \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar html = $.render.personTmpl(person);\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"function toUpper(val) { return val.toUpperCase(); }\\n\\n$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar myHelpers = {color: \\\"red\\\", format: toUpper};\\n\\nvar html = $.render.personTmpl(person, myHelpers);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"$.render.personTmpl(...):\",\r\n \"height\": \"50\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"db.render\": {\r\n \"title\": \"jQuery instance method to render a template declared in a script block\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"$(\\\"#myTmpl\\\").render()\",\r\n \"text\": \"If a template has been [registered](#d.templates) using a script block:\\n\\n```jsr\\n\\n```\\n\\n...then you can call the [`render()`](#tmplrender) method of the template without needing to hold on to the compiled template object returned from [`$.templates(...)`](#d.templates), and without registering a named template.\\n\\nJust call `$(\\\"#myTmpl\\\").render(...)`\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$(tmplSelector).render(data, helpersOrContext, noIteration)\",\r\n \"name\": \"render\",\r\n \"object\": \"$(tmplSelector)\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helpersOrContext\",\r\n \"type\": \"object\",\r\n \"optional\": true,\r\n \"description\": \"Contextual helper methods or properties - available to template as ~keyName\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"noIteration\",\r\n \"type\": \"boolean\",\r\n \"optional\": true,\r\n \"description\": \"Pass in parameter true to prevent iteration on array data\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var html = $(\\\"#myTmpl\\\").render(myData, myHelpers, true);\",\r\n \"description\": \"Render template against data. Optionally pass in helpers and specify iteration behavior.\"\r\n }\r\n ],\r\n \"description\": \"Render a template against data. Return a string.
                          (Optionally provide helpers/context, and specify iteration behavior). \",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var person = {\\n name: \\\"Adriana\\\"\\n };\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"title\": \"$(\\\"#personTemplate\\\").render(...):\",\r\n \"height\": \"50\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"compiletmpl\": {\r\n \"title\": \"Using templates\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering templates](#d.templates): The `$.views.templates()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining templates\",\r\n \"text\": \"To define a template you need to provide the markup for the template. JsRender will convert (compile) the markup into a JavaScript function -- the 'render' function for your template. In fact for convenience, JsRender creates a *template object* which has a [`template.render()`](#rendertmpl) method which is the compiled function.\\n\\nThere are two ways to create a template:\\n\\n- Pass the markup string to the [`$.templates()`](#d.templates) method\\n- Declare the template in a script block with `type=\\\"text/x-jsrender\\\"` (or at least a type other than the default `text/javascript`), then pass the jQuery selector for the script block to the [`$.templates()`](#d.templates) method\\n\\nIn either case, the `$.templates()` method will compile a template object, and optionally register it by name.\\n\\nHere is an example of the first approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"We pass our markup string to the [`$.templates()`](#d.templates) method:\\n\\n```jsr\\nvar myTmpl = $.templates(\\\" {{:name}} \\\");\\n```\\n\\nthen call the [`render()`](#rendertmpl) method on the returned template object:\\n\\n```js\\nvar html = myTmpl.render(people);\\n```\"\r\n }\r\n ],\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"
                          \",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}} \\\");\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\\n\\nvar html = myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering a template from a template markup string:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is an example of the second:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This time we put our markup in a script block with `type=\\\"text/x-jsrender\\\"`\\n\\n```jsr\\n\\n```\\n\\nand then in the code we call the [`$.templates()`](#d.templates) method with a jQuery selector for that script block: \\n\\n```jsr\\nvar myTmpl = $.templates(\\\" {{:name}} \\\");\\n```\\n\\nThen as before we call the [`render()`](#rendertmpl) method on the returned template object:\\n\\n```js\\nvar html = myTmpl.render(people);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\\n\\nvar html =myTmpl.render(people);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering a template declared in script block:\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The first approach above has the advantage of keeping your template declaration independent of the HTML markup that you are loading into the browser. Indeed you may want to provide the template markup strings for your templates in different application-specific ways, such as loading the string from the server (using a script file or text or html file), creating 'computed' template markup strings on the fly, etc.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example of fetching the markup string from the server\",\r\n \"text\": \"Here is a simple example of fetching the markup string from the server. We load a `.../person.js` file from the server which registers a named `\\\"person\\\"` template.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"We load the *person.js* script from the server, which registers a named `\\\"person\\\"` template:\\n\\n```js\\n$.templates(\\\"person\\\", \\\" {{:name}} \\\");\\n```\\n\\nAs soon as the script is loaded, we call the [`render(...)`](#d.render) method for the registered template:\\n\\n```js\\n$.getScript(\\\".../person.js\\\", function() {\\n var html = $.render.person(people);\\n $(\\\"#peopleList\\\").html(html);\\n });\\n```\\n\\n*Note:* For a more sophisticated example of lazy loading of scripts for registering templates, see the [remote templates](#samples/jsr/composition/remote-tmpl) sample.\"\r\n }\r\n ],\r\n \"markup\": \"\\n\",\r\n \"data\": {},\r\n \"code\": \"$.getScript(\\\"https://www.jsviews.com/samples/resources/templates/person.js\\\", function() {\\n var html = $.render.person(people);\\n $(\\\"#peopleList\\\").html(html);\\n });\\n\\nvar people = [\\n {\\n name: \\\"Adriana\\\"\\n },\\n {\\n name: \\\"Robert\\\"\\n }\\n];\",\r\n \"html\": \"
                          \",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"title\": \"Fetching a script file from the server, which registers a named template from a string\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/resources/templates/person.js\",\r\n \"label\": \"person.js\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is a variant of the same sample, where we fetch a text file containing the template markup:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The markup string is fetched in an AJAX request (the *person.txt* file).\\n\\n```jsr\\n {{:name}}\\n```\\n\\nAs soon as the request returns, we use the markup string to compile the `personTemplate` object. This time we will not register it as a *named template*, but instead directly call the [`render(...)`](#tmplrender) method of the returned `personTemplate` object:\\n\\n```js\\n$.get(\\\"...person.txt\\\", function(value) {\\n personTemplate = $.templates(value);\\n var html = personTemplate.render(people);\\n $(\\\"#peopleList\\\").html(html);\\n});\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\",\r\n \"code\": \"var personTemplate;\\n\\n$.get(\\\"resources/templates/person.txt\\\", function(value) {\\n personTemplate = $.templates(value);\\n var html = personTemplate.render(people);\\n $(\\\"#peopleList\\\").html(html);\\n});\\n\\nvar people = [\\n {name: \\\"Adriana\\\"},\\n {name: \\\"Robert\\\"}\\n];\",\r\n \"title\": \"Registering a named template using markup fetched from the server in a text file\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/resources/templates/person.txt\",\r\n \"label\": \"person.txt\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the second approach:\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering templates](#d.templates): The `$.views.templates()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Sample: sub-templates\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"d.templates\": {\r\n \"title\": \"Registering templates: $.templates()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.templates()` is used to register or compile templates. See *[Using templates](#compiletmpl)* for an overview, and simple examples.\\n\\nThis topic provides more details.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Simple scenarios\",\r\n \"text\": \"`$.templates(...)` is powerful and flexible. You can use it for many scenarios, including the following:\\n- Compile a template from a string\\n- Get a template object for a template declared in a script block\\n- Register a template (from either a string or a script block declaration) as a *named template*\\n- Get a template object for a previously registered *named template*\\n- On Node.js: Get a template object for a template declared as a file on the file-system (see *[File-based templates on Node.js](#node/filetmpls)*).\",\r\n \"anchor\": \"$.templates\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(...)\",\r\n \"name\": \"templates\",\r\n \"object\": \"$\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"Compiled template object\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"markupOrSelector\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"A markup string or a selector for a template declaration script block\"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var myTemplate = $.templates(myMarkupString);\",\r\n \"description\": \"Compile a template from a string or selector, and return the template object\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered template\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"markupOrSelector\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"A markup string or a selector for a template declaration script block\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(\\\"myTemplateName\\\", myMarkupString);\",\r\n \"description\": \"Register a named template from a string or selector\"\r\n }\r\n ],\r\n \"description\": \"Create one or more compiled templates – optionally registered as named templates\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}}\\\");\\n\\nvar html = myTmpl.render(person);\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\" {{:name}}\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Compile a template from a string\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\",\r\n \"anchor\": \"tmpl-string\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\nvar myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar html = myTmpl.render(person);\\n```\"\r\n }\r\n ],\r\n \"title\": \"Get template object for script block template\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var myTmpl = $.templates(\\\"#personTemplate\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = myTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\" {{:name}}\\\");\\n\\nvar html = $.render.personTmpl(person);\\n\"\r\n }\r\n ],\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\" {{:name}}\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                          \",\r\n \"height\": \"40\",\r\n \"title\": \"Register named template from a string\",\r\n \"anchor\": \"namedfromstring\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar html = $.render.personTmpl(person);\\n\"\r\n }\r\n ],\r\n \"code\": \"$.templates(\\\"personTmpl\\\", \\\"#personTemplate\\\");\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"title\": \"Register named template from script block\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Register multiple templates in one call\",\r\n \"text\": \"You can register multiple named templates in one call to `$.templates()` as follows:\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(namedTemplates)\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTemplates\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"<label>Name:</label>\\\"\\n});\",\r\n \"description\": \"Register multiple named templates\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n\\n```\\n\\n```js\\n$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"\\\"\\n});\\n\\nvar html = $.render.personTmpl(person);\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.templates({\\n personTmpl: \\\"#personTemplate\\\",\\n labelTmpl: \\\"\\\"\\n});\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Registering multiple templates\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Get a template object for a named template\",\r\n \"text\": \"You can get the template object for a previously registered *named template* as follows:\\n\\n```js\\nvar myTemplate = $.templates.myTemplateName; // or $.templates[\\\"myTemplateName\\\"]\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregister a named template\",\r\n \"text\": \"To unregister a previously registered named template, pass `null` to `$.templates()`:\\n\\n```js\\n$.templates(\\\"myTemplateName\\\", null);\\n// Named template \\\"myTemplateName\\\" is no longer registered\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advanced scenarios: Associating private resources with templates\",\r\n \"text\": \"$.templates() can also be used for the following more advanced scenarios:\\n\\n- Compile a template, (or multiple templates) along with specified resources to be available only within that template\\n- Compile one or more templates to be added to the set of private resources of another (already compiled) template\\n\\nYou can use `$.templates()` to compile or register not only a template, but in addition some helpers, converters, custom tags or nested sub-templates, to be made available to the new template as private resources.\\n\\nNote that as an alternative you can register resources (helpers, converters, custom tags or templates) globally, using `$.views.helpers()`, `$.views.converters()`, `$.views.tags()`, or `$.templates()` -- rather than making them private to the template that needs to reference them.\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.templates(...) — associating resources\",\r\n \"name\": \"templates\",\r\n \"object\": \"$\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"templateOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var myTmpl = $.templates({\\n markup: \\\"...\\\",\\n helpers: {...},\\n tags: {...}\\n ...\\n});\",\r\n \"description\": \"Compile a template, along with specified resources to be available only within this template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered template\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"templateOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"An options object with a markup property, and optionally other declared resources (converters, helpers, etc.)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(\\\"myTmpl\\\", {\\n markup: \\\"...\\\",\\n helpers: {...},\\n tags: {...}\\n ...\\n});\",\r\n \"description\": \"Register a named template, along with specified resources available only within that template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTemplates\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of template) and values (markup string, selector, or templateOptions object)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these template(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.templates(namedTemplates, parentTemplate);\",\r\n \"description\": \"Register named templates as private resources for a 'parent template'\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n },\r\n \"anchor\": \"resources\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"A converter and a helper are registered as private resources for the `personTmpl` named template.\\n\\n```js\\n$.templates(\\\"personTmpl\\\", {\\n markup: \\\"#personTemplate\\\",\\n converters: {\\n upper: function(val) {return val.toUpperCase();}\\n },\\n helpers: {\\n append: function(a, b) {return a + b;}\\n }\\n});\\n```\\n\\nThey are accessed within the `personTmpl`\\n\\n```jsr\\n\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Register a template along with a converter and a helper that it will use.\\n// These resources are private to the template, rather than being registered\\n// globally using $.views.converters or $.views.helpers\\n$.templates(\\\"personTmpl\\\", {\\n markup: \\\"#personTemplate\\\",\\n converters: {\\n upper: function(val) {return val.toUpperCase();}\\n },\\n helpers: {\\n append: function(a, b) {return a + b;}\\n }\\n});\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = $.render.personTmpl(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"title\": \"Register a named template along with specified resources\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding templates as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.templates(...)`. In that way the template you are registering becomes a 'private template resource' for the `parentTemplate`.\\n\\nHere is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"$.templates(\\\"labelTmpl\\\", \\\"\\\", personTmpl);\\n\"\r\n }\r\n ],\r\n \"code\": \"var personTmpl = $.templates(\\\"#personTemplate\\\");\\n\\n$.templates(\\\"labelTmpl\\\", \\\"\\\", personTmpl);\\n\\nvar person = {name: \\\"Robert\\\"};\\n\\nvar html = personTmpl.render(person);\\n\\n$(\\\"#peopleList\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"title\": \"Add a \\\"labelTmpl\\\" template resource as a 'sub template' – a private resource for an existing \\\"personTemplate\\\"\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Debug a template by including a debugger; statement\",\r\n \"text\": \"As a technique for debugging compiled templates, you can temporarily set the template option `debug: true`:\\n\\n```js\\n$.templates({\\n myTmpl: {\\n markup: \\\"...\\\",\\n debug: true // This option will add a debugger; statement to the compiled template\\n }\\n});\\n```\\n\\nThe result will be to include a `debugger;` statement at the beginning of the compiled template, which will behave as a breakpoint when debugging, and will facilitate understanding, or stepping through, the compiled template.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"compiletmpl\",\r\n \"label\": \"Using templates\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/composition/sub-tmpl\",\r\n \"label\": \"Sample: sub-templates\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrregister\": {\r\n \"title\": \"Register helpers, converters, tags...\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"converters\",\r\n \"label\": \"$.views.converters()\"\r\n },\r\n {\r\n \"hash\": \"tags\",\r\n \"label\": \"$.views.tags()\"\r\n },\r\n {\r\n \"hash\": \"helpers\",\r\n \"label\": \"$.views.helpers()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tags\": {\r\n \"title\": \"Using custom tags\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering tags](#tagsapi): The `$.views.tags()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What is a custom tag?\",\r\n \"text\": \"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\\n\\nA tag renders itself as part of the template output. You determine how it renders, generally by specifying either a function as *render()* method or a template, when you declare your custom tag.\\n\\nThe *render()* method, or the *template*, can access both unnamed arguments (*args*) and named properties (*props*) and , [as in](#tagsyntax@tagparams):\\n\\n```jsr\\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\\n```\\n\\nIn fact it can also access the current data item -- or even the whole hierarchy of views and data...\\n\\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering a custom tag\",\r\n \"text\": \"To register a custom tag, you call [`$.views.tags(...)`](#tagsapi):\\n```js\\n$.views.tags(\\\"mytag\\\", tagOptions)\\n```\\n\\nYou provide a `tagOptions` object, whose properties will typically include a `render: tagRenderFn` (function to be used as *render()* method) and/or a `template: tagTemplate` (template to be rendered -- markup string, selector string or template object).\\n\\nFor the simple case where the *only* option you need to specify is a *render()* method, you can provide the function directly:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagRenderFn);\\n```\\n\\nOr if you *only* want to provide a template markup string, to show how it renders, you can again provide it directly:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagTemplate);\\n```\\n\\nHere is an example of a simple custom tag using just a function:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Render method for the tag\\nfunction renderBoldP(value) {\\n return \\\"

                          \\\" + value + \\\"

                          \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // Provide just a render method\\n```\\n\\nAlternatively we could have written:\\n\\n```js\\n$.views.tags(\\\"boldp\\\", {\\n render: renderBoldP); // Provide just a render method\\n});\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Using the tag\",\r\n \"markup\": \"This is the title:{{boldp title /}}\"\r\n }\r\n ],\r\n \"title\": \"A custom tag using just a render() method\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Render method for the tag\\nfunction renderBoldP(value) {\\n return \\\"

                          \\\" + value + \\\"

                          \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // Provide just a render method\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"70\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"render-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the equivalent sample using just a template:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Template markup string for the tag\\nvar tagTemplate = \\\"

                          {{:}}

                          \\\";\\n\\n$.views.tags(\\\"boldp\\\", tagTemplate); // Provide just a template markup string\\n```\\n\\nAlternatively we could have written:\\n\\n```js\\n$.views.tags(\\\"boldp\\\", {\\n template: tagTemplate; // Provide just a template markup string\\n});\\n```\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"Using the tag\",\r\n \"markup\": \"This is the title:{{boldp title /}}\"\r\n }\r\n ],\r\n \"code\": \"// Template markup string for the tag\\nvar tagTemplate = \\\"

                          {{:}}

                          \\\";\\n\\n$.views.tags(\\\"boldp\\\", tagTemplate); // Provide just a template markup string\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"title\": \"A custom tag using just a template\",\r\n \"height\": \"70\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"template-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing unnamed arguments, named properties, data, etc. within the render() method\",\r\n \"text\": \"The `this` pointer within the tag *render()* method is the instance of the tag, and can be used to access properties, data, view hierarchy, and more. Most of the useful context is provided via `this.tagCtx`. (See [tagCtx object](#tagctxobject).)\\n\\nIn particular, unnamed arguments can be accessed via `tagCtx.args`, and named properties via `tagCtx.props`.\\n\\nHere is tag with two arguments and one named property:\\n\\n```jsr\\n{{sometag title name mode=\\\"edit\\\"}}\\n```\\n\\nFrom within the *render()* method of `sometag`, you can access `title` and `name` as `this.tagCtx.args[0]` and `this.tagCtx.args[1]`. And you can access mode as `this.tagCtx.props.mode`.\\n\\nIn addition to being accessible as `tagCtx.args`, unnamed arguments are also passed directly as arguments to the *render()* method (if your tag is using one):\\n\\n```js\\nfunction sometagRenderMethod(title, name) {\\n // Here, this.tagCtx.args[1] and the name argument are the same thing\\n}\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Render method for the tag\\nfunction sometagRenderMethod(title, name) {\\n var parentData = this.tagCtx.view.data;\\n\\n return\\n \\\"title: \\\" ... title ... // Get argument passed to render method\\n + \\\"parentData.title: \\\" ... this.tagCtx.view.data.title ... // Get title from parent context\\n\\n + \\\"args[1]: \\\" ... this.tagCtx.args[1] ... // Get argument from args[]\\n + \\\"mode: \\\" ... this.tagCtx.props.mode; // Get named property from props\\n}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Render method for the tag\\nfunction sometagRenderMethod(title, name) {\\n var parentData = this.tagCtx.view.data;\\n\\n return \\\"title: \\\" + title + \\\"
                          \\\" // Get argument passed to render method\\n + \\\"parentData.title: \\\" + this.tagCtx.view.data.title + \\\"
                          \\\" // Get title from parent context\\n + \\\"args[1]: \\\" + this.tagCtx.args[1] + \\\"
                          \\\" // Get argument from args[]\\n + \\\"mode: \\\" + this.tagCtx.props.mode; + \\\"\\\"// Get named property from props\\n}\\n\\n$.views.tags(\\\"sometag\\\", sometagRenderMethod); // Provide just a render method\\n\\nvar team = {\\n title: \\\"theTitle\\\",\\n name: \\\"theName\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"title\": \"Accessing context within the render() method\",\r\n \"action\": \"append\",\r\n \"header\": \"\",\r\n \"anchor\": \"context-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing arguments, named properties, data, etc. from the tag template\",\r\n \"text\": \"Within the template, the tag instance can be accessed as `~tag`, and so unnamed arguments and named properties are obtained using `~tagCtx.args[...]` and `~tagCtx.props...`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Template markup for the tag\\nvar sometagTemplate =\\n \\\"title: {{:}}\\\" // The data context within the tag is the first argument, title\\n + \\\"title (#data): {{:#data}}\\\" // Equivalent unabbreviated syntax for current data\\n + \\\"parentData.title: {{:~tagCtx.view.data.title}}\\\" // Get title from parent context\\n\\n + \\\"args[1]: {{:~tagCtx.args[1]}}\\\" // Get argument from args[]\\n + \\\"mode: {{:~tagCtx.props.mode}}\\\"; // Get named property from props\\\";\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Template markup for the tag\\nvar sometagTemplate =\\n \\\"title: {{:}}
                          \\\" // The data context within the tag is the first argument, title\\n + \\\"title (#data): {{:#data}}
                          \\\" // Equivalent unabbreviated syntax for current data\\n + \\\"parentData.title: {{:~tagCtx.view.data.title}}

                          \\\" // Get title from parent context\\n + \\\"args[1]: {{:~tagCtx.args[1]}}
                          \\\" // Get argument from args[]\\n + \\\"mode: {{:~tagCtx.props.mode}}\\\"; // Get named property from props\\n\\n$.views.tags(\\\"sometag\\\", sometagTemplate ); // Provide just a template markup string\\n\\nvar team = {\\n title: \\\"theTitle\\\",\\n name: \\\"theName\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"124\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"title\": \"Accessing context from the tag template\",\r\n \"anchor\": \"tmplcontext-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing and rendering wrapped block content, in a custom tag\",\r\n \"text\": \"A common requirement is to define a custom tag to be used as a block tag, which renders itself by wrapping the rendered block content with other markup.\\n\\nFor example, a `boldp` tag which wraps its content as: `

                          ...

                          `:\\n\\n```jsr\\n{{boldp}}\\n This is inside our block content:
                          \\n {{:title}}\\n{{/boldp}}\\n```\\n\\n**_Block content, using a render() method_**:\\n\\nIn a *render()* method, the block content can be included in the rendered output using:\\n\\n```js\\n... this.tagCtx.render() ...\\n```\\n\\n(For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See [template as fallback sample](#tags@tmpl-fallback) below) \\n\",\r\n \"anchor\": \"wrapping\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag render method:*\\n\\n```js\\nfunction renderBoldP(val) {\\n //To render the block content, we call this.tagCtx.render()\\n return \\\"

                          \\\" + this.tagCtx.render() + \\\"

                          \\\";\\n}\\n```\\n\\n*Using the tag:*\\n\\n```jsr\\nThis is outside our block content: ...\\n{{boldp}}\\n This is inside our block content: ...\\n {{:title}}\\n{{/boldp}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Rendering block content from a custom tag render() method\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"function renderBoldP(val) {\\n return \\\"

                          \\\" + this.tagCtx.render() + \\\"

                          \\\";\\n}\\n\\n$.views.tags(\\\"boldp\\\", renderBoldP); // User renderBoldP() as render method\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"renderblock-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"When using `tagCtx.render()` without arguments, the data context within the block content is the same as the data context outside our custom tag. However by passing an argument to `tagCtx.render(myData)` the inner data context can be moved to the chosen data. \\n\\nThe following sample shows a custom `{{runningTotal}}` tag which renders an array of `lineItems` (with a column for each property), and provides a running total of one of the columns.\\n\\nIt uses a *render()* method to access tag arguments and named properties, and iterate over the `lineItems` array. It renders a row for each `lineItem`, using the code:\\n\\n```js\\nret += this.tagCtx.render(lineItem, {total: totalVal});\\n```\\n\\nHere, the row is rendered using the block content as template -- with the `lineItem` passed in as data context. The running total `totalVal` is provided as contextual helper: `~total`.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"You call the custom `{{runningTotal}}` tag like this:\\n\\n```jsr\\n{{runningTotal lineItems totalColumn=\\\"quantity\\\"}}\\n ...{{:quantity}}\\n ...{{:~total}}\\n{{/runningTotal}}\\n```\\n\\nAnd the *render()* method code accesses context (`this.tagCtx`) to get at the arguments and named properties... :\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", function renderLineItems(array) {\\n ...\\n totalVal = 0; // Initialize ~total to 0 before rendering\\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\\n for (var i = 0; i < array.length; i++) {\\n lineItem = array[i];\\n totalVal += lineItem[totalCol]; // Compute running total\\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content as\\n // template. Pass lineItem as data and totalVal as helper: ~total\\n }\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"function renderLineItems(array) {\\n var lineItem,\\n ret = \\\"\\\",\\n totalVal = 0, // Initialize ~total to 0 before rendering\\n totalCol = this.tagCtx.props.totalColumn; // The column/property to use for running total\\n for (var i = 0; i < array.length; i++) { // Iterate over array and render a row for each lineItem \\n lineItem = array[i];\\n totalVal += lineItem[totalCol]; // Compute running total\\n ret += this.tagCtx.render(lineItem, {total: totalVal}); // Add the row for this lineItem - using the block content\\n // as template, and passing lineItem as current data and totalVal as helper: ~total\\n }\\n return ret;\\n}\\n\\n$.views.tags(\\\"runningTotal\\\", renderLineItems); // Use renderLineItems() as render method\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ]\\n};\\nvar html = $(\\\"#myTmpl\\\").render(data);\\n\\n$(\\\"#lineItems\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"152\",\r\n \"title\": \"A {{runningTotal}} custom tag, using a render() method \",\r\n \"anchor\": \"runningtotal-sample\",\r\n \"header\": \"\",\r\n \"action\": \"append\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"**_Block content, using a template_**:\\n\\nTo render block content declaratively within a custom tag template, use:\\n\\n```jsr\\n{{include tmpl=#content/}}\\n```\\n\\nor equivalently:\\n\\n```jsr\\n{{include tmpl=~tagCtx.content/}}\\n```\\n\\nHere is a modified [`{{boldp}}`](#tags@renderblock-sample) sample using a custom template instead of a *render()* method.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"To render block content, we use `{{include tmpl=#content/}}`\\n\\n```js\\ntemplate: \\\"

                          {{include tmpl=#content/}}

                          \\\"\\n```\\n\\n(The syntax `#content` is an example of a `view path` -- equivalent to `#view.content`.)\\n\\nThe `content` property on the `view` object is a compiled template for the block content, which is also available as the `content` property on the `tagCtx`.\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"boldp\\\", {\\n template: \\\"

                          {{include tmpl=#content/}}

                          \\\"\\n});\\n\\nvar team = {\\n title: \\\"The A Team\\\"\\n};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n\\n$(\\\"#team\\\").html(html);\",\r\n \"height\": \"90\",\r\n \"title\": \"Rendering block content from a custom tag template\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"tmplblock-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here, the default data context within the block content is the same as the data context outside our custom tag (as was the case in the [previous](#tags@renderblock-sample) `{{boldp}}` sample). However by providing an argument to the `{{include...}}`, as in `{{include myData tmpl=#content/}}`, the inner data context can be moved to the chosen data.\\n\\n(Note: To be precise, the default data in the two samples is different. When using `tagCtx.render()` the outer context is *outside our `{{boldp}}` tag*. Whereas when using `{{include}}`, it is *outside the `{{include}}` and within the `{{boldp}}` template*. If we provide an argument to the tag: '{{mytag someArgument}}...' then in custom tag template approach the passed-in argument value will be used as default data context.)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"For further details and examples of custom tags which wrap content, see [*Rendering wrapped block content*](#tagsapi@wrapping)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags using both a render() method and a template\",\r\n \"text\": \"If there is both a *template* and a *render()* method, then the *template* will only be used if the *render()* method returns *undefined*.\\n\\nLet's take our `{{runningTotal}}` example using a *render()* method, but provide a *template* which will be used as \\\"fallback\\\" rendering for the tag in the case when there are no items to render in the chosen range. We will also provide support for limiting the range of line items by setting `start=... end=...`:\",\r\n \"anchor\": \"tmpl-fallback\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"First, in the *render()* method, we will change the original code to test whether the item exists in the array, before rendering the block content.\\n\\nSecondly, we will make sure that when there is an item we do render the block content and not the template. So we call `this.tagCtx.content.render(...)`, rather than `this.tagCtx.render(...)`.\\n\\nThat's because `this.tagCtx.render(...)` will actually look to see if there is template associated with the tag, (either a template on the tag definition, or a `tmpl` property on the tag) -- in which case it will render that template and not the block content... \\n\\n```js\\nfor (var i=start; iNo line items\\\"\\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.tags(\\\"runningTotal\\\", {\\n render: function(array) {\\n var lineItem,\\n ret = \\\"\\\",\\n totalVal = 0, // Initialize ~total to 0 before rendering\\n props = this.tagCtx.props,\\n totalCol = props.totalColumn; // The column/property to use for running total\\n start = props.start,\\n end = props.end;\\n for (var i=start; iNo line items\\\" // Template for fallback if no line items\\n});\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ],\\n lineItems2: []\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(data, {\\n category: function(item, index, items) {\\n return item.category === this.props.category;\\n }\\n});\\n\\n$(\\\"#purchases\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"height\": \"244\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"\",\r\n \"anchor\": \"renderplustmpl-sample\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"url\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In the above sample our feature for limiting the range of items by setting `start=... end=...` is basically identical to the corresponding feature available natively on the [`{{for}}`](#fortag@sortfilterrange) tag:\\n\\n```jsr\\n{{for start=... end=...}}\\n```\\n\\nIn fact we can add this feature to our `{{runningTotal}}` tag for free (along with providing sorting, filtering etc.) by making `{{runningTotal}}` derive from `{{for}}`, as `baseTag`. This will also simplify our code considerably. See [*Specifying tag inheritance*](#tagsapi@basetag) for details and an [updated](#tagsapi@derivedfor) `{{runningTotal}}` sample.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags and 'tag controls'\",\r\n \"text\": \"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering tags](#tagsapi): The `$.views.tags()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls\",\r\n \"label\": \"Samples: JsViews tag controls\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvtagcontrols\",\r\n \"label\": \"JsViews tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrobjects\": {\r\n \"title\": \"JsRender objects\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"viewsobject\",\r\n \"label\": \"$.views object\"\r\n },\r\n {\r\n \"hash\": \"templateobject\",\r\n \"label\": \"template object\"\r\n },\r\n {\r\n \"hash\": \"viewobject\",\r\n \"label\": \"view object\"\r\n },\r\n {\r\n \"hash\": \"tagobject\",\r\n \"label\": \"tag object\"\r\n },\r\n {\r\n \"hash\": \"ctxobject\",\r\n \"label\": \"View context object (ctx)\"\r\n },\r\n {\r\n \"hash\": \"tagctxobject\",\r\n \"label\": \"Tag context object (tagCtx)\"\r\n },\r\n {\r\n \"hash\": \"globals\",\r\n \"label\": \"Globals\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"viewsobject\": {\r\n \"title\": \"The $.views object (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `$.views` object provides access to APIs for creating templates, tags, helpers etc.

                          \\n\\n\\n- `$.views.templates(...)` -- available also as `$.templates(...)`\\n
                          Used for defining templates -- see: [Registering templates](#d.templates)\\n- `$.views.tags(...)`\\n
                          Used for defining custom tags -- see: [Registering custom tags](#tagsapi)\\n- `$.views.converters(...)`\\n
                          Used for defining converters -- see: [Registering converters](#convertersapi)\\n- `$.views.helpers(...)`\\n
                          Used for defining helpers -- see: [Registering helpers](#helpersapi)\\n- `$.views.viewModels(...)`\\n
                          Used for defining View Models -- see: [Compiled View Models](#viewmodelsapi)\\n\\nIt also provides access to:

                          \\n- `$.views.settings`\\n
                          Used for modifying JsViews settings and options -- see: [Settings](#jsvsettings)\\n- `$.views.map(...)`\\n
                          Used for defining custom maps (advanced) \\n- `$.views.jsviews`\\n
                          Provides the version number of the currently loaded JsViews or JsRender library\\n\\n\"\r\n }\r\n ]\r\n },\r\n \"settingsobject\": {\r\n \"title\": \"$.views.settings object\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"subobject\": {\r\n \"title\": \"$.views.sub object\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"templateobject\": {\r\n \"title\": \"The template object (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The [`$.templates()`](#d.templates) API can be used to obtain a compiled template object:\\n\\n```js\\nvar myTmpl = $.templates(\\\" {{:name}}\\\");\\n```\\n\\nThe compiled template object (`myTmpl`, in the example) provides a number of properties and methods, in particular:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The render() method\",\r\n \"text\": \"```js\\nvar html = myTmpl.render(person);\\n```\\n\\nSee [Render a template against data objects or arrays](#tmplrender)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The markup property\",\r\n \"text\": \"The declarative markup string for the template (available whether the template was registered by providing a markup string, or by a script block reference).\\n\\n```js\\nvar test = myTmpl.markup; // \\\" {{:name}}\\\"\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The compiled template object is actually a render() function\",\r\n \"text\": \"The compiled template *is itself a function*, corresponding to its own render method, so the following two examples are actually equivalent.\\n\\n*Calling the render method:*\\n\\n```js\\nvar html = myTmpl.render(person);\\n```\\n\\n*Invoking the compiled template directly as render method:*\\n\\n```js\\nvar html = myTmpl(person);\\n```\"\r\n }\r\n ]\r\n },\r\n \"viewobject\": {\r\n \"title\": \"The view object (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates render as a [*view hierarchy*](#views).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"A view object has the following properties and methods:\",\r\n \"text\": \"- [type property](#viewobject@type)\\n- [data property](#viewobject@data)\\n- [parent property](#viewobject@parent)\\n- [index property](#viewobject@index)\\n- [getIndex() method](#viewobject@getindex)\\n- [get(type) method](#viewobject@get)\\n- [content property](#viewobject@content)\\n- [root property](#viewobject@root)\\n- [ctxPrm() 'get' method](#viewobject@ctxprm)\\n- [other properties and methods (tmpl, views, ctx, tag, getRsc()](#viewobject@other)\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `view` objects have additional methods:*\\n- *[refresh()](#jsvviewobject@refresh)*\\n- *[contents()](#jsvviewobject@contents)*\\n- *[childTags()](#jsvviewobject@childtags)*\\n- *[nodes()](#jsvviewobject@nodes)*\\n\\n*See [JsViews `view` object](#jsvviewobject).*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing view objects\",\r\n \"text\": \"The properties of the current view are accessed *declaratively* in a template using *[view paths](#paths)* -- such as `#parent` for the `view.parent` property.\\n\\nAccessing `view` objects *programmatically* is less common in JsRender, but can be useful for example:\\n\\n- in a helper function, `~myHelper()`, where the `this` pointer is the current view\\n- in the render() method of a custom tag -- using `this.tagCtx.view`\\n\\n*Note:* In JsViews, accessing `view` objects programmatically is very common, thanks to the [`$.view()`](#jsv.d.view) method. For example in a click handler, `$.view(this);` returns the corresponding `view` object.

                          \\n\\n\\n### Properties and methods:\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The type property:\",\r\n \"text\": \"***view.type**: string corresponding to the type of view:*\\n\\n- `\\\"data\\\"` -- for the top-level view from a `render()` call\\n- `\\\"array\\\"` or `\\\"item\\\"` -- from `{{for array}}` or `{{props object}}` (see *[array and item views](#views@itemview)*)\\n- `\\\"sometag\\\"` -- for the view from `{{sometag}}...{{sometag}}` -- for example: `\\\"include\\\"`, `\\\"if\\\"`, `\\\"for\\\"`, `\\\"props\\\"`, `\\\"mytag\\\"`...\\n\",\r\n \"anchor\": \"type\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The data property:\",\r\n \"text\": \"***view.data**: the current data context for the view* -- as in:\\n\\n```js\\nvar team = view.data.team; // The team property of the current data object\\n```\\n\\n`view.data` can be accessed declaratively in templates as `#data`-- as in:\\n\\n```jsr\\n{{:#data}}\\n{{>#data.description()}}\\n{{for #data.team.members}}...\\n```\\n\\nBut note that since `#data`, the current data context, is the starting point for *[data paths](#paths)* within templates, the above expressions with `#data` can be abbreviated to:\\n\\n```jsr\\n{{:}}\\n{{>description()}}\\n{{for team.members}} etc.\\n```\",\r\n \"anchor\": \"data\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parent property:\",\r\n \"text\": \"***view.parent**: the parent view* (used to step up through views in the hierarchy).\\n\\n```js\\nvar index = view.parent.index; // The index of the parent view\\n```\\n\\nAccessed declaratively as `#parent`:\\n\\n```jsr\\n{{>#parent.data.title()}}... {{!-- accessing data of parent view - view.parent --}}\\n{{if #parent.parent.parent.data.teams.length > 1}}... {{!-- accessing data of view.parent.parent... --}}\\n```\\n\\n(See also *[Accessing parent data](#parentdata)*)\",\r\n \"anchor\": \"parent\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The index property:\",\r\n \"text\": \"***view.index**: the view index* (only available on [item views](#views@itemview)).\\n\\n```js\\nvar index = view.index; // The index of the view (for \\\"item\\\" views - otherwise an 'error string')\\n```\\n\\nAccessed declaratively as `#index`:\\n\\n```jsr\\n{{if #index > 2}} {{!-- we are in an \\\"item\\\" view --}}\\n {{:#parent.index}}... {{!-- \\\"item\\\" view index (- the parent - since we are inside the 'ifView') --}}\\n{{/if}}\\n```\\n\\n**Note:** On non-\\\"item\\\" views, accessing the index property returns the error message prompt: *\\\"For #index in nested block use #getIndex().\\\"*\",\r\n \"anchor\": \"index\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The getIndex() method:\",\r\n \"text\": \"***view.getIndex()**: get the index of current \\\"item\\\" view* (steps up to nearest [item view](#views@itemview), and returns the index).\\n\\n```js\\nvar index = view.getIndex(); // The index of the view\\n```\\n\\nAccessed declaratively as `#getIndex()`:\\n\\n```jsr\\n{{for teams}}\\n {{for members}}\\n {{if #getIndex() > 0}} {{!-- index of member (- this view is an \\\"item\\\" view for member) --}}\\n {{:#getIndex()}} {{!-- index of member --}}\\n {{/if}}\\n\\n {{:#parent.getIndex()}}... {{!-- index of team (-nearest \\\"item\\\" view of parent is team \\\"item\\\" view) --}}\\n {{/for}}\\n{{/for}}\\n```\\n\",\r\n \"anchor\": \"getindex\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If index is a multiple of 3, render new tr, and format index in bold.\\n\\nUse `getIndex()` to get *item* index from within *if* block.\\n\\n```jsr\\n\\n\\n{{for members}}\\n {{if #index===0}}\\n \\n{{/for}}\\n\\n
                          1:\\n {{else #index%3===0}}\\n
                          {{:#getIndex()+1}}:\\n {{else}}\\n {{:#getIndex()+1}}:\\n {{/if}}\\n {{:name}}\\n
                          \\n```\"\r\n }\r\n ],\r\n \"markup\": \"\\n\\n{{for members}}\\n {{if #index===0}}\\n \\n{{/for}}\\n\\n
                          1:\\n {{else #index%3===0}}\\n
                          {{:#getIndex()+1}}:\\n {{else}}\\n {{:#getIndex()+1}}:\\n {{/if}}\\n {{:name}}\\n
                          \",\r\n \"data\": {\r\n \"title\": \"The A Team\",\r\n \"members\": [\r\n {\r\n \"name\": \"Jeff\"\r\n },\r\n {\r\n \"name\": \"Jack\"\r\n },\r\n {\r\n \"name\": \"Jim\"\r\n },\r\n {\r\n \"name\": \"Jo\"\r\n },\r\n {\r\n \"name\": \"Joanna\"\r\n },\r\n {\r\n \"name\": \"James\"\r\n }\r\n ]\r\n },\r\n \"title\": \"getIndex() – iterating + grouping by 3\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"80\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The get(type) method:\",\r\n \"text\": \"***view.get(type)**: returns the nearest parent view of type `type`.*\\n\\n```js\\nvar arrayView = view.get(\\\"array\\\"); // Step through parents to nearest \\\"array\\\" view\\nvar arrayLength = arrayView.data.length; // Get length of data array\\n```\\n\\nAccessed declaratively as `#get(...)`:\\n\\n```jsr\\n{{for members}}\\n {{if #index+1 === #get(\\\"array\\\").data.length}}\\n The last member in the list\\n {{/if}}\\n{{/for}}\\n```\\n\\n**Note:** An additional signature is available: ***view.get(true, type)*** (for advanced scenarios) -- which steps *down* through descendant views (depth first traversal) and returns *the first descendant view of type `type`*.\\n\\n```jsr\\n{{for members}}\\n {{:name}}\\n{{/for}}\\n{{:#get(true, \\\"item\\\").data.name}} {{!-- get the name of the first member --}}\\n```\\n\\nIn using this API it is sometimes necessary to be aware of the processing order. For example in the sample code above, placing `{{:#get(true, \\\"item\\\")...}}` before `{{for members}}` will not return any \\\"item\\\" view, since the `{{:get(...)...}}` is being evaluated during the rendering, and the \\\"item\\\" views for `{{for ...}}` will not yet have been rendered. (View instantiation is part of rendering, which is a single-pass process.) \\n\\n*Note:* `view.get(\\\"root\\\")` returns [`view.root`](#viewobject@root), `view.get()` returns [`view.parent`](#viewobject@parent) and `view.get(true)` returns [`view.views[0]`](#viewobject@other).\",\r\n \"anchor\": \"get\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The content property (for views which wrap inline block content):\",\r\n \"text\": \"***view.content**: template corresponding to the inline block content.*\\n\\nAccessed declaratively as `#content`:\\n\\nIn the [wrapping content](#tagsyntax@wrap) scenarios, the tag:\\n\\n```jsr\\n{{sometag ... tmpl=\\\"externalTmpl\\\"}}...{{/sometag}}\\n```\\n\\nor\\n\\n```jsr\\n{{mytag}}...{{/mytag}}\\n```\\n\\nwill render with a view which has both a `view.tmpl` template property and a `view.content` template property.\\n\\nThe `view.content` template corresponds to the inline block content, and is used for wrapping that content as in:\\n\\n```jsr\\nbefore {{include tmpl=#content /}} after\\n```\\n\",\r\n \"anchor\": \"content\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*mytag:* \\n\\n```js\\n$.views.tags(\\n \\\"mytag\\\",\\n \\\"startTag {{include tmpl=#content /}} endTag\\\"\\n);\\n```\\n\\n*externalTmpl:* \\n\\n```js\\n$.templates(\\n \\\"externalTmpl\\\",\\n \\\"startTmpl {{include tmpl=#content /}} endTmpl\\\"\\n);\\n```\\n\\n*Template:* \\n\\n```jsr\\n{{mytag}}\\n
                          inside mytag
                          \\n{{/mytag}}\\n\\n
                          \\n\\n{{mytag tmpl=\\\"externalTmpl\\\"}}\\n
                          inside mytag with external tmpl
                          \\n{{/mytag}}\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"code\": \"$.views.tags(\\n \\\"mytag\\\",\\n \\\"startTag {{include tmpl=#content /}} endTag\\\"\\n);\\n\\n$.templates(\\n \\\"externalTmpl\\\",\\n \\\"
                          startTmpl {{include tmpl=#content /}} endTmpl
                          \\\"\\n);\\n\\n$(\\\"#result\\\").html(\\n $.templates(\\\"#myTmpl\\\").render()\\n);\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"view.content – wrapping content\",\r\n \"height\": \"170\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The root property:\",\r\n \"text\": \"***view.root**: the root view (top-level ancestor view for this view)* -- as in:\\n\\n```js\\nvar topLevelData = view.root.data; // Get the top-level data (obtained from the root view)\\n```\",\r\n \"anchor\": \"root\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The ctxPrm() 'get' method\",\r\n \"text\": \"***view.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the view).\\n\\n```js\\nvar value = view.ctxPrm(\\\"color\\\");\\n// Get value of contextual parameter (or helper) \\\"color\\\"\\n```\\n\\nAvailable also as [`tag.ctxPrm()`](#tagobject@ctxprm).\\n\\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\\n\\n(*Note:* in JsRender, the `ctxPrm()` method is used only for *getting* the value, whereas in JsViews, [`ctxPrm()`](#jsvviewobject@ctxprm) can also be used for *setting* the value.)\",\r\n \"anchor\": \"ctxprm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Other view object properties and methods:\",\r\n \"text\": \"The following additional properties of the `view` object are used by JsRender for processing templates:\\n\\n- *tmpl*: the template used to render the view\\n- *views*: the child views in the view hierarchy\\n- *ctx*: object (hash) with the named contextual helpers/template parameters for this view\\n- *tag*: the `\\\"mytag\\\"` view rendered by a custom tag `{{mytag ...}}`, has a `view.tag` property -- the instance of the `mytag` tag object\\n- *getRsc(namedCollection, itemName)*: returns a named resource (*converter* function, compiled *template* object, compiled *tag*, *helper* or *viewModel*), as available contextually in the scope of the view (i.e. global, or local as a template resource from one of the parent templates)

                          The `namedCollection` parameter can be `\\\"templates\\\"`, `\\\"converters\\\"`, `\\\"tags\\\"`, `\\\"helpers\\\"` or `\\\"viewModels\\\"`). For example:\\n ```js\\n var upperCvtFunction = view.getRsc(\\\"converters\\\", \\\"upper\\\");\\n ```\",\r\n \"anchor\": \"other\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvviewobject\",\r\n \"label\": \"JsViews view object\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tagobject\": {\r\n \"title\": \"The tag object (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag object properties and event handlers provided as tag options\",\r\n \"text\": \"The following tag properties and event handlers can be specified as tag options in the [`$.views.tags()`](#tagsapi) call, when registering a custom tag:\\n\\n*Tag properties*\\n\\n- [`baseTag`](#tagsapi@basetag)\\n- [`flow`](#tagsapi@flow)\\n- [`template`](#tagsapi@template)\\n- [`bindTo`](#tagsapi@bindto)\\n- [`ctx`](#tagobject@ctx)\\n- [`contentCtx`](#tagsapi@contentctx)\\n- [`argDefault`](#tagsapi@argdefault)\\n\\n*Event handlers*:\\n\\n- [`init()`](#tagsapi@init)\\n- [`render()`](#tagsapi@render)\\n- [`convert()`](#tagsapi@convert)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Additional properties and methods on the tag object\",\r\n \"text\": \"In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\\n\\n*Tag properties*\\n\\n- [parent](#tagobject@parent)\\n- [parents](#tagobject@parents)\\n- [tagCtx](#tagobject@tagctx)\\n- [tagCtxs](#tagobject@tagctxs)\\n- [tagName](#tagobject@tagname)\\n- [rendering](#tagobject@rendering)\\n\\n*Tag methods*\\n\\n- [ctxPrm()](#tagobject@ctxprm)\\n- [cvtArgs()](#tagobject@cvtargs)\\n- [bndArgs()](#tagobject@bndargs)\\n- [base()](#tagobject@base)\\n- [baseApply()](#tagobject@baseapply)\",\r\n \"anchor\": \"propsmethods\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"***Note:** When using JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method, the `tag` object has many additional properties, methods and events. See [JsViews `tag` object](#jsvtagobject).*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing tag objects\",\r\n \"text\": \"The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\\n\\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\\n\\n```jsr\\n{{:~tag.parent.tagName}}`\\n```\\n\\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\\n\\n```jsr\\n{{:~tagCtx.props.mode}}`\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag properties\",\r\n \"text\": \" \",\r\n \"anchor\": \"properties\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parent property\",\r\n \"text\": \"***tag.parent**: the parent custom tag* (nearest ancestor custom tag) in the hierarchy of custom tags.\\n\\n```js\\nvar outerTag = innerTag.parent;\\n```\\n\\nAccessed declaratively as `~tag.parent`.\\n\\nSee *[Custom tag hierarchy -- Accessing parent tags](#tagsapi@parents)*\",\r\n \"anchor\": \"parent\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The parents property\",\r\n \"text\": \"***tag.parents**: a hash of all the ancestor custom tags.*\\n\\nFor example if `outerTag` is a `{{layout}}` tag:\\n\\n```js\\nvar outerTag = innerTag.parents.layout;\\n```\\n\\nAccessed declaratively as `~parentTags`.\\n\\nSee *[Custom tag hierarchy -- Accessing parent tags](#tagsapi@parents)*\",\r\n \"anchor\": \"parents\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagCtx property\",\r\n \"text\": \"***tag.tagCtx**: a [tag context](#tagctxobject) object* providing access to instance information such as arguments/properties/view etc., as in:\\n\\n```js\\n var propA = tag.tagCtx.props.propA;\\n```\\n\\nAccessed declaratively (in a tag template or wrapped content) as `~tagCtx`.\\n\\nSee [*Tag Context*](#tagsapi@context)\",\r\n \"anchor\": \"tagctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagCtxs property\",\r\n \"text\": \"***tag.tagCtxs**: an array of [tag context](#tagctxobject) objects, -- one for each {{else}} block*.\\n\\nThe first item in `tag.tagCtxs` is the `tag.tagCtx` object.\\n\\nIf the tag has `{{else}}` blocks, there will be an additional `TagCtx` object for each `{{else}}` block.\\n\\nAccessed declaratively as `~tag.tagCtxs`.\\n\\nSee [*Tag context objects for {{else}} blocks*](#tagsapi@tagctxs)\",\r\n \"anchor\": \"tagctxs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The ctx property\",\r\n \"text\": \"***tag.ctx**: a [view context](#ctxobject) object (hash) providing access to the [contextual parameters](#contextualparams)*.\\n\\nAccessed declaratively as `~tag.ctx`.\\n\\nSee also:\\n- [`tag.ctxPrm()`](#tagobject@ctxprm), below\\n- The [`ctx` tag option](#tagsapi@ctx) (for specifying default context on a custom tag)\",\r\n \"anchor\": \"ctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The tagName property\",\r\n \"text\": \"***tag.tagName**: the name of the tag*.\\n\\n(e.g. `\\\"mytag\\\"` for the `{{mytag}}` custom tag.)\",\r\n \"anchor\": \"tagname\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The rendering property\",\r\n \"text\": \"***tag.rendering**: an object (hash) that is only present during rendering*.\\n\\nIt can be used to test whether the tag is currently rendering. It is also available as a means of passing parameters (application state) from one context to another, during rendering.\",\r\n \"anchor\": \"rendering\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag methods\",\r\n \"text\": \" \",\r\n \"anchor\": \"methods\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The ctxPrm() 'get' method\",\r\n \"text\": \"***tag.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the tag instance).\\n\\n```js\\nvar value = tag.ctxPrm(\\\"color\\\");\\n// Get value of contextual parameter (or helper) \\\"color\\\"\\n```\\n\\nAvailable also as [`view.ctxPrm()`](#viewobject@ctxprm).\\n\\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\\n\\n(*Note:* in JsRender, the `ctxPrm()` method is used only for *getting* the value, whereas in JsViews, [`ctxPrm()`](#jsvtagobject@ctxprm) can also be used for *setting* the value.)\",\r\n \"anchor\": \"ctxprm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The cvtArgs() method\",\r\n \"text\": \"***tag.cvtArgs()***: returns an array `[arg1, arg2, ...]`, corresponding to the values of the arguments passed in the tag markup.\\n\\n```jsr\\n{{myTag lastName age 'edit'/}}\\n```\\n\\n```js\\nvar args = tag.cvtArgs(); // [\\\"Jones\\\", 55, \\\"edit\\\"]\\n```\\n\\nIf the tag uses a converter, then `cvtArgs(...)` will return the arguments *after* conversion.\\n\\nIf the tag uses multiple `{{else}}` blocks, then passing the `elseBlock` index as parameter to `cvtArgs(elseBlock)` returns the arguments for that `{{else}}` block.\",\r\n \"anchor\": \"cvtargs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The bndArgs() method\",\r\n \"text\": \"If a tag uses a [`bindFrom/bindTo`](#tagsapi@bindto) setting, then ***tag.bndArgs()***: returns an array `[argOrProp1, argOrProp2, ...]`, corresponding to the values of the arguments/properties specified in the `bindFrom/bindTo` option.\\n\\nIf there is no `bindFrom/bindTo` setting, then `tag.bndArgs()` is equivalent to `tag.cvtArgs()`\\n\\n```jsr\\n{{myTag lastName age mode='edit'/}}\\n```\\n\\n```js\\n$.views.tags(\\\"myTag\\\", {\\n bindFrom: [\\\"mode\\\", 1, 0],\\n init: function() {\\n var args = tag.bndArgs(); // [\\\"edit\\\", 55, \\\"Jones\\\"]\\n }\\n)\\n```\\n\\nIf the tag uses a converter, then arguments/properties returned by `bndArgs(...)` will be *after* conversion.\\n\\nIf the tag uses multiple `{{else}}` blocks, then passing the `elseBlock` index as parameter to `bndArgs(elseBlock)` returns the arguments/properties for that `{{else}}` block.\\n\\nSee also [*Specifying bound arguments and properties: the `bindTo` and `bindFrom` options*](#tagsapi@bindto)\",\r\n \"anchor\": \"bndargs\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The base() method\",\r\n \"text\": \"***tag.base()***: Used in a derived tag, when overriding a method/handler, to call the corresponding *base* method.\\n\\nAllows passing specific arguments.\\n\\n```js\\nthis.base(a, b, ...); // Pass chosen arguments\\n```\\n\\nSee [`baseTag`](#tagsapi@basetag)\",\r\n \"anchor\": \"base\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The baseApply() method\",\r\n \"text\": \"***tag.baseApply()***: Used in a derived tag, when overriding a method/handler, to call the corresponding *base* method.\\n\\nAllows passing on the `arguments` array (or some other chosen array of arguments).\\n\\n```js\\nthis.baseApply(arguments); // Pass arguments array\\n```\\n\\nExample:\\n\\n```\\n$.views.tags(\\\"mytag2\\\", {\\n baseTag: \\\"mytag\\\",\\n render: function() { // Override the render() method\\n var ret = this.baseApply(arguments); // Call the base method\\n ... // Modify return string...\\n return ret;\\n }\\n});\\n```\\n\\nSee [*Specifying tag inheritance: the `baseTag` option*](#tagsapi@basetag)\",\r\n \"anchor\": \"baseapply\"\r\n }\r\n ]\r\n },\r\n \"ctxobject\": {\r\n \"title\": \"The view context object, ctx (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Each view has a view context object: ***view.ctx***, which is a 'hash' whose properties correspond to the set of [contextual parameters](#contextualparams), `~foo` accessible from that view, within a template. (See [*Accessing contextual parameters and helpers*](#tagsapi@ctxparams).)\\n\\nIt also has the following built-in properties (contextual parameters):\\n\\n- `ctx.root`: The [root data](#contextualparams@root) (accessed from a template as `~root`)\\n- `ctx.tag`: The [tag object](#tagobject) (accessed from a template as `~tag`)\\n- `ctx.tagCtx`: The [tagCtx object](#tagobject@tagctx) (accessed from a template as `~tagCtx`)\\n- `ctx.parentTags`: [parent tags](tagsapi@parents) (accessed from a template as `~parentTags`)\\n\\nFor programmatic access to contextual parameters, it may be better to use the [view.ctxPrm()](#viewobject@ctxprm) or [tag.ctxPrm()](#tagobject@ctxprm) API.\"\r\n }\r\n ]\r\n },\r\n \"tagctxobject\": {\r\n \"title\": \"The tag context object, tagCtx (JsRender)\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"When a template is rendered, each tag is instantiated.\\n\\n```jsr\\n{{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr .../}}\\n```\\n\\nThe tag instance has an associated tag context object, `tag.tagCtx`, giving contextual information for the tag.\\n\\nSee [*Tag context*](#tagsapi@context)\\n\\nIn the case of a tag with `{{else}}` blocks it has an array of `tagCtx` objects, `tag.tagCtxs`, one for each `{{else}}` block):\\n\\n```jsr\\n{{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr ...}}\\n ...\\n{{else argExpr2 prop2=propExpr2 ~ctxprm2=prmExpr2 ...}}\\n ...\\n{{/sometag}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"tagCtx properties\",\r\n \"text\": \"- ***tagCtx.props:***\\n - a hash of the values of the named properties (such as `tagCtx.props.prop1`)\\n- ***tagCtx.args:***\\n - an array with argument value (such as `tagCtx.args[0]`)\\n- ***tagCtx.params:***\\n - provides access to argument, property and contextual parameter expressions (such as `tagCtx.params.props.prop1`, `tagCtx.params.args[0]` or `tagCtx.params.ctx.ctxprm1`)\\n- ***tagCtx.content:***\\n - for a block tag (see [wrapping block content](#tagsapi@wrapping)), the compiled template for wrapped content\\n - otherwise, for a tag with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, the compiled external template (same as `tagCtx.tmpl`)\\n - otherwise, `false`\\n- ***tagCtx.tmpl:***\\n - for a tag with an external template, `tmpl=...`, the compiled external template\\n - otherwise, for a block tag, the template for wrapped content (same as `tagCtx.content`)\\n - otherwise, `false`\\n- ***tagCtx.index:***\\n - for `{{else}}` blocks, the index of the block (see [`tag.tagCtxs`](#tagobject@tagctxs))\\n - otherwise, `0`\\n- ***tagCtx.tag:***\\n - the tag instance\\n- ***tagCtx.view:***\\n - the contextual (containing) view object\\n- ***tagCtx.ctx:***\\n - the [ctx](#ctxobject) (view context) object with the contextual helpers/template parameters for this tag.\",\r\n \"anchor\": \"properties\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"tagCtx methods\",\r\n \"text\": \"- ***tagCtx.render(data, context, noIteration):***\\n - if there is a tag template, renders the template\\n - otherwise for a template with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, renders the external template\\n - otherwise, for a block tag, renders the wrapped content\\n - otherwise, returns `\\\"\\\"`\\n - *Note:* as an alternative, to render wrapped content even if there is a tag template, or an external template (`tmpl-=...`), use
                          ***tagCtx.content.render(data, context, noIteration)***. (See [sample](#tags@renderplustmpl-sample))\\n- ***tagCtx.ctxPrm(name):***\\n - equivalent to [`tag.ctxPrm(name)`](#tagobject@ctxprm)\\n - however, for a tag with `{{else}}` blocks such as:\\n ```jsr\\n {{mytag}}...{{else ~myparam=...}}...{{/mytag}}\\n ```\\n the context is the specific `{{else}}` block -- e.g. accessing `tag.tagCtxs[1].ctxPrm(\\\"myparam\\\")` for the example above\\n- ***tagCtx.cvtArgs():***\\n - equivalent to [`tag.cvtArgs()`](#tagobject@cvtargs)\\n - however, for a tag with `{{else}}` blocks) the context is the specific `{{else}}` block
                          \\n -- i.e. equivalent to `tag.cvtArgs(tagCtx.index)`\\n- ***tagCtx.bndArgs():***\\n - equivalent to [`tag.bndArgs()`](#tagobject@bndargs)\\n - however, for a tag with `{{else}}` blocks) the context is the specific `{{else}}` block
                          \\n -- i.e. equivalent to `tag.bndArgs(tagCtx.index)`\",\r\n \"anchor\": \"methods\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Note:* When using JsViews data-linking, the tagCtx object has additional [properties](#jsvtagctxobject@properties) and [methods](#jsvtagctxobject@methods). See JsViews [`tagCtx`](#jsvtagctxobject) object.\\n\"\r\n }\r\n ]\r\n },\r\n \"node/browserify\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Browserify support for JsRender and JsViews\\n\\n[Browserify](http://browserify.org/) lets you create modular JavaScript projects for the browser, using the npm `require()` pattern for packages/modules.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender as a Browserify module\",\r\n \"text\": \"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the Browserify client script bundle, and loaded in the browser.\\n\\nThere are three options for loading JsRender in the browser as a Browserify module:\\n\\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the Browserify client script bundle:\\n ```js\\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\\n ```\\n- Load both jQuery and JsRender as modules in the Browserify client script bundle:\\n ```js\\n var $ = require('jquery'); // Load jQuery as a module\\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\n ```\\n- Load JsRender as a module in the Browserify client script bundle, without loading jQuery at all:\\n ```js\\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\\n ```\\n\\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \\n\\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \\n\\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\\n\",\r\n \"anchor\": \"jsrender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded globally:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n \\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded as module:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar $ = require('jquery'); // Load jQuery as a module\\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – JsRender without jQuery:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\\nvar tmpl = jsrender.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\ndocument.querySelector('#container').innerHTML = html;\\n```\\n\\n**command line:**\\n\\n```bash\\nbrowserify ./source.js > ./bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsViews as a Browserify module\",\r\n \"text\": \"JsViews can also be included in the Browserify client-script bundle, and loaded in the browser.\\n\\nAfter installing on the server (using `$ npm install jsviews`), call:\\n\\n```js\\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\\n```\\n\\nor -- if also loading jQuery as a Browserify module, use:\\n\\n```js\\nvar $ = require('jquery');\\n...\\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as a parameter)\\n```\",\r\n \"anchor\": \"jsviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Loading templates as Browserify modules\",\r\n \"text\": \"JsRender includes a Browserify transform: `jsrender/tmplify` (see [below](#node/browserify@clientbundle)) which allows you also to include your server [file-based templates](#node/filetmpls) in the client-script bundle generated by Browserify. \\n\\nYou can then access the compiled templates in the browser, as modules.\\n\\nThe exact syntax depends on whether jQuery is loaded globally, loaded as a Browserify module, or not loaded at all.\\n\\n- If jQuery is loaded globally then use:\\n ```js\\n var tmpl = require('./templates/myTemplate.html'); // Load template (jQuery \\n // is loaded globally)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n- If jQuery is loaded as a module, use:\\n ```js\\n var $ = require('jquery');\\n ...\\n var tmpl = require('./templates/myTemplate.html')($); // Load template (local\\n // jQuery as parameter)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n- If loading JsRender as a module, without jQuery, use:\\n ```js\\n var jsrender = require('jsrender')(); // function call -- no parameter\\n ...\\n var tmpl = require('./templates/myTemplate.html')(jsrender); // Load template (jsrender\\n // namespace as parameter)\\n var html = tmpl.render(myData);\\n ...\\n ```\\n\\n**Note on relative paths:** The `./...` paths used to identify bundled templates are always interpreted as relative paths *relative to the location of your calling script*, which in this case is the Browserify script that created the client bundle. (Note that declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Nested templates\",\r\n \"text\": \"Template inclusion in the bundle can be recursive, so for example if you call `require(\\\"./templates/myTemplate.html\\\");` and *myTemplate.html* includes a nested reference to another template, such as `{{include tmpl=\\\"./another/tmpl2.html\\\"/}}`, then the client-script bundle will include that template too.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Generating the client bundle\",\r\n \"text\": \"If *source.js* includes template references such as: `var tmpl=require('./some/path/myTemplate.html')`, then Browserify generates a client script bundle which will include the referenced templates.\\n\\n[Browserify](http://browserify.org/) provides three different ways of generating a *bundle.js* script from a *source.js* script, and calling a transform:\\n\\n**Command line:**\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\n**package.json:**\\n\\n```bash\\n\\\"browserify\\\": {\\n \\\"transform\\\": [\\n [\\\"jsrender/tmplify\\\"]\\n ]\\n}\\n```\\n\\n**API:**\\n\\n```bash\\nbrowserify('./source.js')\\n .transform(require('jsrender/tmplify'))\\n .bundle()\\n .pipe(fs.createWriteStream('./bundle.js'));\\n```\",\r\n \"anchor\": \"clientbundle\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Option: extensions\",\r\n \"text\": \"The `jsrender/tmplify` Browserify transform uses a white-space-separated list of extensions: `\\\"html jsrender jsr\\\"`, by default. This means that when you generate a client-script bundle using the `tmplify` transform, it will treat any `.html`, `.jsrender` or `.jsr` file as a template, and will include the compiled template in the client-script bundle for rendering in the browser. \\n\\nYou can instead specify a different list of file extensions for templates, by using the `--extensions` or `-e` option, as in the following examples:\\n\\n```bash \\nbrowserify -t [jsrender/tmplify --extensions 'htm jsrender'] ./source.js > ./bundle.js\\n```\\n\\n```bash \\nbrowserify -t [jsrender/tmplify -e 'htm jsrender'] ./source.js > ./bundle.js\\n```\\n\\n```bash \\n\\\"browserify\\\": {\\n \\\"transform\\\": [\\n [\\\"jsrender/tmplify\\\", {\\n \\\"extensions\\\": \\\"htm jsrender\\\"\\n }]\\n ]\\n}\\n```\\n\\n```bash \\nbrowserify('./source.js')\\n .transform(require('jsrender/tmplify'), {extensions: 'htm jsrender'})\\n .bundle()\\n .pipe(fs.createWriteStream('./bundle.js'));\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Including jQuery and/or JsRender/JsViews in the client-script bundle\",\r\n \"text\": \"When using Browserify with JsRender on Node.js, you will generally need jQuery and JsRender/JsViews in the client, to render (and optionally data-link) the templates.\\n\\njQuery, JsRender and JsViews are all available as npm/Browserify modules, so you can choose whether to load them globally, using a script block, or as a module. Here are three examples following alternative strategies:\\n\\n**Load jQuery and JsRender/JsViews globally**\\n\\n`$` is defined as a global variable (`window.$`, or `window.jQuery`).
                          \\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n\\n\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nvar myTmpl = require('./templates/myTemplate.html'); // Include compiled template in client-script bundle\\nvar html = myTmpl(data); // Render using compiled template\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\nSee the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project for complete examples:\\n- [clientcode-hello.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-hello.js) and [layout-hello.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello.html) using JsRender\\n- [clientcode-movies.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/public/js/clientcode-movies.js) and [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) using JsViews.\\n \\n**Load jQuery and JsRender/JsViews as Browserify modules**\\n\\nUse `var $ = require('jquery')` to load jQuery, and `require('jsrender')($)` or `require('jsviews')($)` to load JsRender/JsViews.
                          \\nUse `require(templatePath)($)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nvar $ = require('jquery');\\nrequire('jsrender')($);\\nvar myTmpl = require('./templates/myTemplate.html')($)\\nvar html = myTmpl(data);\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\nSee:\\n- [clientcode-hello-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify.js) and [layout-hello-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify.html) for an example loading jQuery and JsRender as modules\\n- [clientcode-hello-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-hello-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading JsRender as a module (without jQuery)\\n- [clientcode-movies-browserify2.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-hello-browserify2.js) and [layout-movies-browserify2.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-hello-browserify2.html) for an example loading jQuery and JsViews as modules\\n\\n**Mixed approach: Load jQuery globally, and JsRender/JsViews as a Browserify module**\\n\\n`$` is defined as a global variable (`window.$` or `window.jQuery`).
                          \\nUse `require('jsrender')` or `require('jsviews')` to load JsRender/JsViews.
                          \\nUse `require(templatePath)` to load templates as Browserify modules included in the client-script bundle, as in the following example:\\n\\n*index.html:*\\n\\n```jsr\\n\\n...\\n\\n```\\n\\n*source.js:*\\n\\n```js\\nrequire('jsrender');\\nvar myTmpl = require('./templates/myTemplate.html');\\nvar html = myTmpl(data);\\n$('#result').html(html);\\n```\\n\\n*command line:*\\n\\n```bash\\nbrowserify -t jsrender/tmplify ./source.js > ./bundle.js\\n```\\n\\nSee [clientcode-movies-browserify.js](//github.com/BorisMoore/jsrender-node-starter/blob/master/browserify/clientcode-movies-browserify.js) and [layout-movies-browserify.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies-browserify.html) for an example using JsViews.\",\r\n \"anchor\": \"clientscript\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sample code\",\r\n \"text\": \"For running code examples using JsRender, Browserify, and the `tmplify` transform, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also:\",\r\n \"text\": \"*[Webpack support](#node/webpack)*\"\r\n }\r\n ]\r\n },\r\n \"node/renderfile\": {\r\n \"title\": \"renderFile() method\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender on Node.js provides a shortcut `renderFile` method, for convenience, to compile and render in one step:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n// result: Name: Jim
                          \\n```\\n\"\r\n }\r\n ]\r\n },\r\n \"node/filetmpls\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## File-based templates\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining templates as .html files\",\r\n \"text\": \"On Node.js, JsRender templates can be stored directly in the file system (e.g. as `.html`, `.jsr.` or `.jsrender` files) -- for example:\\n\\n**Template:** *./templates/myTemplate.html* -- with contents:\\n\\n```jsr\\nName: {{:name}}
                          \\n```\\n\\n**Code:** JsRender recognizes file paths (for valid relative file paths starting with `'./'`), so you can write:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar tmpl = jsrender.templates('./templates/myTemplate.html'); // Compile the template\\n\\nvar html = tmpl({name: \\\"Jim\\\"}); // Render\\n// result: Name: Jim
                          \\n```\\n\\n**Note:** The `./...` paths are always interpreted as relative paths *relative to the location of your calling script*. Declaring a *templates* folder for Express or Hapi does not change the origin of these relative paths.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"renderFile() method\",\r\n \"text\": \"JsRender on Node.js provides a shortcut `renderFile()` method, for convenience, to compile and render in one step:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n// result: Name: Jim
                          \\n```\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"jsrender.renderFile(filepath, data)\",\r\n \"name\": \"renderFile\",\r\n \"object\": \"jsrender\",\r\n \"method\": true,\r\n \"returns\": \"string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"filepath\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"Relative path to template file - starting with './'\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object or array\",\r\n \"optional\": true,\r\n \"description\": \"The data to render. This can be any JavaScript type, including Array or Object.\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"var jsr = require('jsrender');\\nvar html = jsr.renderFile('./.../tmpl.html', data);\",\r\n \"description\": \"Load file-based template, compile and render against data\"\r\n }\r\n ],\r\n \"description\": \"Shortcut method – compile and render\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Nested calls to file-based templates (composition)\",\r\n \"text\": \"JsRender's awareness of Node.js file paths (relative paths starting with `'./'`) means your templates can include recursive calls to other templates (partials). You don't need to register or compile those templates separately. (See also: [template composition](#tagsyntax@composition)).\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\nName: {{:name}}
                          Address: {{include tmpl='./templates/other/addressTemplate.jsr'}}\\n```\\n\\n**Template:** *./templates/other/addressTemplate.jsr*:\\n```jsr\\nStreet: {{:street}}\\n```\\n\\n**Code:** Compile and render, recursively:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar tmpl = jsrender.templates('./templates/personTemplate.html');\\n// Compile template - and also any recursively called templates\\n\\nvar html = tmpl({name: \\\"Jim\\\", street: \\\"Main St\\\"});\\n// result: Name: Jim
                          Address: Main St\\n```\",\r\n \"anchor\": \"composition\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Register a file-based template by name – and render it\",\r\n \"text\": \"For convenience you can register file-based templates by name, just as you can for [templates from strings](#d.templates@namedfromstring).\\n\\n```js\\n// Register named template - \\\"myTmpl1\\n$.templates(\\\"myTmpl1\\\", \\\"./templates/myTemplate.html\\\");\\n\\n// Render named template\\nvar html = $.templates.myTmpl1(person);\\n\\n// Alternative syntax: var html = $.render.myTmpl1(person);\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Automatic caching of file-based templates\",\r\n \"text\": \"The first time `jsrender.templates('./templates/myTemplate.html')` is called, JsRender will:\\n\\n - load the template file from the file system\\n - compile the template\\n - cache the template\\n - return the compiled template\\n\\nThe cached template can be accessed directly as `jsrender.templates['./templates/myTemplate.html']` - and can also be deleted by calling `delete jsrender.templates['./templates/myTemplate.html']`, or `jsrender.templates('./templates/myTemplate.html', null)`\\n\\nOn subsequent calls, JsRender will simply:\\n - return the compiled template\\n\\nThe caching means you can load and compile the template during server initialization, and avoid the cost of reading the file or compiling during HTTP requests:\\n\\n```js\\njsrender.templates('./templates/myTemplate.html'); // Cache the compiled template\\n\\napp.get('/...', function(req, res) {\\n res.render('myTemplate', {name: \\\"Jim\\\"}); // Render previously cached template, using Express\\n});\\n```\\n\\nSimilarly when using the alternative forms for rendering templates:\\n\\n```js\\napp.get('/...', function(req, res) {\\n var tmpl = jsrender.templates('./templates/myTemplate.html'); // Get previously cached template\\n var html = tmpl.render({name: \\\"Jim\\\"});\\n res.send(html);\\n});\\n```\\n\\nor \\n\\n```js\\napp.get('/...', function(req, res) {\\n // Render previously cached template\\n var html = jsrender.renderFile('./templates/myTemplate.html', {name: \\\"Jim\\\"});\\n res.send(html);\\n});\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the same template on the server and in the browser\",\r\n \"text\": \"JsRender lets you easily use the same templates for both server and browser rendering. See *[server/browser templates](#node/server-browser)* for details on two alternative approaches, one with the `{{clientTemplate}}` tag, and the other using *Browserify*.\"\r\n }\r\n ]\r\n },\r\n \"jsrnode\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Quickstart\",\r\n \"text\": \"See the [JsRender Node.js Quickstart](#jsr-node-quickstart) for an overview of JsRender support in Node.js\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"Detail topics:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"node/install\",\r\n \"label\": \"Installation and usage\"\r\n },\r\n {\r\n \"hash\": \"node/filetmpls\",\r\n \"label\": \"File-based templates\"\r\n },\r\n {\r\n \"hash\": \"node/express-hapi\",\r\n \"label\": \"Express and Hapi integration\"\r\n },\r\n {\r\n \"hash\": \"node/server-browser\",\r\n \"label\": \"Server/browser shared templates\"\r\n },\r\n {\r\n \"hash\": \"node/browserify\",\r\n \"label\": \"Browserify support\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"node/install\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Installation\\n\\nOn Node.js from the command line, install jsrender:\\n\\n```bash\\n$ npm install jsrender\\n```\\n\\n## Usage\\n\\nLoad the jsrender module:\\n\\n```js\\nvar jsrender = require('jsrender');\\n```\\n\\nNow call JsRender APIs, or use [Express](#node/express-hapi@express) or [Hapi](#node/express-hapi@hapi) integration, for server-rendering of JsRender templates.\\n\\n(For loading JsRender in the browser using Browserify or webpack, see *[JsRender as a Browserify module](#node/browserify@jsrender)* and *[JsRender as a webpack module](#node/webpack@jsrender)*)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender APIs on the server – same as in the browser!\",\r\n \"text\": \"In the browser, when jQuery is present, JsRender loads as a jQuery plugin and adds APIs to the jQuery namespace object, as:\\n\\n`$.views`, `$.templates` and `$.render` \\n\\nOn the server exactly the same APIs are provided, associated instead with the `jsrender` namespace:\\n\\n`jsrender.views`, `jsrender.templates` and `jsrender.render`.\\n\\nFor convenience you can call the namespace `$` and then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy from the regular browser examples/samples -- as if in the browser with jQuery.\\n\\nFor example:\\n\\n```js\\nvar $ = require('jsrender'); // Returns the jsrender namespace object - referenced for convenience as var $\\n\\nvar tmpl = $.templates('Name: {{:first}} {{upper:last}}'); // Compile template from string\\n\\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\\n \\nvar data = {first: 'Jo', last: 'Ryan'};\\n\\nvar html = tmpl(data); // Or alternative syntax: var html = tmpl.render(data);\\n// result: \\\"Name: Jo RYAN\\\" \\n```\",\r\n \"anchor\": \"apis\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helpers, converters, custom tags...\",\r\n \"text\": \"On Node.js you can use the full set of JsRender features, template tags and APIs, just as you would in the browser -- by simply using the `jsrender` namespace object returned from `require('jsrender')`, instead of the jQuery object, `$`. In addition you can take advantage of [file-based templates](#node/filetmpls).\\n\\n**Custom Tags example:** -- For example, here is the JsRender Quickstart *[Custom Tags Sample](#jsr-quickstart@customtags)*, as you might write it on Node.js:\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\nName: {{fullName person/}}\\n```\\n\\n**Code:**\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\njsrender.views.tags(\\\"fullName\\\", \\\"{{:first}} {{:last}}\\\"); // Register custom tag\\n\\nvar tmpl = jsrender.templates('./templates/personTemplate.html'); // Compile template\\n\\nvar html = tmpl({person: {first: \\\"Jim\\\", last: \\\"Varsov\\\"}}); // Render\\n// result: \\\"Jim Varsov\\\"\\n```\\n\\n**Helpers example:** -- And here is the JsRender Quickstart *[Helpers](#jsr-quickstart@helpers)* example, in a version for Node.js:\\n\\n**Template:** *./templates/personTemplate.html*:\\n\\n```jsr\\n{{:~title}} {{:first}} {{:~upper(last)}}\\n```\\n\\n**Code:**\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nvar myHelpers = {\\n upper: function(val) { return val.toUpperCase(); },\\n title: \\\"Sir\\\"\\n};\\n\\nvar tmpl = $.templates('./templates/personTemplate.html');\\n\\nvar data = {first: \\\"Jim\\\", last: \\\"Varsov\\\"};\\n\\nvar html = tmpl(data, myHelpers);\\n// result: \\\"Sir Jim VARSOV\\\"\\n```\\n\\nOr we can register helpers globally:\\n\\n```js\\njsrender.views.helpers(myHelpers);\\n\\nvar data = {first: \\\"Jim\\\", last: \\\"Varsov\\\"};\\nvar html = tmpl(data);\\n// result: \\\"Sir Jim VARSOV\\\"\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Additional API: jsrender.compile()\",\r\n \"text\": \"On NodeJS, an additional `jsrender.compile(...)` API is available, as an alternative to `jsrender.templates(...)`. This is provided for compatibility with standard APIs, and for better integration with platforms such as Hapi:\\n\\nThe following:\\n\\n```js\\n// Compile template from file\\nvar tmpl1 = jsrender.compile('./templates/mytmpl.html');\\n\\n// Compile template from markup string\\nvar tmpl2 = jsrender.compile('Name: {{name}}');\\n```\\n\\nis equivalent to:\\n\\n```js\\n// Compile template from file\\nvar tmpl1 = jsrender.templates('./templates/mytmpl.html');\\n\\n// Compile template from markup string\\nvar tmpl2 = jsrender.templates('Name: {{name}}');\\n```\\n\\n**Note:** both the above APIs allow [passing in additional template options](#d.templates@resources), such as associated converter resources:\\n\\n```js\\n// Compile template from markup string, and provide options\\nvar tmpl3 = jsrender.compile('Name: {{upper:name}}', {\\n converters: {upper: ...}\\n});\\n```\\n\\nor equivalently:\\n\\n```js\\n// Compile template from markup string, and provide options\\nvar tmpl3 = jsrender.templates({\\n markup: 'Name: {{upper:name}}',\\n converters: {upper: ...}\\n});\\n```\",\r\n \"anchor\": \"compile\"\r\n }\r\n ]\r\n },\r\n \"node/express-hapi\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Express and Hapi integration\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using Express to render templates\",\r\n \"text\": \"In Express you can use JsRender APIs to render the template, as in the examples above, then return the html in the HTTP response:\\n\\n```js\\napp.get('/...', function(req, res) {\\n res.send(html);\\n});\\n```\\n\\nBut alternatively you can register JsRender as template engine for Express:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\napp.engine('html', jsrender.__express); // Set JsRender as template engine for .html files\\napp.set('view engine', 'html'); \\napp.set('views', __dirname + '/templates'); // Folder location for JsRender templates for Express\\n```\\n\\nRender template *./templates/myTemplate.html* -- content: `Name: {{:name}}
                          `:\\n\\n```js\\napp.get('/...', function(req, res) {\\n res.render('myTemplate', {name: \\\"Jim\\\"}); \\n // result: Name: Jim
                          \\n});\\n```\",\r\n \"anchor\": \"express\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using Hapi to render templates\",\r\n \"text\": \"JsRender also has built-in support as template engine for [Hapi](http://hapijs.com/):\\n\\nSet JsRender as the template engine for Hapi:\\n\\n```js\\nvar jsrender = require('jsrender');\\n\\nserver.register(vision, function (err) {\\n ...\\n server.views({\\n engines: { html: jsrender },\\n relativeTo: __dirname,\\n path: 'templates'\\n });\\n```\\n\\nUse Hapi to render a template:\\n\\n```js\\nserver.route({\\n method: 'GET',\\n path: '/',\\n handler: function (request, reply) {\\n return reply.view('myTemplate', myData);\\n }\\n});\\n```\",\r\n \"anchor\": \"hapi\"\r\n }\r\n ]\r\n },\r\n \"node/server-browser\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Sharing the same templates between server and browser\\n\\nJsRender lets you share templates between server and client, using either of the *Browserify* or *{{clientTemplate}}* approaches shown below.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Browserify\",\r\n \"text\": \"Using Browserify with the `jsrender/tmplify` transform allows you to include your server [file-based templates](#node/filetmpls) in the Browserify client-script bundle. \\n\\nYou can then access the compiled templates in the browser, as modules, using:\\n\\n```js\\nvar tmpl = require('./.../myTemplate.html)`\\nvar html = tmpl.render(myData);\\n...\\n```\\n\\nFor details, see the *[Browserify](#node/browserify)* topic.\\n\\nFor complete running samples, see the *index-express-browserify.js* and *index-hapi-browserify.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering file-based templates in the browser: {{clientTemplate}}\",\r\n \"text\": \"JsRender also provides a `{{clientTemplate}}` tag that makes file-based templates available for rendering in the browser without needing to use Browserify.\\n\\nSimply include `{{clientTemplate \\\"templateFilePath...\\\"}}` in the layout template, for any template you want to expose in the browser:\\n\\n```jsr\\n\\n {{clientTemplate \\\"./templates/myTemplate.html\\\" /}}\\n\\n\\n
                          \\n\\n\\n```\\n\\nSee the *index-express.js* and *index-hapi.js* samples in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* project.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender on the server, JsRender or JsViews in the browser...\",\r\n \"text\": \"Both the *Browserify* and the *{{clientTemplate}}* approach to sharing templates between server and browser let you then render or link those templates in the browser, using JsRender or JsViews.\\n\\nIn the browser, you reference the templates using the same `./file/path/template.html` syntax as on the server. \\n\\nFor example, in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)* samples, the [layout-movies.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/layout-movies.html) template contains the following:\\n\\n```html\\n\\n {{include tmpl=\\\"./templates/movie-list.html\\\"/}}\\n\\n```\\n\\nHere, the `{{include ...}}` is used on the server to do initial rendering of the movies list using the *movie-list.html* template. Then in the browser, the `data-link=\\\"{include ...}` causes JsViews to access the same template in the browser, and provide dynamic data-binding of the list...\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Single Page Apps with initial rendering on server\",\r\n \"text\": \"An important scenario is a *single page app* using JsRender or JsViews in the client to create dynamic UI, combined with initial rendering of the content on the server by JsRender using the same template.\\n\\nThis can bring many advantages, including SEO, and eliminating flicker when the page is refreshed with a new server request.\\n\\n*Note:* To completely eliminate flicker on data-linked content which has already been rendered on the server, it is sometimes useful to use the syntax `data-link=\\\"...^{...}\\\"` -- which data-links without doing the initial render. Here is an example from [movie-detail.html](//github.com/BorisMoore/jsrender-node-starter/blob/master/templates/movie-detail.html) in the *[JsRender Node Starter](https://github.com/BorisMoore/jsrender-node-starter)*:\\n\\n```html\\n
                          \\n```\\n\"\r\n }\r\n ]\r\n },\r\n \"tagsyntax\": {\r\n \"title\": \"Tag syntax\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Template tags in JsRender use the Mustache style: `{{...}}`.
                          \\n(You can choose different delimiters, such as `<%...%>`, using `$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\")`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tags without content\",\r\n \"text\": \"The most common JsRender tags are [`{{: pathOrExpr}}`](#assigntag) -- which inserts the value of the path or expression, and [`{{> pathOrExpr}}`](#htmltag) which inserts the *HTML-encoded* value of the path or expression. \\n\\nThose tags, along with the *allow code* tag [`{{* ...}}`](#allowcodetag) and *comment tag* [`{{!-- ... --}}`](#commenttag), are self-contained tags which do not wrap other content:\\n\\n**Built-in tags without content:**\\n\\n```jsr\\n{{: pathOrExpr}} (value)\\n{{> pathOrExpr}} (HTML-encoded value)\\n{{* mycode}} (using code)\\n{{!-- this is a comment --}} \\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags – tags with content: \",\r\n \"text\": \"**All other built-in tags, as well as all custom tags, use the block tag syntax:**\\n\\n```jsr\\n{{include ...}}...{{/include}} or {{include .../}}\\n{{for}}...{{/for}} or {{for.../}}\\n{{props}}...{{/props}} or {{props .../}}\\n{{if}}...{{/if}} or {{if .../}}\\n{{myCustomTag}}...{{/myCustomTag}} or {{myCustomTag .../}}\\n```\\n\\nTags using the *block tag syntax* have *open* and *close* tags, with content, or else they use the self-closing syntax, without content:\\n\\n**Block tag with content**\\n\\n```jsr\\n{{sometag ...}}\\n content\\n{{/sometag}}\\n```\\n\\n**Self-closing block tag (empty tag) -- no content:**\\n\\n```jsr\\n{{sometag .../}}\\n```\\n\\n\",\r\n \"anchor\": \"blocktag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using tmpl=... to reference content as an external template\",\r\n \"text\": \"A particular case of self-closing syntax is when any block tag uses the named property `tmpl=...` to reference an external template, which then replaces what would have been the block content.\\n\\nThis is a very useful technique for encapsulation and reuse of tag content. The content becomes a *'partial'* -- and is included thanks to template composition:\\n\\n**Self-closing block tag referencing an external template:**\\n\\n```jsr\\n{{sometag ... tmpl=.../}}\\n```\\n\\n(See for example `{{for languages tmpl=\\\"#columnTemplate\\\"/}}` in [this sample](#samples/jsr/composition/tmpl).)\\n\",\r\n \"anchor\": \"tmplref\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Template composition (partials)\",\r\n \"text\": \"The most common way of composing templates is to have a layout template, and to use `{{include tmpl=... /}}`:\\n\\n```jsr\\ntop level content\\n{{include tmpl='myInnerTemplate' /}}\\n```\\n\\nBut in fact template composition can be done by adding references to external templates using `tmpl=...` on ***any*** tag, as shown in the previous section.\\n\\n**Dynamic composition**\\n\\nNote that the `tmpl=...` can use any expression, so you can assign different nested templates dynamically based on data or context. For example you might write `{{include tmpl=~getTemplate(type) /}}` -- where `~getTemplate(...)` is a helper which returns a different template based in this case on the `type` property of the current data item.\\n\\nIn fact when setting `tmpl=...` dynamically, the returned template can be in any if the following forms:\\n- a compiled template\\n- a markup string\\n- the name of a registered template\\n- a selector\\n- (on Node.js) a file path to a template\",\r\n \"anchor\": \"composition\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag arguments and named properties\",\r\n \"text\": \"Tags can take both unnamed arguments and named properties:\\n\\n```jsr\\n{{sometag argument1 param1=...}}\\n content\\n{{/sometag}}\\n```\\nAn example of a named property is the `tmpl=...` property mentioned above:\\n\\n```jsr\\n{{for languages tmpl=\\\"#columnTemplate\\\"/}}\\n```\\n\\nArguments and named properties can be assigned values from simple data-paths such as:\\n\\n```jsr\\n{{formattedAddress address.street format=~util.formats.upper /}}\\n```\\n\\nor from richer expressions such as `product.quantity * 3.1 / 4.5`, or `name.toUpperCase()`\\n\\n```jsr\\n{{productValue product.quantity*3.1/4.5 description=name.toUpperCase() /}}\\n```\\n\",\r\n \"anchor\": \"tagparams\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Wrapping content \",\r\n \"text\": \"If a tag has an external `tmpl=...` reference, ***and*** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (one or more times), thanks to the [`view.content`](#viewobject@content) or `#content` property:\\n\\n```jsr\\n{{sometag ... tmpl=\\\"externalTmpl\\\"}}\\n inline block content\\n{{/sometag}}\\n```\\n\\n```js\\n$.templates(\\\"externalTmpl\\\", \\\"before {{include tmpl=#content /}} after\\\";\\n```\\n\\nSimilarly, a custom tag can use a built-in template which wraps the inline content:\\n\\n \\n```jsr\\n{{mytag}}\\n inline block content\\n{{/mytag}}\\n```\\n\\n```js\\n$.view.tags(\\\"mytag\\\", {\\n ...\\n template: \\\"before {{include tmpl=#content /}} after\\\"),\\n ...\\n});\\n```\",\r\n \"anchor\": \"wrap\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Block tags with {{else}}\",\r\n \"text\": \"Some block tags provide features which involve using alternative content blocks. Block tag syntax supports this by allowing the content to be separated into two or more alternative content blocks, using `{{else}}` tags as separators:\\n\\nFor example, the [`{{if}}`](#iftag) tag uses `{{else}}` to provide *if-else*, or *if-elseif-else ...* behavior:\\n\\n```jsr\\n{{if firstExpression}}\\n render this if the firstExpression is true\\n{{else secondExpression}}\\n else render this if the secondExpression is true\\n{{else}}\\n else render this\\n{{/if}}\\n```\\n\\nAnd the [`{{for}}`](#propstag) tag accepts alternative content to render if an array is empty (or an array or object is `null` or `undefined`):\\n\\n```jsr\\n{{for members}}\\n Member Name: {{:name}}\\n{{else}}\\n There are currently no members...\\n{{/for}}\\n```\\n\\nSimilarly you can use `{{else}}` with a custom tag, such as in [this sample](#samples/tag-controls/tabs):\\n\\n```jsr\\n{{tabs caption=\\\"First Tab\\\"}}\\n first tab content\\n{{else caption=\\\"Second Tab\\\"}}\\n second tab content\\n{{/tabs}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsrtags\",\r\n \"label\": \"Template tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"views\": {\r\n \"title\": \"JsRender view hierarchy\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"A view is a rendered template/block tag\",\r\n \"text\": \"Each instance of a rendered template or a template [block tag](#tagsyntax@blocktag) is associated with a JsViews [*\\\"view\\\"* object](#viewobject).\\n\\nFor example, if the following template is rendered, and inserted into the page --\\n\\n```jsr\\n\\n```\\n\\n```js\\nvar team = {title: \\\"The A team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]};\\n\\nvar html = $(\\\"#teamTemplate\\\").render(team);\\n```\\n\\n-- then the rendered result will have the following *view structure*:\\n\\n
                          \\n— teamView                (Team: The A team)\\n   — ifView               (The team has members!)\\n
                          \\n\\n\\nEach view is associated with a [`view`](#viewobject) object, which provides APIs for accessing properties of that view, as well as for accessing parent or child views in the view hierarchy.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The data context of a view\",\r\n \"text\": \"In particular, a [`view`](#viewobject) has a [`data`](#viewobject@data) property, which is the *current data context* used for rendering that *view* (rendering that template, or inline block content):\\n\\n
                          \\n— teamView                data: team\\n   — ifView               data: team\\n
                          \\n\",\r\n \"anchor\": \"datacontext\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Inline block content / external 'tmpl=...' reference: same view hierarchy...\",\r\n \"text\": \"A view corresponds to an instance of a *[block tag](#tagsyntax@blocktag)* ***or*** a *rendered template* -- so if we replace the inline content of a tag by an external reference: `tmpl=...`, the rendered result will be unchanged, and *the view structure will also be identical*:\\n\\n```jsr\\n\\n\\n\\n```\\n\\nSame view structure as before:\\n \\n
                          \\n— teamView                data: team\\n   — ifView               data: team\\n
                          \",\r\n \"anchor\": \"nestedtmpl\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Stepping into a block tag – what is the new data context?\",\r\n \"text\": \"Let's add a custom tag `{{mytag}}` to our template:\\n\\n```jsr\\nMy team\\n{{mytag members/}}\\n...\\n```\\n\\nWe'll define the custom tag, with a built-in template:\\n\\n```js\\n $.views.tags(\\\"mytag\\\", \\\"{{:length}} member(s)\\\");\\n```\\n\\n`{{mytag members/}}` will render block content (with an associated view) using its tag template `\\\"{{:length}} members\\\"`. \\n\\n*What will the data context be for the `mytag` view?*\\n\\nBy default:\\n\\n- a block tag with no argument `{{sometag}}` will stay on the current data context\\n- a block tag with an argument `{{sometag expr ...}}` will move the data context to `expr`.\\n\\nSo `{{mytag members}}` (just like `{{include members}}`) *will move the data context to `members`*.\",\r\n \"anchor\": \"innerdata\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"However a block tag may be designed to simply stay on the same data context as the parent block -- and that is the case for the `{{if}}` tag:\\n\\n- `{{if expr}}` does not move the data context.\\n\\nSo our template\\n\\n```jsr\\n\\n```\\n\\nwill have this view structure:\\n\\n
                          \\n— teamView                data: team\\n   — mytagView            data: team.members\\n   — ifView               data: team (same as parent – teamView)\\n
                          \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Array views and item views – {{for array}}\",\r\n \"text\": \"Now let's add a `{{for members}}` tag to iterate over the `members`, inside the `{{if}}` block:\\n\\n```jsr\\nTeam\\n{{mytag members/}}\\n\\n{{if members.length}}\\n Members:\\n {{for members}}\\n {{:name}}\\n {{/for}}\\n{{/if}}\\n```\\n\\nWhen a [`{{for ...}}`](#propstag) tag is used with an array it creates:\\n\\n- an *\\\"array\\\" view*, whose `data` property is the array -- and under the \\\"array\\\" view:\\n- an *\\\"item\\\" view* for each item in the array -- with as `data` property the item, and as [`index`](#getindex) property the index in the array:\\n\\n(Similarly, any tag which derives from the `{{for}}` tag -- such as the [`{{props}}`](#propstag) tag -- will also add an \\\"array\\\" view and \\\"item\\\" views...)\\n\\nSo our view structure with the `{{for}}` tag included will now be :\\n\\n
                          \\n— teamView                data: team                 type: \\\"data\\\"\\n   — mytagView            data: team.members         type: \\\"mytag\\\"\\n   — ifView               data: team                 type: \\\"if\\\"\\n      — arrayView         data: team.members         type: \\\"array\\\"\\n         — itemView       data: team.members[0]      type: \\\"item\\\"\\n         — itemView       data: team.members[1]      type: \\\"item\\\"\\n
                          \\n\\n-- where we show also the [`type`](#viewobject@type) property of each `view`.\",\r\n \"anchor\": \"itemview\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Array views and item views – tmpl.render(array)\",\r\n \"text\": \"Suppose now we have an array of teams -- and we pass the `teams` array to the `render()` method:\\n\\n```js\\nvar teams = [\\n {title: \\\"A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n```\\n\\nJsRender will render the `teamTemplate` once for each team -- and just like with the `{{for}}` it will create an *\\\"item\\\" view* for each item in the `teams` array -- with the two *\\\"item\\\" views* as children of an *\\\"array\\\" view*.\\n\\nHere it is as a working sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var html = $(\\\"#teamTemplate\\\").render(teams);\\n\"\r\n }\r\n ],\r\n \"markup\": \"\",\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"// mytag: custom tag to output \\\"1 member\\\" or \\\"n members\\\"\\n$.views.tags(\\\"mytag\\\", \\\"{{:length == 1 ? '1 member' : length + ' members'}}
                          \\\");\\n// Alternative version of mytag:\\n// $.views.tags(\\\"mytag\\\", \\\"{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
                          \\\");\\n\\nvar teams = [\\n {title: \\\"The A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"The B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"86\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is the resulting view structure:\\n\\n
                          \\n— arrayView               data: teams\\n   — itemView             data: teams[0]               (Team: The A Team - )\\n      — mytagView         data: team.members           (2 members)\\n      — ifView            data: teams[0]               (Members:)\\n         — arrayView      data: teams[0].members\\n            — itemView    data: teams[0].members[0]    (Jeff)\\n            — itemView    data: teams[0].members[1]    (Maria)\\n   — itemView             data: teams[1]               (Team: The B Team - )\\n      — mytagView         data: team.members           (1 members)\\n      — ifView            data: teams[1]               (Members:)\\n         — arrayView      data: teams[1].members\\n            — itemView    data: teams[1].members[0]    (Francis)\\n
                          \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"The default argument for a tag is the current data – #data\",\r\n \"text\": \"For all built-in tags (and custom tags if you don't use the [argDefault](#tagsapi@argdefault) option), you can pass the current data to the tag by writing it without an argument.\\n\\nSo the following:\\n\\n```jsr\\n{{:}} {{!--Render value of current data (string)--}}\\n{{>}} {{!--Render value of current data (string)--}}\\n{{for}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\\n{{if}}...{{/if}} {{!--Render block if current data is truthy--}}\\n{{props}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\\n```\\n\\nare equivalent to:\\n\\n```jsr\\n{{:#data}} {{!--Render value of current data (string)--}}\\n{{>#data}} {{!--Render value of current data (string)--}}\\n{{for #data}}...{{/for}} {{!--Move to current data (object) or iterate over current data (array)--}}\\n{{if #data}}...{{/if}} {{!--Render block if current data is truey--}}\\n{{props #data}}...{{/props}} {{!--Iterate over properties of current data (object)--}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"In JsViews: From UI back to data:\",\r\n \"text\": \"***Note:*** One of the features provided by JsViews data-linking (when you use the JsViews [`.link()`](#jsvlinktmpl) method rather than JsRender's [`.render()`](#rendertmpl) method) is the [`$.view(elem)`](#$view) method. This method provides a *reverse mapping* and lets you get from a rendered DOM element back to the corresponding view object in the view hierarchy. From the view you can get to the underlying data, the index, etc.\\n\\nSo in effect in JsViews, *the mapping from the view hierarchy to the UI becomes a two-way mapping...* \\n\\nSee [*Using $.view() to get from the rendered UI back to the data*](#jsv.d.view)\",\r\n \"anchor\": \"#$view\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"getindex\",\r\n \"label\": \"getIndex()\"\r\n },\r\n {\r\n \"hash\": \"contextualparams\",\r\n \"label\": \"Contextual parameters\"\r\n },\r\n {\r\n \"hash\": \"parentdata\",\r\n \"label\": \"Accessing parent data\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"paths\": {\r\n \"title\": \"Paths and expressions\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender tags can take [unamed arguments, or named properties](#tagsyntax@tagparams):\\n\\n```jsr\\n{{:arg0}}\\n\\n{{sometag arg1 arg2 param_a=param1 param_b=param2}}\\n content\\n{{/sometag}}\\n```\\n\\nThe values of the arguments or properties (such as `arg0`... `param1` ... above) must be valid JsRender paths or expressions.\\n\\nJsRender expressions are regular Javascript expressions, but with *no access to global variables*.\\n\\nInstead of global Javascript variables, JsRender expressions use *data paths*, *helper paths* and *view paths*, to access data values, values provided by helpers, and values obtained from the [view hierarchy](#views), such as the `#getIndex()`.\\n\\n***Data paths*** are of the form `dataProperty.bb.cc`, and they step through the data hierarchy, starting from the current data item (the [data context](#views@datacontext) for the current view). They can include array access, such as `team.members[id]`\\n\\n***View paths*** are of the form `#viewProperty.bb.cc`, and they start from the current [view](#views). So for example, `#data` is short for `#view.data` -- where `#view` is the current view.\\n\\n***Helper paths*** are of the form `~myHelper.bb.cc`, and they start from the named [helper](#helpers) `\\\"myHelper\\\"`. In addition they can be used to access *[contextual parameters](#contextualparams)*, or the built-in [`~root`](#contextualparams@root) \\n\\nHere are some examples of JsRender paths and values:\\n\\n*Data paths*:\\n\\n```jsr\\n{{:name}}\\n{{for address.street}}...{{/for}}\\n{{>team.members[0].lastName}}\\n{{:name.toUpperCase()}}\\n```\\n\\n*Helper paths*:\\n\\n```jsr\\n{{>~utilities.errorMessages.msg1}}\\n{{if ~settings.show}}...{{/if}}\\n{{:~root.selectedName}} {{!--Accessing root data--}}\\n```\\n\\n*View paths*:\\n\\n```jsr\\n{{:#getIndex()}}\\n{{include #content /}}\\n{{if #parent.parent.data.isLead}}...{{/if}}\\n{{>~getDescription(#data)}}\\n```\\n\\n*A primitive value of type string, number, boolean, null ...*:\\n\\n```jsr\\n{{if isOpen tmpl='It is open' /}}\\n{{for address tmpl=\\\"#addressTemplate\\\"}}...{{/for}}\\n{{for members start=1 end=5 /}}\\n{{for members reverse=true /}}\\n```\\n\\nJsRender expressions can combine values in more complex expressions, using functions, parens, operators such as `+` `-` `*` `/` `!` `===` `==` `>` `!==` `||` `&&`, as well as ternary expressions: `...?...:...`, array and object accessors: `[...]` etc.\\n\\n*Here are some examples of expressions*: \\n\\n```jsr\\n{{if book.author === \\\"Jim Boyd\\\"}}...{{/if}}\\n{{:~utilities.format(book.title, 'upper', true)}}\\n{{for ~sort(~root.getMembers()}}}...{{/for}}\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n{{for #parent.data.members()/}}\\n{{:(~addRebate(book.price) + 23.2)*3.5/2.1}}\\n{{:~mode === \\\"useTitle\\\" ? book.title : book.name}}\\n{{if error}}...{{else !utilities.valid(book.description)}}...{{else}}...{{/if}}\\n{{:~books[id].title}}\\n{{:people[~currentIndex].name}}\\n```\\n\\nExpressions can include white space. The following two examples are equivalent:\\n\\n```jsr\\n{{averageValue product.quantity*3.1/4.5 description=~getDescription(#data) /}}\\n{{averageValue product.quantity * 3.1 / 4.5 description = ~getDescription( #data ) /}}\\n```\\n\\nThe `{{averageValue}}` tag is being assigned one argument, and one named \\\"description\\\" parameter. The two expressions differ only in white space, and both are syntactically valid. However, removing optional white space -– as in the first example -– makes it easier to see the distinct arguments and parameters of the tag.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Chained paths: Stepping through object properties (or functions)\",\r\n \"text\": \"All of the paths above (whether *Data/Helper/View paths*) involve starting from an initial value (a *current data item property/helper/view property*) -- and then, if it is an object, perhaps stepping through one or more chained properties.\\n\\nFor example `team.manager.address.street` starts from a `team` object and steps through the `manager` property -- which is itself a 'person' object with an `address` property, etc. \\n\\n(See also *[Data-linked paths](#linked-paths)*.)\",\r\n \"anchor\": \"paths\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Computed properties\",\r\n \"text\": \"In some cases a property may be of type *function* (possibly taking parameters), so you might have:\\n\\n`team.manager().getAddress('home').street`\\n\\n-- where the manager property is in fact a *'getter'* function which returns a `person` object, which has a `getAddress()` parameterized accessor (taking `'home'` or `'work'` -- or maybe a Boolean `isHomeAddress`). Similarly a path can include an array accessor such as `team.members['id'].address`.\\n\\nProperties of type function -- returning a value -- are referred to as a *computed properties*, or *getter properties*, and
                          \\n`team.manager().getAddress('home').street` is an example of chained computed properties.\\n\\n(See also *[Computed properties and computed observables](#computed)* -- for using computed properties with JsViews and data-linking.)\\n\\nA computed value can also use JavaScript methods, such `toFixed()` to format a number:\\n\\n```jsr\\n{{:price.toFixed(2)}} \\n{{:(+price).toFixed(2)}} \\n```\",\r\n \"anchor\": \"computed\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter properties and computed properties\",\r\n \"text\": \"A common pattern using computed 'getter' functions would be to provide a `person.firstName()` 'getter' property which returns a value: `person._firstName`, considered as 'private'.\\n\\nIn addition, there may be computed properties which depend on other properties, such as a `person.fullName()` which concatenates first and last name.\\n\\nHere is a sample showing both types of computed property:\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Data:*\\n\\n```js\\nfunction firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nvar data = {\\n person: {\\n _firstName: \\\"Jo\\\",\\n _lastName: \\\"Blow\\\",\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n }\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n First name: {{:person.firstName()}}\\n Last name: {{:person.lastName()}}\\n Full name: {{:person.fullName()}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"function firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nvar data = {\\n person: {\\n _firstName: \\\"Jo\\\",\\n _lastName: \\\"Blow\\\",\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n }\\n};\\n\\nvar html = $(\\\"#personTmpl\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"height\": \"72\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Getter properties with plain objects\",\r\n \"anchor\": \"getter-plain-sample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter properties on a View Model\",\r\n \"text\": \"Rather than using plain JavaScript objects with getter functions, as above, a more common pattern (providing better encapsulation) would be to define a *'View Model'* class -- with getter properties defined in the class -- and to instantiate that class to provide data instances.\\n\\n(See *[Plain objects or View Model](#explore/objectsorvm)* for details.)\\n\\nThe following sample uses that approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Data:*\\n\\n```js\\nfunction firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nfunction Person(first, last) {\\n this._firstName = first;\\n this._lastName = last;\\n}\\n\\nPerson.prototype = {\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n};\\n\\nvar data = {\\n person: new Person(\\\"Jo\\\", \\\"Blow\\\")\\n};\\n```\\n\\n*Template:*\\n\\n```jsr\\n First name: {{:person.firstName()}}\\n Last name: {{:person.lastName()}}\\n Full name: {{:person.fullName()}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"72\",\r\n \"code\": \"function firstName() { return this._firstName; }\\nfunction lastName() { return this._lastName; }\\nfunction fullName() { return this._firstName + \\\" \\\" + this._lastName; }\\n\\nfunction Person(first, last) {\\n this._firstName = first;\\n this._lastName = last;\\n}\\n\\nPerson.prototype = {\\n firstName: firstName,\\n lastName: lastName,\\n fullName: fullName\\n};\\n\\nvar data = {\\n person: new Person(\\\"Jo\\\", \\\"Blow\\\")\\n};\\n\\nvar html = $(\\\"#personTmpl\\\").render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"Getter properties with a View Model\",\r\n \"anchor\": \"getter-vm-sample\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"settings/allowcode@security\",\r\n \"label\": \"Expressions and security\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"tmplsyntax\": {\r\n \"title\": \"Template syntax and structure\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following topics provide information on JsRender template syntax:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"tagsyntax\",\r\n \"label\": \"Tag syntax\"\r\n },\r\n {\r\n \"hash\": \"paths\",\r\n \"label\": \"Paths and expressions\"\r\n },\r\n {\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"settings\": {\r\n \"title\": \"Settings\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender provides the following APIs for modifying settings:\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"settings/delimiters\",\r\n \"label\": \"Delimiters\"\r\n },\r\n {\r\n \"hash\": \"settings/debugmode\",\r\n \"label\": \"Debug mode\"\r\n },\r\n {\r\n \"hash\": \"settings/allowcode\",\r\n \"label\": \"Allow code\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"settings/delimiters\": {\r\n \"title\": \"Setting tag delimiters for JsRender\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also *[Setting tag delimiters for JsViews](#jsvsettings/delimiters)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender default tag delimiters\",\r\n \"text\": \"Template tags in JsRender use the Mustache style: `{{...}}`\\n\\n(JsRender also accepts the data-linked tag syntax used in in JsViews: `{^{...}}`). \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Changing delimiters:\",\r\n \"text\": \"Sometimes there can be a need to use different delimiters. For example there may be a conflict if the template is being rendered on the server using a declarative syntax such as *Django* with the same default delimiters `{{` and `}}`.\\n\\nThe following call:\\n\\n```js\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n```\\n\\nwill change the tag syntax to `<%...%>`.\\n\\nThe chosen delimiters must each consist of two non-alphanumeric characters. \\n\\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `[\\\"<%\\\", \\\"%>\\\"]`, which can be useful for reverting to a previous set of delimiters -- as shown in the last sample [below](#settings/delimiters@tmpl-for-tmpl). )\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Verifying current setting for tag delimiters:\",\r\n \"text\": \"```js\\nvar delimiters = $.views.settings.delimiters();\\n// Returns an array [\\\"{{\\\", \\\"}}\\\", \\\"^\\\"] - JsRender tag delimiters (and JsViews link character)\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Markup:* \\n\\n```jsr\\n\\n```\\n\\n*Code*\\n\\n```js\\n$.views.settings.delimiters(\\\"[%\\\", \\\"%]\\\");\\n\\nvar tmpl = $.templates(\\\"#peopleTmpl\\\");\\n...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.views.settings.delimiters(\\\"[%\\\", \\\"%]\\\");\\n\\nvar tmpl = $.templates(\\\"#peopleTmpl\\\");\\n\\nvar team = {\\n title: \\\"A team\\\",\\n members: [{name: \\\"Jo\\\"}]\\n };\\n\\nvar html = tmpl.render(team);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"70\",\r\n \"title\": \"Choosing alternative tag delimiters, with JsRender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using alternative delimiters to 'render a template with a template'\",\r\n \"text\": \"In some scenarios you might want to use a template to generate a template, such as a template on the server to generate/render a template that will then be used in the browser.\\n\\nA good approach to achieving this is to use a different set of delimiters on the server.\\n\\nA similar scenario is to use a 'base' template to render different versions of a template for different languages/localities, as in this example:\\n\",\r\n \"anchor\": \"tmpl-for-tmpl\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n<%:hello%>, {{:name}}
                          \\n<%:welcome%> {{:place}}\\n```\\n\\n```js\\n// Get current delimiters array\\nvar currentDelimiters = $.views.settings.delimiters();\\n\\n// Temporarily switch delimiters\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n\\n// Translate to Spanish localized version\\nvar localizedTemplate = $.templates(\\\"#baseTmpl\\\").render(spanishTerms);\\n\\n// Revert to original delimiters (by passing in previous delimiters array)\\n$.views.settings.delimiters(currentDelimiters);\\n\\n// Render data using localized template\\nhtml = $.templates(localizedTemplate).render(data);\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \\n\",\r\n \"code\": \"var spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Get current delimiters array\\nvar currentDelimiters = $.views.settings.delimiters();\\n\\n// Temporarily switch delimiters\\n$.views.settings.delimiters(\\\"<%\\\", \\\"%>\\\");\\n\\n// Translate to Spanish localized version\\nvar localizedTemplate = $.templates(\\\"#baseTmpl\\\").render(spanishTerms);\\n\\n// Revert to original delimiters (passing in previous delimiters array)\\n$.views.settings.delimiters(currentDelimiters);\\n\\n// Render data using localized template\\nhtml = $.templates(localizedTemplate).render(data);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"54\",\r\n \"title\": \"Template for a template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Incidentally the above scenario of localized terms in a template can be achieved without the 'build step' of creating localized templates, simply by passing in the terms as helpers, distinct from the data itself.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Pass in localized terms as helpers\\nvar html = $.templates(\\\"#tmpl\\\").render(data, spanishTerms );\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \\n\",\r\n \"code\": \"var spanishTerms = {\\n hello: \\\"Hola\\\",\\n welcome: \\\"Bienvenido a\\\"\\n};\\n\\nvar data = {\\n name: \\\"John\\\",\\n place: \\\"Madrid\\\"\\n};\\n\\n// Pass in localized terms as helpers\\nvar html = $.templates(\\\"#tmpl\\\").render(data, spanishTerms );\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"height\": \"54\",\r\n \"title\": \"Passing in terms as helpers\",\r\n \"anchor\": \"passing\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n }\r\n ]\r\n },\r\n \"settings/onerror\": {\r\n \"title\": \"onError\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"settings/dbgmode\": {\r\n \"title\": \"dbgMode\",\r\n \"path\": \"\",\r\n \"sections\": []\r\n },\r\n \"settings/debugmode\": {\r\n \"title\": \"Setting debug mode\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender has a *'debug mode'* setting which determines whether error messages encountered during rendering are displayed.\\n\\n***To get current debug mode:***\\n\\n```js\\nvar isDebugMode = $.views.settings.debugMode(); // false by default\\n```\\n\\n***To set debug mode:***\\n\\n```js\\n$.views.settings.debugMode(...);\\n```\\n\\nDebug mode can be set to any of the following:\\n\\n- `false` -- *errors during rendering will not be rendered* (but an exception will be thrown)\\n- `true` -- no exception will be thrown, but *the error message will be rendered*, in place of the template tag or block\\n- `\\\"some string\\\"` -- no exception. *The string `\\\"some string\\\"` will be rendered* in place of the tag or block\\n- `\\\"\\\"` (empty string) -- no exception. The tag or block will simply be *replaced by the empty string*\\n- a function (to be used as an error handler) -- no exception. The handler will run, and *the error string will be rendered, or else, if the function returns a string, that string will be rendered*\\n\\nSee *[Error handling and debugging](#onerror)* for a full discussion of alternative approaches, together with [details and working examples](#onerror@debugmode) of `$.views.settings.debugMode(...)`.\\n\\n \"\r\n }\r\n ]\r\n },\r\n \"settings/allowcode\": {\r\n \"title\": \"Allow code\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender templates allow you to write [rich expressions](#paths) within the template tags, such as:\\n\\n```jsr\\n{{:person.firstName + ' ' + person.lastName.toUpperCase()}}\\n```\\n\\n\\n\\nNevertheless, in order to improve encapsulation, security and maintainability, they don't allow arbitrary code. For example, they don't allow you to access global variables, like `window`. \\n\\nIf you want complete freedom to insert any code into a compiled template, you can set **allowCode** to *true*, either globally, or specifically for that template. You can then run any code as part of the template rendering, using the [`{{* ...}}`](#allowcodetag) tag, or you can return (render into the template output) the result of evaluating any expression, using the [`{{*: ...}}`](#allowcodetag) tag.\\n\\n(*Note:* it is not recommended to set `allowCode` to true within [data-linked](#jsvlinktmpl) templates -- with JsViews.)\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"User-defined templates and security\",\r\n \"text\": \"For most purposes there is no need to set `allowCode` to true, since the built-in template expressions provide rich functionality which is sufficient for most scenarios.\\n\\nJsRender can be used to render templates either on the server or in the browser -- and is often used for applications which allow users to create their own templates, or to insert markup and expressions into templates. With `allowCode` false, JsRender is designed to *make it impossible for such user-defined templates to run arbitrary code*.\\n\\nUsers can include rich template expressions in the template, but they won't be able to insert code that accesses any variables (or runs any methods) that are outside of the template scope. (They can only access the contextual data/model, use the standard operators, and use any helper methods and variables which the author decides to provide.)\",\r\n \"anchor\": \"security\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode to true, globally\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(true);\\n```\\n(See samples for [`{{* ...}}` and `{{*: ...}}`](#allowcodetag@sample))\\n \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode back to false, globally\",\r\n \"text\": \"```js\\n$.views.settings.allowCode(false);\\n```\\n\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To get current global allowCode setting\",\r\n \"text\": \"```js\\nvar allowCodeIsTrue = $.views.settings.allowCode(); // false by default\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"To set allowCode to true for a specific template\",\r\n \"text\": \"```js\\n$.templates(..., {\\n markup: ...,\\n allowCode: true,\\n ...\\n})\\n```\\n\\n(See `{{* ...}}` and `{{*: ...}}` sample: *[allowCode for template](#allowcodetag@tmpl)*).\"\r\n }\r\n ]\r\n },\r\n \"onerror\": {\r\n \"title\": \"Error handling and debugging\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Sometimes when rendering a JsRender template, a JavaScript error is encountered. For example `{{:address.street}}` in a template will render without error provided there is an `address` property on the current data object. But if there is no `address` property, then *there will be an error*: ***\\\"Cannot read property 'street' of undefined\\\"***.\\n\\nJsRender provides two features which provide powerful control over rendering behavior when errors are encountered.\\n\\n- The optional [`onError=...` property](#onerror@onerror) that can be set on any tag -- for controlling error handling behavior on that specific tag\\n- The [`$.views.settings.debugMode(...)` setting](#onerror@debugmode) -- which provides global control over error handling during rendering\\n\\nIn addition, for advanced debugging of compiled templates, see:\\n\\n- *[Using debugging helpers](#onerror@dbg)*\\n\\n
                          \\n## Specifying onError fallback behavior on a tag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to a string\",\r\n \"text\": \"All JsRender tags (including custom tags) such as `{{address.street}}` or `{{for getItems()}}` allow you to provide a `onError` tag property, with a fallback string to render in the case of errors:\\n\\n```jsr\\n{{:address.street onError=\\\"Address unavailable\\\"}}\\n```\\n\\n```jsr\\n{{for phones() onError=\\\"No phones\\\"}}\\n```\\n\\n```jsr\\n{{myCustomTag ... onError=\\\"\\\"}}\\n```\\n\\nThe `onError` fallback string will be rendered whenever there an error (or exception) is encountered during the tag rendering.\\n\\nSetting to the empty string ensures that errors are simply ignored, and the tag renders as the empty string.\",\r\n \"anchor\": \"onerror\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In this sample, if a `member` object has no `address` property, the `address.street` expression will lead to a JavaScript error, and the `{{:address.street onError=\\\"Address unavailable\\\"}}` will render the fallback string: `\\\"Address unavailable\\\"`.\\n\\nSimilarly, `{{for phones() onError=\\\"...\\\"}}`, if `phones()` produces an error... \\n\\n*Template:*\\n\\n```jsr\\n{{for phones() onError=\\\"No phones\\\"}} ...\\n{{:address.street onError=\\\"Address unavailable\\\"}}\\n```\\n\\n*Code:*\\n\\n```js\\nfunction phones() { if (!this._phones) { throw new Error(\\\"phones() error\\\"); } ... }\\n```\\n\\n*Data:*\\n\\n```js\\nmembers: [\\n {address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"], ...\\n {address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], ... // No address\\n {address: {street: \\\"Main St\\\"}, _phones: undefined, ... // _No phones\\n]\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"markup\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"data\": [],\r\n \"code\": \"function phones() {\\n if (!this._phones) {\\n throw new Error(\\\"phones() error\\\");\\n }\\n return this._phones;\\n}\\n\\nvar team = {\\n members: [\\n {address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"],\\n phones: phones},\\n {address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], // No address\\n phones: phones},\\n {address: {street: \\\"Main St\\\"}, _phones: undefined, // _No phones\\n phones: phones}\\n ]\\n};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"onError=\\\"fallback string...\\\" \",\r\n \"height\": \"164\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to an expression\",\r\n \"text\": \"More specific or powerful behavior can be obtained by setting onError to an expression, such as:\\n\\n```jsr\\n{{:address.street onError=name + \\\" has no address\\\"}}\\n```\\n\\n```jsr\\n{{:address.street onError=~errorMessages(1, name, 'address')}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for phones() onError=name + \\\" has no phones\\\"}} ...\\n```\\n\\n```jsr\\n{{:address.street onError=~errorMessages(1, name, \\\"address\\\")}}\\n```\\n\\n```js\\n$.views.helpers(\\\"errorMessages\\\", function(id, param1, param2) {\\n if (id === 1) { return param1 + \\\" has no \\\" + param2; } ...\\n});\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"function phones() {\\n if (!this._phones) {\\n throw new Error(\\\"phones() error\\\");\\n }\\n return this._phones;\\n}\\n\\nvar team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}, _phones: [\\\"888\\\", \\\"456\\\"],\\n phones: phones},\\n {name: \\\"Jane\\\", address: undefined, _phones: [\\\"987\\\", \\\"111\\\"], // No address\\n phones: phones},\\n {name: \\\"Ava\\\", address: {street: \\\"Main St\\\"}, _phones: undefined, // _No phones\\n phones: phones}\\n ]\\n};\\n\\n$.views.helpers(\\\"errorMessages\\\", function(id, param1, param2) {\\n if (id === 1) {\\n return param1 + \\\" has no \\\" + param2;\\n } \\n});\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"height\": \"210\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"onError=someExpression...\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting onError to a function\",\r\n \"text\": \"If `onError=myOnErrorHandler` is set to a function, then the function will be called when there is an error.\\n\\n- If the function returns a string, then that string will be rendered, replacing the output of the tag\\n- If the function has no return value, then the error message will be rendered\\n\\nFor example, you can provide a `person.error()` error handler method on a person object, and set `onError=error`. Or you can use global helper (or a helper passed to the render function), and set `onError=~myErrorHandler`, such as the following to log the error and display just the empty string:\\n\\n```js\\nfunction myErrorHandler(e, view) {\\n console.log(...); // Log the error \\n return \\\"\\\"; // Display the empty string \\n}\\n```\\n\\nThe parameters of the onError handler function -- `myHandler(e, view)` -- will be:\\n\\n- `e` -- the `error` object\\n- `view` -- the current `view` object\\n- The `this` pointer will be the current data item, `view.data`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:address.street onError=~myOnError}}\\n```\\n```js\\nfunction onErrorHandler(e, view) {\\n console.log(e.message);\\n if (!this.address) {\\n return this.name + \\\" has no address (\\\" + e.message + \\\")\\\";\\n }\\n}\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team, {myOnError: onErrorHandler});\\n```\"\r\n }\r\n ],\r\n \"code\": \"var team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}},\\n {name: \\\"Jane\\\", address: undefined} // No address\\n ]\\n};\\n\\nfunction onErrorHandler(e, view) {\\n console.log(e.message);\\n if (!this.address) {\\n return this.name + \\\" has no address (\\\" + e.message + \\\")\\\";\\n }\\n}\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team, {myOnError: onErrorHandler});\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"height\": \"126\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"onError=~myOnError\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"
                          \\n## Setting debug mode\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `$.views.settings.debugMode(...)` setting provides control of error handling during rendering, similar to the `onError` feature [above](#onerror@onerror), but operating at a global level rather than on individual tags.\\n\\nThese two approaches are complementary and can be used together. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting debug mode to true\",\r\n \"text\": \"- By default *debug mode* is **false** -- and *an exception will be thrown if a JavaScript error is encountered while rendering a tag or template*\\n- If *debug mode* is set to **true** -- any error message encountered while rendering a tag *will replace the rendered content of that tag*\\n\\n***To set debug mode to true:***\\n\\n```js\\n$.views.settings.debugMode(true);\\n```\\n\\n***To set debug mode back to false:***\\n\\n```js\\n$.views.settings.debugMode(false);\\n```\\n\\n***To get current debug mode:***\\n\\n```js\\nvar isDebugMode = $.views.settings.debugMode(); // false by default\\n```\\n\\nIn the following example *debug mode* is set to `true`. The error message is rendered, replacing the rendered tag.\\n\\n(Choose *Try it* and change *debug mode* to `false`, to see the difference.)\\n\",\r\n \"anchor\": \"debugmode\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Code:*\\n\\n```js\\n$.views.settings.debugMode(true);\\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by the error message.\\n\\n```js\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n...\\n```\\n\\n*Template:*\\n\\n```jsr\\n{{for members}}\\n
                          {{:name}} - {{:address.street}}
                          \\n{{/for}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.settings.debugMode(true); \\n// Change to $.views.settings.debugMode(false); - The error\\n// will not be displayed, but an exception will be thrown.\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\",\r\n \"title\": \"Debug mode set to true\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following example also illustrates setting *debug mode* to `true`, but this time it is used with JsViews, and the `link(...)` method, rather than JsRender and `render(...)`.\\n\\nThe error conditions can arise both in expressions within tags, such as `{^{:manager.name}}` and data-link expressions such as `\\n {{if owner}}\\n Owner: {^{:manager.name}}\\n {{/if}}\\n
                          \\nEdit: \\n```\\n\\n*Code:*\\n\\n```js\\n$.views.settings.debugMode(true);\\n// Debug mode is set to true, so error messages are rendered in place of the corresponding tag or data-link expression.\\n\\nvar team = {owner:\\n {name:\\\"Jo\\\"}\\n}; // team.manager is undefined...\\n...\\ntmpl.link(\\\"#result\\\", team); // Error...\\n```\\n\\nIf you choose *Try it* and change to `$.views.settings.debugMode(false);`, the error will instead be thrown as an exception.\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n
                          \\n\\n\\n\\n\",\r\n \"code\": \"$.views.settings.debugMode(true);\\n\\nvar team = {owner:\\n {name:\\\"Jo\\\"}\\n}; // team.manager is undefined...\\n\\nvar tmpl = $.templates(\\\"#teamTmpl\\\");\\n\\ntmpl.link(\\\"#result\\\", {team: team}); // Error...\",\r\n \"height\": \"80\",\r\n \"title\": \"Debug mode set to true – JsViews\",\r\n \"anchor\": \"datalink\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Setting debug mode to a string\",\r\n \"text\": \"By setting debug mode to a string rather than to `true`, no exception will be thrown, and the chosen string will be rendered, replacing the rendered tag. \\n\\n```js\\n$.views.settings.debugMode(\\\"Error!\\\");\\n``` \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.settings.debugMode(\\\"Error!\\\"); \\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is replaced by `\\\"Error!\\\"`.\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"code\": \"$.views.settings.debugMode(\\\"Error!\\\"); // Do not throw exception - render \\\"Error!\\\"\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"title\": \"Debug mode set to a default string\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"In some scenarios the desired behavior may be to ignore errors during rendering, by skipping any tag with an error, rendering it as an empty string. This is achieved very easily, by simply writing:\\n\\n```js\\n$.views.settings.debugMode(\\\"\\\");\\n``` \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n$.views.settings.debugMode(\\\"\\\");\\n```\\n\\nThe `{{:address.street}}` tag for Bill (who has no address) is skipped.\"\r\n }\r\n ],\r\n \"title\": \"Debug mode set to empty string\",\r\n \"code\": \"$.views.settings.debugMode(\\\"\\\"); // Do not throw exception - render \\\"\\\"\\n\\nvar team = {members: [\\n {name:\\\"Jo\\\", address: {street: \\\"1st Ave\\\"}},\\n {name:\\\"Bill\\\"}, // Bill does not have an address!!\\n {name:\\\"Ava\\\", address: {street: \\\"Main St\\\"}}\\n]};\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"74\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a debug mode handler (function)\",\r\n \"text\": \"If debug mode is set to a function, the function will be called each time an error is encountered during rendering. \\n\\n- If the function returns a string, then that string will be rendered, replacing the rendered tag\\n- If the function has no return value, then the error message will be rendered\\n\\n```js\\n$.views.settings.debugMode(myOnErrorHandler);\\n\\nfunction myOnErrorHandler(e, fallback, view) {\\n // This handler will log the error, and then display the empty string\\n console.log(...);\\n return \\\"\\\"; \\n}\\n```\\n\\nThe parameters of the debug mode error handler function -- `myHandler(e, fallback, view)` -- will be:\\n\\n- `e` -- the error object\\n- `fallback` -- the fallback error string, provided by the *[onError fallback](#onerror@onerror)* specified on the tag, if there is one\\n- `view` -- the current view object\\n- The `this` pointer will be the current data item, `view.data`\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{:address.street onError='address'}}\\n```\\n\\n```js\\nfunction onErrorHandler(e, fallback, view) {\\n console.log(e.message);\\n if (fallback === \\\"address\\\") {\\n return 'Address error for ' + this.name + '. (\\\"' + e.message + '\\\")';\\n }\\n}\\n```\\n\\n```js\\n$.views.settings.debugMode(onErrorHandler);\\n```\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\\n\",\r\n \"code\": \"var team = {\\n members: [\\n {name: \\\"Bill\\\", address: {street: \\\"1st Ave\\\"}},\\n {name: \\\"Jane\\\", address: undefined} // No address\\n ]\\n};\\n\\nfunction onErrorHandler(e, fallback, view) {\\n console.log(e.message);\\n if (fallback === \\\"address\\\") {\\n return 'Address error for ' + this.name + '. (\\\"' + e.message + '\\\")';\\n }\\n}\\n\\n$.views.settings.debugMode(onErrorHandler);\\n\\nvar html = $(\\\"#teamTmpl\\\").render(team);\\n\\n$(\\\"#result\\\").html(html);\\n\",\r\n \"title\": \"Debug mode – onError handler\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"116\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advanced debugging, using debugging helpers\",\r\n \"text\": \"***Inserting breakpoints during rendering:***\\n\\nJsRender (and JsViews) provide some helpers for debugging code within compiled templates:\\n\\n- The `{{dbg expression/}}` tag\\n- The `{{dbg: expression}}` converter\\n- The `~dbg(expression)` helper function\\n\\nEach of the above will\\n- evaluate the expression\\n- output a `console.log(...)` call\\n- throw and catch an exception -- which you can use as a break point by *stopping on caught exceptions*\\n- render the evaluated expression\\n\\nThis is done by inserting code into the compiled template which calls into the built-in *dbgBreak* code:\\n\\n```js\\nfunction dbgBreak(val) {\\n try {\\n console.log(\\\"JsRender dbg breakpoint: \\\" + val);\\n throw \\\"dbg breakpoint\\\"; // To break here, stop on caught exceptions.\\n }\\n catch (e) {}\\n```\\n\\n`val` will be the result of evaluating `expression`.\\n\\nWhen rendering execution breaks at the above code, you can then step up through the call stack to the compiled template code, for further debugging.\\n\\nUsage examples: `{{dbg:...}}`, `{{:~dbg(...)}}`, `{{dbg .../}}` etc.\\n\\n***Breakpoints during data linking:***\\n\\nIn JsViews, a breakpoint can also be inserted during template data-linking, as in `{^{for ... onAfterLink=~dbg}}`.\\n\\n___Using {{*debugger}}:___\\n\\nAn alternative (but similar) debugging technique is to use `allowCode` to insert a `debugger;` statement directly into the compiled template code, as follows:\\n\\n*Code:*\\n\\n```js\\nvar tmpl = $.templates({\\n markup: \\\"#myTmpl\\\",\\n allowCode: true // Alternatively use global setting: $.views.settings.allowCode(true)\\n});\\n```\\n\\n*Template:*\\n\\n```jsr\\n...\\n{{*debugger}}\\n...\\n```\",\r\n \"anchor\": \"dbg\"\r\n }\r\n ]\r\n },\r\n \"advanced\": {\r\n \"title\": \"JsRender – advanced topics\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"onerror\",\r\n \"label\": \"Error handling\"\r\n },\r\n {\r\n \"hash\": \"settings/advanced\",\r\n \"label\": \"Advanced settings\"\r\n },\r\n {\r\n \"hash\": \"jsrobjects\",\r\n \"label\": \"JsRender objects\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"apps\": {\r\n \"title\": \"Building apps\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Apps using JsRender\",\r\n \"text\": \"*JsRender* is a simple light-weight templating engine. It can be used in the browser within simple web pages, or within complex single-page apps, or in conjunction with other frameworks. It can also be used on the server, using *Node.js*.\\n\\nIt is highly flexible, expressive, and 'unopinionated' -- so it leaves you free to work within your own choice of overall application architecture (including architectures based on *MVVM*, *MVP* or *MVC* -- optionally with server/client integration), and lets you use your own flavor of data/model layer -- whether simple plain JavaScript objects, hand-coded *View Model* instances, or *[compiled View Models](#viewmodelsapi)*.\\n\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Components of an app using JsRender\",\r\n \"text\": \"Any app or web page using JsRender templates will generally involve defining or registering the following elements:\\n\\n- one or more **templates** -- see *[Templates](#compiletmpl)*\\n- a **'data Layer'** -- see *[JsRender: Data or View Model](#jsrmodel)*\\n- optionally, **helpers** -- in the form of metadata, helper functions and converter functions, see *[Helpers](#helpers)* and *[Converters](#converters)*\\n- optionally, **reusable components** for use within your templates -- see *[Custom tags](#tags)*\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Apps using JsViews\",\r\n \"text\": \"*JsRender* also provides optional integration with *JsViews*. *JsViews* is much more of a framework than *JsRender*. It does much more than just templating -- providing also data-binding, *MVVM* support, observability of the *data/View Model* layer, support for interactive encapsulated components (*JsViews tag controls*), and more. Nevertheless, it can also interoperate with other frameworks and components. See *[Building apps in JsViews](#jsvapps)* for more information.\"\r\n }\r\n ]\r\n },\r\n \"getindex\": {\r\n \"title\": \"Iterating over arrays: accessing the array index\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"If you pass an array to the JsRender [`.render(myArray)`](#rendertmpl) method, or if you use [`{{for myArray}}`](#propstag), in a template, JsRender will iterate over the array, and render an [*item view*](#views@itemview) for each item in the array.\\n\\nWithin an item view you can access the array-index of the current item, using `{{:#index}}`:\\n\\n- *Getting item index within a top-level item view (from `.render(myArray)`)*:\\n\\n ```jsr\\n ...\\n {{:#index}}\\n ...\\n ```\\n\\n- *Getting item index within a `{{for myArray}}` block*:\\n\\n ```jsr\\n {{for myArray}}\\n ...\\n {{:#index}}\\n ...\\n {{/for}}\\n ```\\n\\nIf there are additional nested tags, then from within the nested tags you can still access the index, by using `{{:#getIndex()}}`:\\n\\n- *Getting item index from nested tags within an item view*:\\n\\n ```jsr\\n {{for myArray}}\\n ...\\n {{if ...}}\\n ...\\n {{:#getIndex()}}\\n ...\\n {{/if}}\\n ...\\n {{/for}}\\n ```\\n\\nSee [`index`](#viewobject@index) and [`getIndex()`](#viewobject@getIndex) for additional details.\\n\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"contextualparams\": {\r\n \"title\": \"Contextual parameters\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Defining contextual parameters\",\r\n \"text\": \"*Contextual parameters* provide a very convenient way of passing values in to nested tag contexts. (See *[View hierarchy](#views)*.)\\n\\nA contextual parameter is defined by simply writing `~myValue=...` (for any expression) on any block tag, such as `{{if}}` or `{{for}}`.\\n\\nThe resulting `~myValue` parameter can then be accessed within the block tag -- or deeper down within nested tag contexts, at any depth. \\n\\nFor example, the following template defines three contextual parameters, and uses them in nested contexts:\\n\\n```jsr\\n...\\n{{if isActive ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\\n {{for members}}\\n {{if ~teamIndex>2}}\\n {{:~teamTitle}} {{:~teamData.description}}\\n ...\\n```\\n\\n*Note:* You can also set contextual parameters on `{{else}}` blocks, such as in the following example which uses the same template for the `{{if}}` and `{{else}}` blocks, but assigns different values to the `~teamTitle` parameter in each case:\\n\\n```jsr\\n{{if isActive ~teamTitle=activeTitle tmpl=\\\"teamTmpl\\\"}}\\n{{else ~teamTitle=inactiveTitle tmpl=\\\"teamTmpl\\\"}}\\n{{/if}}\\n```\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"itemVar – contextual parameter for data 'item' of block\",\r\n \"text\": \"The *itemVar* feature lets you set up a contextual parameter for the current data 'item' of a block. It is in effect an 'alias' for `#data` within the block.\\n\\nTo define an *itemVar* contextual parameter for a block tag, simply write `itemVar=~someName`. The parameter `~someName` can then be accessed like any other helper variable or contextual parameter, within nested contexts to any depth.\\n\\n```jsr\\n...\\n{{for teams itemVar=\\\"~team\\\"}}\\n ...\\n {{for members itemVar=\\\"~member\\\"}}\\n ...\\n {{if isActive}}\\n {{:~team.title}} {{:~member.name}}\\n```\\n\\nSee also [this sample](#fortag@itemvar).\",\r\n \"anchor\": \"itemvar\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing root data: the built-in '~root' contextual parameter\",\r\n \"text\": \"The built-in contextual parameter `~root` provides direct access to the *root data* which was passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews). It can be accessed from anywhere within a template, at an level of nested tags.\\n\\n*Note:* If an array is passed to `render()` or `link()` then `~root` will be the array (so you can render `{{:root.length}}` for example).\",\r\n \"anchor\": \"root\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsapi@ctxparams\",\r\n \"label\": \"Accessing contextual parameters and helpers\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"parentdata\": {\r\n \"title\": \"Accessing parent data\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing \\\"parent\\\" data, from nested views. Passing in template variables\",\r\n \"text\": \"When a template (containing nested template tags) is rendered, the result is a [view hierarchy](#views) -- where the views provide information on how the underlying data objects map to the rendered UI.\\n\\nOften it is helpful to be able to access the data for a *parent view* from a [*nested* template](#views@nestedtmpl) or [block](#tagsyntax@blocktag) (*nested view*).\\n\\nThere are several ways to get to *parent data*:\\n\\n- Create a *[contextual parameter](#contextualparams)* to pass a value to nested views.\\n\\n Here are three examples:\\n\\n ```jsr\\n ...\\n {{if ... ~teamTitle=title ~teamData=#data ~teamIndex=#index}}\\n ...\\n {{for ...}}\\n ...\\n {{:~teamTitle}} {{:~teamData.title}} {{:~teamIndex}}\\n ```\\n\\n- Use [`itemVar`](#contextualparams@itemvar) to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \\n\\n ```jsr\\n ...\\n {{for members itemVar=\\\"~member\\\"}}\\n ...\\n {{props}}\\n ...\\n {{:~member.name}}\\n ```\\n\\n- Use the [`view.parent`](#viewobject@parent) property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\\n\\n ```jsr\\n ...\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#parent.parent.data.title}}\\n ```\\n\\n- Use the [`view.get(type)`](#viewobject@get) method to get to a parent view of a given `type`:\\n\\n ```jsr\\n ...\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#get(\\\"if\\\").data.title}}\\n\\n ```\\n\\n- Use the [`view.getIndex()`](#viewobject@getIndex) method to get to the index of a parent *\\\"item\\\"* view:\\n\\n ```jsr\\n {{if ...}}\\n ...\\n {{for ...}}\\n ...\\n {{:#parent.getIndex()}}\\n {{:#getIndex()}}\\n ```\\n\\nHere is a sample showing all of these methods:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This sample shows all the ways to get to *parent data* described in the section above:\\n\\n- Create a *contextual parameter* to pass a value to nested views.
                          \\n- Use `itemVar` to provide a contextual parameter for the current data 'item' of a block, to be passed in to deeper nested contexts \\n- Use the `view.parent` property to step up through successive parent views (`#parent`, `#parent.parent` etc.):\\n- Use the `view.get(type)` method to get to a parent view of a given `type`:\\n- Use the `view.getIndex()` method to get to the index of a parent *\\\"item\\\"* view:\\n\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \",\r\n \"code\": \"// mytag: custom tag to output \\\"1 member\\\" or \\\"n members\\\"\\n$.views.tags(\\\"mytag\\\", \\\"{{:length == 1 ? '1 member' : length + ' members'}}
                          \\\");\\n// Alternative version of mytag:\\n// $.views.tags(\\\"mytag\\\", \\\"{{if length == 1}}1 member{{else}}{{:length}} members{{/if}}
                          \\\");\\n\\nvar teams = [\\n {title: \\\"The A Team\\\", members: [{name: \\\"Jeff\\\"}, {name: \\\"Maria\\\"}]},\\n {title: \\\"The B Team\\\", members: [{name: \\\"Francis\\\"}]}\\n];\\n\\nvar html = $(\\\"#teamTemplate\\\").render(teams);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"290\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"views\",\r\n \"label\": \"View hierarchy\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"jsrmodel\": {\r\n \"title\": \"JsRender: Data / View Model\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsRender* is designed to work well with either plain JavaScript objects and arrays, or with instances of JavaScript classes, such as *View Model* classes.\\n\\nSo, for example, if you are using data obtained from a JSON request, you can choose between:\\n- rendering your templates directly against the objects and arrays returned from the JSON request\\n- passing the data through a 'mapping' process to create a hierarchy of *View Model* instances, and rendering your templates against those objects\\n\\nThe *plain objects* [approach](#jsrmodel@plain) is convenient and simple for getting rapidly up and running with templates. But for more complex projects the *View Model* approach is better for creating clean well-designed modular code, where each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using JsRender built-in compiled View Models\",\r\n \"text\": \"*JsRender* will work well with your own 'hand-coded' *View Model* classes (see [below](#jsrmodel@vm)).\\n\\nBut in most cases it is simpler and better to use the [`$.views.viewModels(...)`](#jsrmodel@compilevm) API. This API lets you very easily and rapidly compile *View Model* classes for your own needs, following a standard pattern, and with some additional powerful features:\\n\\n- It provides a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\\n- It also provides a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Data / View Model with JsViews\",\r\n \"text\": \"All of the alternatives mentioned above (plain object hierarchies, hand-coded *View Model* classes, or JsRender *compiled View Model* classes) can also be used with *JsViews* data-binding and observable data. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: JsRender with plain objects and arrays\",\r\n \"text\": \" \"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Suppose this is our data from a JSON request:\",\r\n \"code\": \"var person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n\"\r\n },\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"We'll render using a template structured like this:\",\r\n \"markup\": \"... \\n{{:name}}\\n...\\n{{:address.street}}\\n...\\n{{for phones}}\\n ... \\n {{:number}}\\n ...\\n{{/for}}\\n...\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person (plain object)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Data: hierarchy of plain objects and arrays\\nvar person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n\\n// Render template against plain object hierarchy\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n\",\r\n \"height\": \"140\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template directly against plain objects...\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Now we'll convert the above sample to use *View Model* classes.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: JsRender with 'hand-coded' View Model objects\",\r\n \"text\": \"We'll convert the data to a corresponding hierarchy of simple 'hand-coded' *View Model* class instances. In each case we will replace properties by simple *getters*, and corresponding 'private' properties. \",\r\n \"anchor\": \"vm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model classes:\",\r\n \"text\": \"Here is the class definition for Person:\\n\\n```js\\n// Constructor\\nfunction Person(name, address, phones) {\\n // Initialize private properties\\n this._name = name;\\n this._address = address;\\n this._phones = phones;\\n}\\n\\n// Prototype\\nvar personProto = {\\n // Define a getter for each property \\n name: function() {\\n return this._name;\\n },\\n address: function() {\\n return this._address;\\n },\\n phones: function() {\\n return this._phones;\\n }\\n};\\n...\\n```\\n\\nWe define exactly similar classes for our Address and Phone objects too.\\n\\nThe above pattern for *View Model* classes will work well with *JsRender*. (It will also work seamlessly with *JsViews* data-binding, if at some point you choose to upgrade to use *JsViews* features).\\n\\n*Note:* The standard JsRender *View Model* pattern provided by `$.views.viewModels` is similar, but provides also setters (along with optional *'observability'* for two-way binding in *JsViews*).\",\r\n \"anchor\": \"handvm\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Getter functions\",\r\n \"text\": \"Note that properties are now getter functions, which return the appropriate value (which may be of any type, including objects or arrays -- such as `address` and `phones` above).\\n\\nIn fact they are particular case of *[computed properties](#paths@computed)* -- a concept that can be used quite generally within *JsRender* and *JsViews*, not only for *View Model* properties.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Template\",\r\n \"text\": \"To convert our template from using plain objects to using *View Model* objects, the only change we need to make is to add parens for our properties, which are now getter functions:\\n\\n```jsr\\n... \\n{{:name()}}\\n...\\n{{:address().street()}}\\n...\\n{{for phones()}}\\n ... \\n {{:number()}}\\n ...\\n{{/for}}\\n...\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Instantiate and render:\",\r\n \"text\": \"Now all we need to do is to construct our root `person` object (with its underlying hierarchy of *View Model* instance objects) and render the template against that object in the usual way.\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [\r\n {\r\n \"_type\": \"codetab\",\r\n \"name\": \"\",\r\n \"url\": \"samples/mvvm/person-view-models-jsr.js\",\r\n \"label\": \"person-view-models-jsr.js\"\r\n }\r\n ],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n... {{:name()}} ...\\n```\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy\",\r\n \"code\": \"// Use previously defined View Model classes: Person, Address, Phone\\nvar person = new Person(\\n \\\"Pete\\\",\\n new Address(\\n \\\"1st Ave\\\"),\\n [\\n new Phone(\\\"111 111 1111\\\"),\\n new Phone(\\\"222 222 2222\\\")\\n ]\\n );\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Instantiate View Model hierarchy\\nvar person = new Person(\\n \\\"Pete\\\",\\n new Address(\\\"1st Ave\\\"),\\n [\\n new Phone(\\\"111 111 1111\\\"),\\n new Phone(\\\"222 222 2222\\\")\\n ]\\n );\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\",\r\n \"height\": \"140\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template against a View Model object hierarchy\",\r\n \"anchor\": \"vmsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using the same function as both getter and setter\",\r\n \"text\": \"For properties which are read-write, the above *getter* functions can be replaced by a corresponding *getter/setter*, as follows: \\n\\n```js\\nname: function(val) {\\n if (!arguments.length) {\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is a value argument, treat as a setter\\n},\\n```\\n\\nNote that when *JsRender* renders a template using a *get/set* property `{{:name()}}` it will *always call the function as a getter, not as a setter*. However the *setter* feature lets you modify the value of `name()` from code, using:\\n\\n```js\\nsomePerson.name(\\\"newName\\\"); // setter\\n```\\n\\nAlso, if you use the same *View Model* class with *JsViews* then the *setter* will be called:\\n\\n- when the user modifies a value with two-way data-binding such as ``\\n- when using `$.observable(person).setProperty(\\\"name\\\", \\\"newName\\\")` from code
                          \\n(See [JsViews Data/View Model](#jsvmodel) for details, and alternative *setter* patterns.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding methods and computed properties to the View Model \",\r\n \"text\": \"Typically a *View Model* does not only provide *getter* (or *get/set*) properties -- but also other methods or computed properties corresponding to the appropriate logic at that point in the application. For example, a *View Model* for a *Person* might include a `selectPhone(...)` method or a `fullName()` computed property.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: Using JsRender compiled View Models, with $.view.viewModels(...)\",\r\n \"text\": \"The built-in support in both *JsRender* and *JsViews* for compiled *View Models* makes it extremely easy to define *View Model* classes that include *get/set* properties using the pattern described above, along with any desired additional methods and computed properties. Simple calls to `$.views.viewModels(...)` allow you to compile *View Model* classes conforming to these patterns without having to manually write repetitive code for multiple such *get/set* properties.\\n \\nAnother advantage of the compiled *View Model* classes is when working with (or migrating to) *JsViews*. In that context the classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates.\\n\\nFor details on `$.views.viewModels` see: *[Compiled View Models](#viewmodelsapi)*.\\n\\nTo illustrate, let's convert our [sample above](#jsrmodel@vm) to use compiled *View Models*. At the same time we will add a `person.addPhone(...)` custom method to the `Person` *View Model* class, and we'll illustrate calling a setter -- `name(...)`:\",\r\n \"anchor\": \"compilevm\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name()}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"], // get/set properties\\n extend: {addPhone: addPhone} // Additional methods or properties\\n});\\n...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy using constructors\",\r\n \"code\": \"var person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Call setter, call method...\",\r\n \"code\": \"...\\nperson.name(\\\"newName\\\"); // Use the name(...) setter\\n\\n...\\nperson.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n\\n
                          \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(Phone(phoneNo));\\n}\\n\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"],\\n extend: {addPhone: addPhone}\\n});\\n\\n// Compile Address View Model\\nvar Address = $.views.viewModels({getters: [\\\"street\\\"]});\\n\\n// Compile Phone View Model\\nvar Phone = $.views.viewModels({getters: [\\\"number\\\"]});\\n\\n// Instantiate View Model hierarchy using constructors\\nvar person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\",\r\n \"height\": \"190\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Render template against a hierarchy of compiled View Model objects\",\r\n \"anchor\": \"compilevmsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See also the [corresponding sample](#jsvviewmodelsapi@compilevmsample) with JsViews and data-linking (and [this version](#jsvmodel@compilevmsample) with two-way binding).\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"For additional details and scenarios for compiled View Models, see:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"viewmodelsapi\",\r\n \"label\": \"Compiled View Models\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsv-model\",\r\n \"label\": \"JsViews: Data/View Model\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"computed\",\r\n \"label\": \"Computed Observables\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"helpersapi\": {\r\n \"title\": \"Registering helpers: $.views.helpers()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.views.helpers()` is used to register helpers, accessed within templates using the syntax `~myhelper`. See *[Using helpers](#helpers)* for information about what *helpers* are, and some additional ways of providing them to templates.\\n\\nThis topic provides more details.\\n\\nWith `$.views.helpers(...)` you can:\\n- register one or more helpers globally, to be used in any template\\n- add one or more helpers as [private resources](#helpersapi@private) for a parent template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering one or more helpers\",\r\n \"text\": \"\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.helpers(...)\",\r\n \"name\": \"helpers\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of helper - to be used in template path expressions as ~name...\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"helper\",\r\n \"type\": \"any type\",\r\n \"optional\": false,\r\n \"description\": \"the helper - a function, object, or value\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers(\\\"format\\\", myFormatFunction);\",\r\n \"description\": \"Register a helper, for use in any template with the syntax:
                          ~name\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedHelpers\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of helper) and values (function, object, or value)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers({\\n format: myFormatFunction,\\n utilities: {},\\n mode: \\\"filtered\\\"\\n});\",\r\n \"description\": \"Register multiple helpers\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example using a 'hierarchy' of helpers...\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an example using a 'hierarchy' of helpers...\\n\\n```js\\n$.views.helpers({\\n ...\\n utilities: {\\n maxCount: 23,\\n subtractMax: function(val) {\\n return val - this.maxCount;\\n },\\n errorMessages: {\\n msg1: \\\"not available\\\"\\n }\\n },\\n ...\\n});\\n```\\n\\n```jsr\\n{{:~utilities.subtractMax(sold) > 0\\n ? ~utilities.errorMessages.msg1\\n : \\\"immediate\\\"\\n}}\\n```\"\r\n }\r\n ],\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\n$.views.helpers({\\n format: myFormatFunction,\\n utilities: {\\n maxCount: 23,\\n subtractMax: function(val) {\\n return val - this.maxCount;\\n },\\n errorMessages: {\\n msg1: \\\"not available\\\"\\n }\\n },\\n mode: \\\"filtered\\\"\\n});\\n\\nvar html = $(\\\"#myTemplate\\\").render({title: \\\"gizmo\\\", sold: 27});\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"title\": \"Register multiple helpers, including objects, etc.\",\r\n \"height\": \"40\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding helpers as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.helpers(...)`.\\n\\nIn that way the helper you are registering becomes a 'private helper resource' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"private\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.helpers(namedHelpers[, parentTemplate])\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedHelpers\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of helper) and values (function, object, or value)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these helper(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.helpers({\\n format: myFormatFunction,\\n ...\\n}, parentTemplate);\",\r\n \"description\": \"Add one or more helpers as private resources for a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"helpers\",\r\n \"label\": \"Using helpers\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/helpers\",\r\n \"label\": \"Sample: Passing helpers to template.render()\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"helpers\": {\r\n \"title\": \"Using helpers\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also *[Registering helpers](#helpersapi): The `$.views.helpers()` API*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What are helpers?\",\r\n \"text\": \"JsRender templates are made up of HTML markup, text, and *template tags*. *Template tags* are used to evaluate data-paths or computed expressions, and insert those values into the rendered output.\\n\\nBut often the values you will want to insert are not actually taken from the data, but rather from other parameters or *metadata* which you want to use. And often you will want to process the values, using helper functions or other code, e.g. for converting values to other formats, or for computed values.\\n\\n*Helpers*, in JsRender, refers to any functions, objects, parameters or metadata which you want to provide, in addition to the actual data you passed to the [`render()`](#rendertmpl) method (or [`link()`](#jsvlinktmpl) method if you are using JsViews).\\n\\nHelpers can also be objects, arrays, etc.\\n\\nYou access helpers by prepending the `~` character. Here are some examples:\\n\\n```jsr\\n{{:~myHelperValue}}\\n{{:~myHelperFunction(name, title)}}\\n{{for ~myHelperObject.mySortFunction(people, \\\"increasing\\\")}} ... {{/for}}\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Passing in helpers\",\r\n \"text\": \"There are three ways to provide helpers:\\n\\n- Global helpers -- registered using [`$.views.helpers(myHelpers)`](#helpersapi)\\n- Helpers registered for a specific template -- [`$.templates(\\\"mytmpl\\\", {markup: ..., helpers: myHelpers}`](#d.templates@resources)\\n- Helpers passed in on a specific render call -- [`tmpl.render(data, myHelpers)`](#tmplrender@helpers)
                          \\n(Similarly you can [pass helpers](#jsvhelpers-converters) to JsViews `link()` calls)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Contextual parameters\",\r\n \"text\": \"In addition to providing helpers as above, you can also define *[contextual parameters](#contextualparams)* within a template, which you access using the same `~someName` syntax as for regular helpers. \"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.views.helpers(myHelpers);\\n```\\n\\n```jsr\\n{{:~format(name, true)}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Global helper: $.views.helpers(...)\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.views.helpers(myHelpers);\\n\\nvar html = $(\\\"#personTemplate\\\").render({name: \\\"Robert\\\"});\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.templates({\\n mytmpl: {\\n markup: \\\"#personTemplate\\\",\\n helpers: myHelpers\\n }\\n});\\n```\\n\\n```jsr\\n{{:~format(name)}}\\n{{:~format(name, true)}}\\n```\"\r\n }\r\n ],\r\n \"title\": \"Helper resource for a specific template\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\n$.templates({\\n mytmpl: {\\n markup: \\\"#personTemplate\\\",\\n helpers: myHelpers\\n }\\n});\\n\\nvar html = $.render.mytmpl({name: \\\"Robert\\\"});\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\nvar myHelpers = {format: myFormatFunction};\\n\\nvar html = $(\\\"#personTemplate\\\").render(data, myHelpers); \\n```\\n\\n```jsr\\n{{:~format(name, true)}}\\n{{:~format(name)}}\\n```\\n\\nSee [`template.render(...)`](#rendertmpl)\"\r\n }\r\n ],\r\n \"title\": \"Passing helpers with a render() call\",\r\n \"code\": \"function myFormatFunction(value, upper) {\\n return upper ? value.toUpperCase() : value.toLowerCase();\\n}\\n\\nvar data = {name: \\\"Robert\\\"};\\n\\nvar myHelpers = {format: myFormatFunction};\\n\\nvar html = $(\\\"#personTemplate\\\").render(data, myHelpers); \\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"40\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"text\": \"[Registering helpers](#helpersapi): The `$.views.helpers()` API\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"rendertmpl\",\r\n \"label\": \"Render a template\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/helpers\",\r\n \"label\": \"Sample: Passing helpers to template.render()\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"settings/delimiters@passing\",\r\n \"label\": \"Sample: Passing in terms as helpers\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"convertersapi\": {\r\n \"title\": \"Registering converters: $.views.converters()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"See *[Using converters](#converters)* for an overview of what *converters* are, and some examples.\\n\\nThis topic provided more details.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using custom or built-in converters\",\r\n \"text\": \"In JsRender, a converter is a convenient way of processing or formatting a data-value, or the result of expression evaluation.\\n\\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \\n\\n```jsr\\n{{html:movie.description}} - This data is HTML encoded\\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\\n\\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\\n```\\n\\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\\n\\n```jsr\\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \\n{{upper:name}} - This uses my 'upper' converter \\n```\\n\\n(See: [sample](#converters@simple).)\\n\\nYou can also use converters with any JsRender tag, not just the `{{: ...}}` tag, using the following syntax:\\n\\n```jsr\\n{{sometag convert='myconverter' ...}}\\n```\\n\\n(See: [sample](#converters@fortag).)\\n\\n***Note:*** With JsViews, you can use converters with two-way data-binding, and you will have a convert and a convertBack converter -- one for each direction.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering converters\",\r\n \"text\": \"`$.views.converters()` is used to register converters.\\n\\nWith `$.views.converters(...)` you can:\\n- register one or more converters globally, to be used in any template\\n- add one or more converters as [private resources](#convertersapi@private) for a parent template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering one or more converters\",\r\n \"text\": \"A simple sample of registering a converter is shown [here](#converters@simple).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.converters(...)\",\r\n \"name\": \"converters\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of converter - to be used in template markup: {{name: ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"converterFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Converter function. Takes val parameter and returns converted value\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n\\n{{upper: \\\"upper case: \\\" + nickname}}\",\r\n \"description\": \"Register a converter\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedConverters\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of converter) and values (converter functions)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters({\\n upper: function(val) {...},\\n lower: function(val) {...}\\n});\",\r\n \"description\": \"Register multiple converters\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding converters as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.converters(...)`.\\n\\nIn that way the converter you are registering becomes a 'private converter resource' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"private\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.converters(...) — adding to parent template\",\r\n \"name\": \"converters\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of converter - to be used in template markup: {{name: ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"converterFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Converter function. Takes val parameter and returns converted value (See API: function converterFn below for details)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this converter is being added as private resource\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters(\\n \\\"upper\\\",\\n function(val) { ... },\\n parentTemplate\\n);\",\r\n \"description\": \"Register a converter as private resources for a parent template\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedConverters\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of converter) and values (converter functions)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template - to which this/these converter(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.converters({\\n upper: function(val) {...},\\n lower: function(val) {...}\\n}, parentTemplate);\",\r\n \"description\": \"Add one or more converters as private resources for a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregister a named converter\",\r\n \"text\": \"To unregister a previously registered converter, pass `null` to `$.views.converters()`:\\n\\n```js\\n$.views.converters(\\\"myCvt\\\", null);\\n// Named converter \\\"myCvt\\\" is no longer registered\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter functions\",\r\n \"text\": \"In most cases a converter function will return a computed value based on the input parameter `val`:\\n\\n```js\\nfunction myConverter(val) {\\n ... \\n return computedVal; // converted/encoded/formatted value for 'val'\\n}\\n```\\n\\nwhere `val` comes from the data value or expression passed to the tag `{{myconverter: someExpression}}`. \\n\\n(See: [sample](#converters@simple).)\\n\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter function signature\",\r\n \"text\": \"However a converter can access multiple [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag. (See for example `{{fullname: first last ...}}`, in the [fullname sample](#converters@fullname).)\\n\\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag properties](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\\n\\n```js\\nfunction myConverter(arg1, arg2, arg3 ...) {\\n var tag = this;\\n var namedTagParameters = tag.tagCtx.props; \\n ...\\n return computedArg1; // converted value for 'arg1' passed to tag\\n}\\n```\\n\\nHere is the *converterFn* API definition:\",\r\n \"anchor\": \"signature\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"function converterFn(val, ...) {...}\",\r\n \"name\": \"\",\r\n \"object\": \"\",\r\n \"method\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"val1\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"first tag argument\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"val2\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"additional tag arguments\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"function myConverterFn(val1, val2, ...) {\\n var tag = this;\\n var tagProperties = tag.tagCtx.props;\\n ...\\n return ...;\\n}\\n\\n$.views.converters(\\\"myconverter\\\", myConverterFn);\",\r\n \"description\": \"Converter function:
                          • parameters: one or more tag arguments
                          • this pointer: the tag instance
                          • computes return value: which is passed to tag as first argument
                          \"\r\n }\r\n ],\r\n \"description\": \"A converter function registered using $.views.converters(...)\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using converters with other tags\",\r\n \"text\": \"A converter can be used on any tag, thanks to the syntax\\n\\n```jsr\\n{{sometag ... convert=...}}\\n```\\n\\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}` or `{{for}}`.\\n\\nSee the [sample](#converters@fortag) using `{{for people convert='extraItems'}}`, where the converter adds additional items to the array. \\n\\n(***Note:*** This syntax can actually be used with the `{{: ...}}` tag too -- by writing `{{:name convert='upper'}}`...)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example: a converter for {{if}}\",\r\n \"text\": \"Here is an advanced sample: an `\\\"inlist\\\"` converter for `{{if}}`.\\n\\n- It accepts an `item` argument and a `list` argument, and an optional `field` *named property*\\n- It returns `true` if the `item` is found in the `list`\\n- If there is a `field` specified, it takes the value of that field (property) on the `item` and searches for it in the `list`\\n\\nNote that the converter gets called once for the first `{{if}}` tag block and once for each subsequent `{{else}}` block.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{for people}}\\n ...\\n {{if #data ~root.team convert='inlist'}}\\n ...\\n {{else #data ~root.reserve field=\\\"name\\\"}}\\n ...\\n {{else}}\\n ...\\n{{/for}}\\n```\\n\\n```js\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}.\\n ... // Return true\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n ... // Return true if found\\n\\n // If no field property, look for the item among the list items\\n ... // Return true if found\\n\\n return false; // Not found\\n}\\n\\n// Register 'inlist' converter just for the 'teamTmpl' template \\n$.views.converters({inlist: inlistConverter}, teamTmpl);\\n```\"\r\n }\r\n ],\r\n \"title\": \"'inlist' converter for {{if}} tag\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var teamTmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}\\n if (!list) {\\n return true; // Final else, so return true\\n }\\n\\n var field = this.tagCtx.props.field;\\n var l = list.length;\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n if (field) {\\n while (l--) {\\n if (item[field] === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n\\n // If no field property, look for the item among the list items\\n else {\\n while (l--) {\\n if (item === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n return false; // Not found\\n}\\n\\n// Register 'inlist' converter just for the 'teamTmpl' template \\n$.views.converters({inlist: inlistConverter}, teamTmpl);\\n\\n// Define model \\nvar model= {people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Liza\\\"},\\n {name: \\\"Eli\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Zoey\\\"}\\n ],\\n // Specify list of reserves, by name\\n reserve: [\\\"Eli\\\", \\\"Liza\\\"]\\n};\\n\\n// Specify array of team members\\nmodel.team = [model.people[0], model.people[3]];\\n\\n$(\\\"#result\\\").html(teamTmpl.render(model));\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"anchor\": \"iftag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helper functions, or dynamically assigning converters\",\r\n \"text\": \"The `convert=...` syntax allows you to assign a converter function without it being registered by name. For example it can be a data method or a helper function -- such as `{{sometag ... convert=~myConverterHelper}}`.\\n\\n(You can do this with the `{{: ...}}` tag too -- by writing `{{: ... convert=~myConverterHelper}}`...)\\n\\nYou can even assign a converter dynamically. For example you can write: `{{sometag ... convert=~getConverter(...)}}`, where the `getConverter()` helper might return either a string (for a converter registered by name) or a function to be used as converter.\\n\\nTo illustrate, here is a modified version of the previous sample, using `{{if ... convert=~getConverter()}}`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Converter function\\nfunction inlistConverter(item, list) { ... }\\n\\n// Helper to dynamically assign converters\\nfunction getConverter() {\\n return inlistConverter; // For this sample just return `inlistConverter` every time\\n}\\n\\n// Register 'getConverter' helper just for the 'teamTmpl' template \\n$.views.helpers(\\\"getConverter\\\", getConverter, teamTmpl);\\n```\\n\\n```jsr\\n{{if #data ~root.team convert=~getConverter()}}\\n ...\\n{{/if}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"var teamTmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Converter function for looking for an item (first argument of tag) in a list (second argument of tag)\\nfunction inlistConverter(item, list) {\\n // If no arguments, this is the final {{else}}\\n if (!list) {\\n return true; // Final else, so return true\\n }\\n\\n var field = this.tagCtx.props.field;\\n var l = list.length;\\n\\n // If the tag has a 'field' property, look for the value of that field among the list items\\n if (field) {\\n while (l--) {\\n if (item[field] === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n\\n // If no field property, look for the item among the list items\\n else {\\n while (l--) {\\n if (item === list[l]) {\\n return true; // Return true if found\\n }\\n }\\n }\\n return false; // Not found\\n}\\n\\n// Helper to dynamically assign converters\\nfunction getConverter() {\\n return inlistConverter; // For this sample just return `inlistConverter` every time\\n}\\n\\n// Register 'getConverter' helper just for the 'teamTmpl' template \\n$.views.helpers(\\\"getConverter\\\", getConverter, teamTmpl);\\n\\n// Define model \\nvar model= {people: [\\n {name: \\\"Jo\\\"},\\n {name: \\\"Liza\\\"},\\n {name: \\\"Eli\\\"},\\n {name: \\\"Pete\\\"},\\n {name: \\\"Zoey\\\"}\\n ],\\n // Specify list of reserves, by name\\n reserve: [\\\"Eli\\\", \\\"Liza\\\"]\\n};\\n\\n// Specify array of team members\\nmodel.team = [model.people[0], model.people[3]];\\n\\n$(\\\"#result\\\").html(teamTmpl.render(model));\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"title\": \"Dynamically assigning a converter\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in converters:\",\r\n \"text\": \"JsRender has the following built-in converters/encoders:\\n\\n- Built-in HTML encoder: [`{{html: ...}}`](#convertersapi@html) -- accessed programmatically as [`$.views.converters.html()`](#convertersapi@html)\\n- Built-in attribute encoder: [`{{attr: ...}}`](#convertersapi@attr) -- accessed programmatically as [`$.views.converters.attr()`](#convertersapi@attr)\\n- Built-in URL encoder: [`{{url: ...}}`](#convertersapi@url) -- accessed programmatically as [`$.views.converters.url()`](#convertersapi@url)\\n- Basic [encode/unencode converters](#convertersapi@encode)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in HTML encoder\",\r\n \"text\": \"JsRender includes an HTML encoder, which you can use programmatically as follows:\\n\\n```js\\nvar myHtmlEncodedString = $.views.converters.html(myString);\\n```\\n\\nThe same encoder is accessed declaratively as a converter, as in the following two examples:\\n\\n```jsr\\n{{html:myExpression}}\\n\\n{{>myExpression}}\\n```\\n\\nIn fact [`{{>...}}`](#htmltag) is exactly equivalent to `{{html:...}}` and is provided as a simpler syntax for HTML encoding values taken from data or from expressions and rendered within HTML content. \\n\\n(***Note:*** the [`{{> ...}}`](#htmltag) tag should be used in place of the [`{{: ...}}`](#assigntag) tag whenever the data being rendered is not full trusted -- in order to prevent HTML injection attacks.)\",\r\n \"anchor\": \"html\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\n\\nvar result = $.views.converters.html(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\nvar result = $.views.converters.html(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the HTML encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"HTML encoder\",\r\n \"name\": \"html\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"HTML-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be HTML-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Encodes according to the following scheme:\\n

                          \\n`&` → `&`
                          \\n`<` → `<`
                          \\n`>` → `>`
                          \\n`\\\\x00` → `�`
                          \\n`'` → `'`
                          \\n`\\\"` → `"`
                          \\n\\\\` → ```
                          \\n`=` → `=`\\n\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.html;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the HTML-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in attribute encoder\",\r\n \"text\": \"JsRender includes an encoder intended for use when attribute encoding is needed. You can use it programmatically as follows:\\n\\n```js\\nvar myAttributeEncodedString = $.views.converters.attr(myString);\\n```\\n\\nThe same encoder is accessed by declaratively as a converter:\\n\\n```jsr\\n{{attr:myExpression}}\\n```\\n\\nA typical use case would be to encode an HTML attribute value in a template:\\n\\n```jsr\\n
                          ...
                          \\n```\",\r\n \"anchor\": \"attr\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" &\\\";\\n\\nvar result = $.views.converters.attr(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"< > ' \\\\\\\" & =\\\";\\nvar result = $.views.converters.attr(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the 'attribute' encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"Attribute encoder\",\r\n \"name\": \"attr\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"Attribute-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be attribute-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Encodes according to the following scheme:\\n

                          \\n`&` → `&`
                          \\n`<` → `<`
                          \\n`>` → `>`
                          \\n`\\\\x00` → `�`
                          \\n`'` → `'`
                          \\n`\\\"` → `"`
                          \\n\\\\` → ```
                          \\n`=` → `=`\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Note that this scheme encodes more characters than is sometimes the case for attribute encoding. In fact currently `{{attr: ...}}` and `{{html: ...}}` are equivalent. This ensures that using attribute encoding when HTML encoding should have been used will not expose an injection attack risk from untrusted data.\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.attr;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the attribute-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in URL encoder\",\r\n \"text\": \"JsRender includes a URL encoder, which you can use programmatically as follows:\\n\\n```js\\nvar myUrlEncodedString = $.views.converters.url(myString);\\n```\\n\\nThe same encoder is accessed by declaratively as a converter:\\n\\n```jsr\\n{{url:myExpression}}\\n```\\n\\nA typical use case would be to encode a HTML URL attribute value in a template:\\n\\n```jsr\\n\\n```\",\r\n \"anchor\": \"url\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var value = \\\"<_>_\\\\\\\"_ \\\";\\n\\nvar result = $.views.converters.url(value);\\n\\nalert(result);\"\r\n }\r\n ],\r\n \"code\": \"var value = \\\"<_>_\\\\\\\"_ \\\";\\nvar result = $.views.converters.url(value);\\n\\n$(\\\"#show\\\").on(\\\"click\\\", function() {\\n alert(result);\\n});\",\r\n \"html\": \"\\n\",\r\n \"height\": \"46\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Calling the 'url' encoder\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"URL encoder\",\r\n \"name\": \"url\",\r\n \"object\": \"$.views.converters\",\r\n \"method\": true,\r\n \"returns\": \"URL-encoded string\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"valueToEncode\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"input string to be URL-encoded\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Internally encodes by calling the JavaScript function `encodeURI`.\"\r\n }\r\n ],\r\n \"example\": \"var encoder = $.views.converters.url;\\nvar encodedString = encoder(myString);\",\r\n \"description\": \"Returns the URL-encoded string\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Minimalist HTML encode/unencode converters\",\r\n \"text\": \"\\nIn addition JsRender and JsViews provide encode/unencode converters for minimal encoding to prevent HTML injection (see the JsViews topic: [*Encoding to avoid XSS*](#link2way@encode)), by encoding just `<` `>` and `&` by the corresponding HTML entities, and for unencoding back from entities to characters:\\n\\n`&` ↔ `&`
                          \\n`<` ↔ `<`
                          \\n`>` ↔ `>`
                          \\n\\n*Usage:*\\n\\n```js\\nencodedValue = $.views.converters.encode(unencodedValue);\\nunencodedValue = $.views.converters.unencode(encodedValue);\\n```\\n\\n*Declarative usage:*\\n\\n```jsr\\n{{encode:myExpression}}\\n```\",\r\n \"anchor\": \"encode\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"converters\",\r\n \"label\": \"Using converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/converters\",\r\n \"label\": \"Converters and encoding sample\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tagsapi@bindto\",\r\n \"label\": \"Custom tags: The bindTo / bindFrom options and converters\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"converters\": {\r\n \"title\": \"Using converters\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What are converters?\",\r\n \"text\": \"In JsRender, a converter is a convenient way of processing or formatting data-value, or the result of expression evaluation.\\n\\nYou use built-in converters to *HTML-encode*, *attribute-encode*, or *URL-encode*: \\n\\n```jsr\\n{{html:movie.description}} - This data is HTML encoded\\n{{>movie.description}} - (Alternative syntax) - This data is HTML encoded\\n\\n{{url:~getTheFilePath()}} - This expression will be URL-encoded\\n```\\n\\nAnd you can register custom converters. For example you might register a date formatter or an upper-case converter:\\n\\n```jsr\\n{{daymonth:invoice.date}} - This date uses my 'daymonth' formatter \\n{{upper:name}} - This uses my 'upper' converter \\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Built-in converters\",\r\n \"text\": \"JsRender has the following built-in converters -- based on encoders:\\n\\n- Built-in HTML encoder: [`{{> ...}}`](#convertersapi@html)\\n- Built-in attribute encoder: [`{{attr ...}}`](#convertersapi@attr)\\n- Built-in URL encoder: [`{{url ...}}`](#convertersapi@url)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering a converter\",\r\n \"text\": \"You can register your own custom converters, using [`$.views.converters()`](#convertersapi) as in:\\n\\n```js\\n$.views.converters(\\\"upper\\\", function(val) {\\n // Convert data-value or expression to upper case\\n return val.toUpperCase();\\n});\\n```\\n\\nTo use the `\\\"upper\\\"` converter with the [`{{:...}}`](#assigntag) tag, you write:\\n\\n```jsr\\n{{upper:...}}\\n```\\n\\nHere it is in a sample:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n```\\n\\n```jsr\\nName: {{:name}}. Upper case nickname: {{upper:nickname}}\\n...\\n{{upper: \\\"This will be upper case too\\\"}} \\n```\"\r\n }\r\n ],\r\n \"code\": \"$.views.converters(\\\"upper\\\", function(val) {\\n return val.toUpperCase();\\n});\\n\\nvar person = {name: \\\"Robert\\\", nickname: \\\"Bob\\\"};\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"height\": \"80\",\r\n \"title\": \"A simple converter\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"simple\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Converter arguments\",\r\n \"text\": \"A converter can access any number of [tag arguments](#tagsyntax@tagparams), to produce the computed value which it provides to the tag:\\n\\n```js\\n$.views.converters(\\\"myConverter\\\", function(arg1, arg2, arg3 ...) {\\n```\\n\\nFurthermore, the `this` pointer within the converter function is the [instance](#tagobject) of the tag, which allows it to access much more, including [named tag properties](#tagsyntax@tagparams) (`this.tagCtx.props...`), the full data object (`this.tagCtx.view.data`), and more...\\n\\nThe following sample shows a `\\\"fullname\\\"` converter, which provides a computed ***full name*** based on the first two tag arguments (*first* and *last*) and an optional named tag parameter `reverse=true`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters(\\\"fullname\\\", function(first, last) {\\n var reverse = this.tagCtx.props.reverse; \\n if (reverse) {\\n return last.toUpperCase() + \\\" \\\" + first;\\n }\\n return first + \\\" \\\" + last;\\n});\\n```\\n\\n```jsr\\n... {{fullname:first last}}\\n... {{fullname:first last reverse=true}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.views.converters(\\\"fullname\\\", function(first, last) {\\n var reverse = this.tagCtx.props.reverse; \\n if (reverse) {\\n return last.toUpperCase() + \\\" \\\" + first;\\n }\\n return first + \\\" \\\" + last;\\n});\\n\\nvar person = {first: \\\"Xavier\\\", last: \\\"Prieto\\\"};\\n\\nvar html = $(\\\"#personTemplate\\\").render(person);\\n\\n$(\\\"#person\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"80\",\r\n \"title\": \"Full name converter – accessing multiple arguments\",\r\n \"anchor\": \"fullname\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using converters with other tags\",\r\n \"text\": \"A converter can be used on any tag, thanks to the syntax\\n\\n```jsr\\n{{sometag ... convert=...}}\\n```\\n\\nwhere `sometag` can be any custom tag, or a built-in tag such as `{{if}}`.\\n\\n(*Note:* When using JsViews [two-way binding](#link2way@converters), similar syntax is available for *convertBack*: `convertBack=...`.)\\n\\nFor example, you could register an `\\\"inList\\\"` converter which returns true if `item` is found in `itemList` (see [sample](#convertersapi@iftag)):\\n\\n```jsr\\n{{if convert='inList' item itemList}}...{{/if}}\\n``` \\n\\nThe following sample shows the `{{for ...}}` tag used with a named converter which returns the array with additional appended and prepended items:\",\r\n \"anchor\": \"othertags\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.converters({\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n});\\n```\\n\\n```jsr\\n{{for people convert='extraItems'}}\\n ...\\n```\\n\\n\\n\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.views.converters({\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n});\\n\\nvar model= {people: [\\n {name: \\\"Jo1\\\"},\\n {name: \\\"Jo2\\\"},\\n {name: \\\"Jo3\\\"}\\n]};\\n\\nvar html = $(\\\"#myTmpl\\\").render(model);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"title\": \"Using converters with the {{for}} tag\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\",\r\n \"anchor\": \"fortag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using helper functions or data methods as converters\",\r\n \"text\": \"The `convert=...` syntax not only works on any tag, but also allows you to use not only registered converters, by name, as in\\n\\n```jsr\\n{{for people convert='odd'}}\\n```\\n\\nbut alternatively to use helpers, or data methods as in\\n\\n```jsr\\n{{for people convert=utility.extraItems}} // Using data method\\n```\\n\\nYou can also use that approach on `{{:..}}` tags as in\\n\\n```jsr\\n{{:name convert=~hlp.bold}} // Using a helper\\n```\\n\\nNote that the one tag which does not support this syntax is `{{>...}}` -- for which you would need instead to write:\\n\\n```jsr\\n{{>~hlp.bold(name)}} // Using helper \\n```\\n\\nHere is a modified version of the sample above, using helpers and data methods:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n...\\n{{for people convert=utility.extraItems}} {{!-- using data method --}}\\n
                        • \\n {{:name convert=~hlp.bold}} {{!-- using helper --}}\\n...\\n```\"\r\n }\r\n ],\r\n \"code\": \"var helpers = {\\n hlp: {\\n bold: function(val) {\\n return \\\"\\\" + val + \\\"\\\";\\n }\\n }\\n};\\n\\nvar model= {people: [\\n {name: \\\"Jo1\\\"},\\n {name: \\\"Jo2\\\"},\\n {name: \\\"Jo3\\\"}\\n ],\\n utility: {\\n extraItems: function(arr) {\\n // return array with additional items\\n return [{name: \\\"Prepended\\\"}].concat(arr, {name: \\\"Appended\\\"});\\n }\\n }\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(model, helpers);\\n\\n$(\\\"#result\\\").html(html);\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"114\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"For additional details and scenarios see:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"hash\": \"convertersapi\",\r\n \"label\": \"Registering converters\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"link2way\",\r\n \"label\": \"Two-way binding (JsViews)\"\r\n }\r\n ]\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also the following sample:\",\r\n \"text\": \"[Converters and encoding](#samples/jsr/converters)\\n\"\r\n }\r\n ]\r\n },\r\n \"nojqueryapi\": {\r\n \"title\": \"JsRender without jQuery\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"JsRender can be loaded in the browser with or without jQuery, as in these example pages:\\n\\n- [JsRender with jQuery](#download/pages-jsr-jq)\\n- [JsRender without jQuery](#download/pages-jsr)\\n\\nWhen jQuery is present:\\n\\n- JsRender loads as a jQuery plugin and adds APIs to the `jQuery` global namespace object -- usually aliased as `var $ = jQuery;`\\n- The JsRender APIs are\\n - `$.views...`\\n - `$.templates(...)`\\n - `$.render...`. \\n\\nIf jQuery is not present:\\n\\n- JsRender automatically creates its own `jsrender` global namespace variable \\n- JsRender APIs are the same as above, but they are now associated with the `jsrender` namespace variable: \\n - `jsrender.views...`\\n - `jsrender.templates(...)`\\n - `jsrender.render...`. \\n\\nFor convenience you can follow the jQuery approach of creating a global `$` -- set this time to `var $ = jsrender;`\\n\\nYou can then use the regular APIs: `$.views...`, `$.templates...`, `$.render...`, or copy code from the regular browser examples/samples -- *as if* using JsRender with jQuery.\\n\\nFor example:\\n\\n```js\\nvar $ = jsrender; // Alias for the jsrender namespace object - referenced for convenience as var $\\n\\nvar tmpl = $.templates('Name: {{:first}} {{upper:last}}'); // Compile template from string\\n\\n$.views.converters('upper', function(val) {return val.toUpperCase()}); // Register converter\\n \\nvar data = {first: 'Jo', last: 'Ryan'};\\n\\nvar html = tmpl.render(data);\\n// result: \\\"Name: Jo RYAN\\\" \\n```\\n\\n***Note:*** The same approach can be used when using [JsRender on the server](#node/install@apis) with Node.js, where JsRender is also being used without jQuery. \"\r\n }\r\n ]\r\n },\r\n \"node/webpack\": {\r\n \"title\": \"JsRender on Node.js\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"## Webpack support for JsRender and JsViews\\n JsRender and JsViews can be loaded using [webpack](https://webpack.github.io/).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsRender as a webpack module\",\r\n \"text\": \"After installing JsRender on the server (using `$ npm install jsrender`) it can then be included in the webpack client script bundle, and loaded in the browser.\\n\\nThere are three options for loading JsRender in the browser as a webpack module:\\n\\n- Load jQuery globally (as a script tag -- so `window.jQuery` is defined), then load JsRender as a module in the webpack client script bundle:\\n ```js\\n require('jsrender'); // Load JsRender as jQuery plugin (attached to global jQuery)\\n ```\\n- Load both jQuery and JsRender as modules in the webpack client script bundle:\\n ```js\\n var $ = require('jquery'); // Load jQuery as a module\\n require('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\n ```\\n- Load JsRender as a module in the webpack client script bundle, without loading jQuery at all:\\n ```js\\n var jsrender = require('jsrender')(); // Load JsRender without jQuery (function call, no parameter)\\n ```\\n\\n***Note:*** In fact if jQuery is not defined globally, `require('jsrender')` returns a ***function***. \\n\\nCalling that function without a parameter then loads JsRender without jQuery (and returns the JsRender namespace). \\n\\nAlternatively, calling that function with a reference to a jQuery instance as parameter loads JsRender as a plugin (attached to that jQuery instance) -- and returns the jQuery instance.\",\r\n \"anchor\": \"jsrender\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded globally:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n \\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nrequire('jsrender'); // Load JsRender (jQuery is loaded as global)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – jQuery loaded as module:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar $ = require('jquery'); // Load jQuery as a module\\nrequire('jsrender')($); // Load JsRender as jQuery plugin (jQuery instance as parameter)\\nvar tmpl = $.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\n$('#container').html(html);\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Example – JsRender without jQuery:\",\r\n \"text\": \"**index.html:**\\n\\n```jsr\\n\\n
                          \\n \\n\\n```\\n\\n**source.js:**\\n\\n```js\\nvar jsrender = require('jsrender')(); // Load JsRender without jQuery\\nvar tmpl = jsrender.templates('Name: {{:name}}');\\nvar data = {name: 'Jo'};\\nvar html = tmpl.render(data);\\ndocument.querySelector('#container').innerHTML = html;\\n```\\n\\n**command line:**\\n\\n```bash\\nwebpack ./source.js bundle.js\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"JsViews as a webpack module\",\r\n \"text\": \"JsViews can also be included in the webpack client-script bundle, and loaded in the browser.\\n\\nAfter installing on the server (using `$ npm install jsviews`), call:\\n\\n```js\\nrequire('jsviews'); // Load JsViews (if jQuery is loaded globally)\\n```\\n\\nor -- if also loading jQuery as a webpack module, use:\\n\\n```js\\nvar $ = require('jquery');\\n...\\nrequire('jsviews')($); // Load JsViews (passing local jQuery instance as parameter)\\n```\",\r\n \"anchor\": \"jsviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"See also:\",\r\n \"text\": \"*[Browserify support](#node/browserify)*\"\r\n }\r\n ]\r\n },\r\n \"viewmodelsapi\": {\r\n \"title\": \"Compiled View Models, using $.views.viewModels()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This topic provides details on using `$.views.viewModels()` to register/compile *View Models*.\\n\\nThis is the third of the alternative approaches discussed in *[Data / View Models](#jsrmodel)* -- namely:\\n- [using](#jsrmodel@plain) plain objects\\n- [using](#jsrmodel@vm) 'hand-coded' View Models\\n- [using](#jsrmodel@compilevm) `$.views.viewModels()` to compile and register View Models with specific *get/set* properties and methods.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advantages of compiled View Models\",\r\n \"text\": \"Using `$.views.viewModels()` to compile *View Models* brings some important advantages over plain object hierarchies or 'hand-coded' *View Models*:\\n\\n- Simple calls to `$.views.viewModels(...)` allow you to compile these *View Model* classes without having to manually write repetitive code for multiple such *get/set* properties\\n- Using compiled *View Models* rather than plain objects makes it easier to have clean well-designed modular code, since each *View Model* has specific *getters*, *setters* and *methods*, and can have its own 'private' properties and state\\n- The compiled *View Models* provide a built-in mapping and unmapping feature for automatically converting from a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances, or for converting back to plain data (such as for submitting to the server)\\n- They also provide a `merge(...)` feature for incrementally updating the *View Model* hierarchy, using updated plain data from the server\\n- When working with (or migrating to) *JsViews* the compiled classes automatically become fully-fledged MVVM classes, with a rich range of features -- where the *Views* are observable data-linked templates. Updates to the *View Model* hierarchy, and calls to the *View Model* setters both trigger observable changes, with corresponding incremental updates to the *Views*. (For more information see *[JsViews: Data / View Model](#jsvmodel)* and *[JsViews: Compiled View Models](#jsvviewmodelsapi)*.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using compiled View Models\",\r\n \"text\": \"The basic *use scenarios* of compiled *View Models* are as follows:\\n- Using `$.views.viewModels(...)` to [register/compile](#viewmodelsapi@compile) *View Models* (`myVM`)\\n- Using a compiled View Model `myVM` as [constructor/factory](#viewmodelsapi@construct) method -- `MyVM(...)` -- to create View Model instances (`myVmInstance`)\\n- Using `MyVM.map(...)` to [convert](#viewmodelsapi@map) a plain object hierarchy (such as from a JSON request) to a hierarchy of *View Model* instances\\n- Using `myVMInstance.merge(...)` to incrementally [update](#viewmodelsapi@merge) a *View Model* hierarchy, using updated plain data\\n- Using `myVMInstance.unmap()` to [convert](#viewmodelsapi@unmap) a *View Model* hierarchy back to a plain object hierarchy\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"API: $.views.viewModels(...)\",\r\n \"text\": \"To register a *View Model*, you call the `$.views.viewModels(...)` API -- with four alternative signatures:\\n- `var MyVM = $.views.viewModels(viewModelOptions);`
                          returning a compiled *View Model* \\n- `$.views.viewModels(\\\"MyVM\\\", viewModelOptions);`
                          registering a named *View Model*, accessible as `$.views.viewModels.MyVM`\\n- `$.views.viewModels(namedViewModels);`
                          where `namedViewModels` is a hash, declaring multiple *View Models*\\n- `$.views.viewModels(namedViewModels, myViewModels);`
                          where `namedViewModels` is a hash, declaring multiple *View Models* and `myViewModels` is a *View Models* collection (hash) which will provide access to the compiled *View Models*, as `myViewModels.MyVM`\\n\\nIn each case, the compiled *View Model* is specified by a `viewModelOptions` object, with a `getters: gettersArray` (specifying an array of *get/set* properties), and/or an `extend: extendObject` (specifying additional methods or properties).\\n\\nExample:\\n\\n```js\\nvar Book = $.views.viewModels({ // Compile a Book View Model\\n getters: [\\\"title\\\", \\\"price\\\"], // getters array - signature of constructor\\n extend: { // extend object - additional methods \\n placeOrder: function() { ... }\\n }\\n});\\n\\nvar book1 = Book(\\\"Hope\\\", \\\"1.50\\\"); // Construct a Book View Model instance\\nbook.price(\\\"2.50\\\"); // Modify price\\nbook.placeOrder(); // Call method\\n```\\n\",\r\n \"anchor\": \"compile\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.viewModels(...)\",\r\n \"name\": \"viewModels\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"tag\": false,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModelOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A viewModelOptions object which can include:
                          • a 'getters' array (details below)
                          • an 'extend' hash - with additional methods or properties
                          • an 'id' specifier
                          \"\r\n }\r\n ],\r\n \"sections\": [],\r\n \"example\": \"var Book = $.views.viewModels({\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n\\nvar bk1 = Book(\\\"Hope\\\", \\\"$1.50\\\");\",\r\n \"description\": \"Return a compiled View Model (constructor/factory method) with specific get/set properties and methods\",\r\n \"returns\": \"View Model constructor\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": true,\r\n \"description\": \"Name for the registered View Model\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModelOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A viewModelOptions object which can include:
                          • a 'getters' array (details below)
                          • an 'extend' hash - with additional methods or properties
                          • an 'id' specifier
                          \"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.viewModels(\\\"Book\\\", {\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n\\nvar bk1 = $.views.viewModels.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Register (and return) a named View Model\",\r\n \"returns\": \"View Model constructor\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedViewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"hash of viewModelOptions objects - each of which can include:
                          • a 'getters' array (details below)
                          • an 'extend' hash - with additional methods or properties
                          • an 'id' specifier
                          \"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.viewModels({\\n Book: {getters: [\\\"title\\\", \\\"price\\\"]},\\n ...\\n});\\n\\nvar bk1 = $.views.viewModels.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Register multiple named View Models\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedViewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"hash of viewModelOptions objects - each of which can include:
                          • a 'getters' array (details below)
                          • an 'extend' hash - with additional methods or properties
                          • an 'id' specifier
                          \"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"viewModels\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"View Model collection object (hash)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Specifying **viewModelOptions** – details:*\\n\\n- The (optional) `getters` array.
                          -- Each item in the array corresponds to a *get/set* property (and also a constructor argument, which initializes that *get/set* property).
                          -- It must be either\\n - a string -- the `getterName`, or\\n - an object, which must have a *getter* property: `{getter: getterName}`.

                          If an object, it can additionally specify:

                          \\n - a *type* property: `type: viewModelName` -- specifying the name of another *View Model* type (declared in the same View Model collection). In this case then when using `map()` to map from data to a generated *View Model* hierarchy (see below), data values for the *get/set* property will be mapped to instances of that *View Model*.\\n - a *defaultVal* property -- specifying the value to be used at initialization if `undefined` -- such as\\n - `defaultVal: null` (a value) or,\\n - `defaultVal: function() { return ...; }` (a function, to return a computed value. The this pointer is the data item.) \\n- The (optional) `extend` hash has additional members (methods or properties) to be included in the View Model prototype. The prototype will extend this object\\n- The (optional) `id` is either a string (the name of a *View Model* property to be treated as **id**) or\\na function. The specified *id* or the function call will be used for determining identity when `merge(...)` updates a *View Model* hierarchy (see below)\"\r\n }\r\n ],\r\n \"example\": \"var myVms = {};\\n\\n$.views.viewModels({\\n Book: {getters: [\\\"title\\\", \\\"price\\\"]},\\n ...\\n}, myVms);\\n\\nvar bk1 = myVms.Book(\\\"Hope\\\", \\\"$1.50\\\");\\n\",\r\n \"description\": \"Add one or more named View Models to a View Model collection (hash)\",\r\n \"returns\": \"View Model collection (hash)\"\r\n }\r\n ],\r\n \"description\": \"Register one or more View Models\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Creating View Model instances, using the View Model constructor\",\r\n \"text\": \"*View Models* compiled/registered/returned by `$.view.viewModels(...)` are in fact constructors for instances of the *View Model* class.\\n\\n```js\\nvar Book = $.views.viewModels({ // Constructor\\n getters: [\\\"title\\\", \\\"price\\\"] // getters array - signature of constructor\\n ...\\n});\\n\\nvar book1 = Book(\\\"Hope\\\", \\\"$1.50\\\"); // Create Book instance\\n```\\n\\nNote that:\\n- The `new` keyword is not necessary when calling the constructor. (It is in effect a factory method, that calls `new` internally.)\\n- The signature of the constructor call (parameters used to initialize the instance) corresponds to the array of getters specified in the `viewModelOptions` - in this case `[\\\"title\\\", \\\"price\\\"]`\",\r\n \"anchor\": \"construct\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model hierarchies\",\r\n \"text\": \"The `Book` View Model example above has simple *get/set* properties `[\\\"title\\\", \\\"price\\\"]` which are simple primitive types (string in this case).\\n\\nBut consider the `Person` *View Model*, used in the overview topic *[Data / View Model](#jsrmodel)*. Here a `person` object (whether a plain object or a *View Model* instance) is in fact a hierarchy of objects, since the `address` and `phones` properties of a `Person` are themselves objects (an `Address` object and a `Phone` array)\\n\\nHere is a `person` plain object/hierarchy (obtained perhaps by 'evaluating' JSON data from the server): \\n\\n```js\\nvar person = {\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\"\\n },\\n phones: [{number: \\\"111 111 1111\\\"}, {number:\\\"222 222 2222\\\"}] \\n};\\n```\\n\\nTo map this object hierarchy to the corresponding *View Model* hierarchy we need to define three *View Models*:\\n\\n```js\\n// Compile Person View Model, with addPhone method\\nvar Person = $.views.viewModels({\\n getters: [\\\"name\\\", \\\"address\\\", \\\"phones\\\"],\\n extend: {addPhone: addPhone}\\n});\\n\\n// Compile Address View Model\\nvar Address = $.views.viewModels({getters: [\\\"street\\\"]});\\n\\n// Compile Phone View Model\\nvar Phone = $.views.viewModels({getters: [\\\"number\\\"]});\\n```\\n\\nWe can then instanciate the corresponding *View Model* hierarchy, using constructors:\\n\\n```js\\nvar person = Person(\\n \\\"Pete\\\",\\n Address(\\\"1st Ave\\\"),\\n [Phone(\\\"111 111 1111\\\"), Phone(\\\"222 222 2222\\\")]\\n);\\n```\\n\\nSee the [sample](#jsrmodel@compilevmsample) in the *[Data / View Model](#jsrmodel)* topic.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Creating View Model instances by mapping from data\",\r\n \"text\": \"The process of manually writing code to map from JSON data to a corresponding *View Model* hierarchy, as above, can be complex and inconvenient. It requires traversing the data hierarchy and using appropriate *View Model* constructors to instantiate corresponding *View Model* instances. \\n\\nFortunately *JsRender/JsViews* compiled *View Models* provide a `map(data)` feature which when used together with *View Model* typed hierarchies makes this process quite trivial.\\n\",\r\n \"anchor\": \"map\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"API: MyViewModel.map(...)\",\r\n \"text\": \"Any compiled *View Model*, `MyViewModel`, provides a `MyViewModel.map(...)` method, which can be used to convert a plain object or an array of plain objects (or the equivalent JSON string) to the corresponding *View Model* instance (or array of *View Model* instances).\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"MyViewModel.map(...)\",\r\n \"name\": \"map\",\r\n \"object\": \"MyViewModel\",\r\n \"method\": true,\r\n \"returns\": \"View Model instance or array or instances\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object, array of objects, or JSON string\",\r\n \"optional\": false,\r\n \"description\": \"The data (typically from JSON request)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"// View Model\\nvar Person = $.views.viewModels.Person;\\n\\n// View Model instance\\nvar person = Person.map(personData);\",\r\n \"description\": \"Generate a View Model instance/hierarchy/array by mapping from data (a plain object instance/hierarchy/array, or JSON string)\"\r\n }\r\n ],\r\n \"description\": \"Generate a View Model hierarchy from data\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Example:\\n\\n```js\\nvar Book = $.views.viewModels({ // Constructor\\n getters: [\\\"title\\\", \\\"price\\\"]\\n});\\n```\\n\\nMap from `bookData` plain object to `book` View Model instance:\\n\\n```js\\nvar bookData1 = {title: \\\"Hope\\\", price: \\\"$1.50\\\"}; // book (plain object)\\nvar book1 = Book.map(bookData1); // book (instance of Book View Model)\\n```\\n \\nMap from `bookDataArray` array of plain objects to `bookArray` array of View Model instances:\\n\\n```js\\nvar bookDataArray1 = [ // book array (plain objects)\\n {title: \\\"Hope\\\", price: \\\"$1.50\\\"},\\n {title: \\\"Courage\\\", price: \\\"$2.50\\\"}\\n];\\nvar booksArray1 = Book.map(bookDataArray1); // book array (instances of Book View Model)\\n```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"View Model typed hierarchies\",\r\n \"text\": \"When specifying `getters` in the `$.views.viewModels(...)` call, you can declare the type of a *get/set* property. For example an `address` *get/set* property can be specified as being of type `Address` -- where `Address` is another *View Model* declared on the same collection.\\n\\nBy specifying View Model types for properties (and declaring those View Models in the same collection) you obtain a *'View Model typed hierarchy'*.\\n\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using MyViewModel.map(...) to map a whole object hierarchy to a View Model instance hierarchy\",\r\n \"text\": \"In the case of a *'View Model typed hierarchy'*, simply pass the top-level plain object to the `map()` method for the top-level *View Model* class, and all *View Model* instances in the hierarchy will be correctly instantiated:\\n\\n*Compile View Model classes (typed hierarchy):* \\n\\n```js\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // Declare 'name' as being a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // Declare 'address' as being an Address (View Model) type\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Declare 'phones' as being (an array) of Phone (View Model) types\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone: ...\\n});\\n```\\n\\n*Person data (plain object hierarchy, or JSON string):*\\n\\n```js\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, ...]\\n };\\n```\\n\\n*Use map() to convert from `personData` plain object hierarchy (or JSON string) to `person` *View Model* hierarchy:*\\n\\n```js\\nvar person = $.views.viewModels.Person.map(personData);\\n```\\n\\nThe getter properties then let you traverse the hierarchy, call methods, etc.\\n\\n```\\nperson.name(\\\"newName\\\"); // Use setter: change name\\nperson.addPhone(...); // Call method: add phone\\nvar phone2 = person.phones()[1].number(); // Traverse and use getter: get number\\n```\\n\\nLet's modify the [sample](#jsrmodel@compilevmsample) in *[Data / View Model](#jsrmodel)* to use the `map(...)` approach:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"template\",\r\n \"title\": \"\",\r\n \"markup\": \"... {{:name()}} ...\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: ...\\n Phone: ...\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy using Person.map(data)\",\r\n \"code\": \"var personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\nvar person = vmCollection.Person.map(personData);\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Render template against person object (instance of Person)\",\r\n \"code\": \"$(\\\"#result\\\").html(tmpl.render(person));\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Call setter, call method...\",\r\n \"code\": \"...\\nperson.name(\\\"newName\\\"); // Use the name(...) setter\\n\\n...\\nperson.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n\\n\\n\\n
                          \\n\\n\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone:{\\n getters: [\\\"number\\\"]\\n }\\n});\\n\\nvar vmCollection = $.views.viewModels;\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(vmCollection.Phone(phoneNo));\\n}\\n\\n// person plain object hierarchy:\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\n// Instantiate View Model hierarchy using map()\\nvar person = vmCollection.Person.map(personData);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\",\r\n \"height\": \"190\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"title\": \"Using map() to convert from a plain object hierarchy to a View Model hierarchy\",\r\n \"anchor\": \"mapsample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also the [corresponding sample](#jsvviewmodelsapi@mapsample) with JsViews and data-linking.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Along with the map() feature – merge() and unmap()\",\r\n \"text\": \"When working with View Model typed hierarchies, there are two additional features that can be used together with the `map()` feature:\\n\\n- If later you obtain updated JSON data, `personData2`, you can use `merge()` ([below](#viewmodelsapi@merge)) to trigger an incremental update to the *View Model* hierarchy:\\n ```js\\n person.merge(personData2);\\n ```\\n- If values are modified (using setters, or methods) you can at any time can use `unmap()` ([below](#viewmodelsapi@unmap)) to convert back to plain data, but with updated values:\\n ```js\\n var updatedPersonData = person.unmap();\\n ```\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using myVMobjectOrArray.merge(...) to update a View Model hierarchy\",\r\n \"text\": \"If a *View Model* hierarchy (or array of *View Model* instances) was created using the `map()` feature above to map from data, then the *View Model* instances (and arrays) will each have a `merge()` method available:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.merge(personData2); // Incrementally update person (hierarchy)\\n```\\n\\nor for an array:\\n\\n```js\\nvar peopleArray = Person.map(peopleDataArray1);\\npeopleArray.merge(peopleDataArray2); // Incrementally update people array\\n```\\n\\nOr, deeper in the hierarchy:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.phones.merge(phonesDataArray2); // Update just the person.phones array\\n```\",\r\n \"anchor\": \"merge\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Updating with merge() makes minimal incremental changes, and preserves state\",\r\n \"text\": \"Note that the `merge()` update process does not replace the whole hierarchy of *View Model* instances, but works incrementally to add/remove/modify instances as appropriate. So if most of the data in `personData2` is the same as `personData1`, calling `merge(personData2)` will make only minimal changes to the hierarchy. \\n\\nThis means that if *View Model* instances have state (such as additional properties that were set programmatically and are not driven by data) then that state can be maintained across the `merge()` update. \"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"myVMobjectOrArray.merge(...)\",\r\n \"name\": \"merge\",\r\n \"object\": \"myVMobjectOrArray\",\r\n \"method\": true,\r\n \"returns\": \"View Model instance or array\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"data\",\r\n \"type\": \"object, array of objects, or JSON string\",\r\n \"optional\": false,\r\n \"description\": \"The updated data (typically from JSON request)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"person.merge(personData2);\\n// person (View Model hierarchy) has now\\n// been updated, with modified data...\",\r\n \"description\": \"Update a previously generated View Model instance/hierarchy/array by mapping from updated data\"\r\n }\r\n ],\r\n \"description\": \"Update a View Model hierarchy, from modified data\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using myVMobjectOrArray.unmap() to convert back to a plain object hierarchy\",\r\n \"text\": \"If a *View Model* hierarchy (or array of *View Model* instances) was created by mapping from data, using the `map()` feature above, then the View Model instances (and arrays) will each have an `unmap()` method (in addition to the `merge()` method mentioned above):\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.addPhone(newPhone);\\nperson.name(newName)\\nvar modifiedPersonData = person.unmap(); // Convert back to a plain object hierarchy\\n```\\n\\nor for an array:\\n\\n```js\\nvar peopleArray = Person.map(peopleDataArray1);\\npeopleArray[1].address.street(newStreet) // Make changes anywhere in the peopleArray\\nvar modifiedPeopleDataArray = people.unmap(); // Convert back to a plain object array\\n```\\n\\nOr, deeper in the hierarchy:\\n\\n```js\\nvar person = Person.map(personData1);\\nperson.addPhone(newPhone);\\nvar modifiedPhonesArray = person.phones.unmap(); // Get a plain object array for person.phones\\n```\",\r\n \"anchor\": \"unmap\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"myVMobjectOrArray.unmap()\",\r\n \"name\": \"unmap\",\r\n \"object\": \"myVMobjectOrArray\",\r\n \"method\": true,\r\n \"returns\": \"object or array\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"// Convert back to a plain object hierarchy\\nvar modifiedPersonData = person.unmap();\\n\",\r\n \"description\": \"Obtain an updated plain object instance/hierarchy/array, from a previously generated View Model instance/hierarchy/array\"\r\n }\r\n ],\r\n \"description\": \"Get a plain object hierarchy from a View Model hierarchy\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Here is an updated version of our [previous](#viewmodelsapi@mapsample) sample, where now we have added the use of `merge()` and `unmap()`\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Compile View Model classes\",\r\n \"code\": \"...\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: ...\\n Phone: ...\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Instantiate View Model hierarchy, using map()\",\r\n \"code\": \"var personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\nvar person = vmCollection.Person.map(personData);\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Update View Model hierarchy, using merge()\",\r\n \"code\": \"$(\\\"#update\\\").on(\\\"click\\\", function() {\\n person.merge(personData2); // Update person View Model hierarchy\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\"\r\n },\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"Get current data, using unmap()\",\r\n \"code\": \"$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n var updatedPersonData = person.unmap(); // Get plain object hierarchy from current View Model hierarchy\\n window.alert(JSON.stringify(updatedPersonData));\\n});\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"// Compiled template\\nvar tmpl = $.templates(\\\"#personTmpl\\\");\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n \\\"name\\\", // name is a primitive type (string)\\n {getter: \\\"address\\\", type: \\\"Address\\\"}, // address is of type Address (View Model)\\n {getter: \\\"phones\\\", type: \\\"Phone\\\"} // Each phone is of type Phone (View Model)\\n ],\\n extend: {addPhone: addPhone}\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone:{\\n getters: [\\\"number\\\"]\\n }\\n});\\n\\nvar vmCollection = $.views.viewModels;\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) {\\n // Uses Phone() View Model constructor to create Phone instance\\n this.phones().push(vmCollection.Phone(phoneNo));\\n}\\n\\n// First version of data (e.g. from JSON request):\\nvar personData = {\\n name: \\\"Pete\\\",\\n address: {street: \\\"1st Ave\\\"},\\n phones: [{number: \\\"111 111 1111\\\"}, {number: \\\"222 222 2222\\\"}]\\n};\\n\\n// Second version of data (e.g. new JSON request):\\nvar personData2 = {\\n name: \\\"Peter\\\",\\n address: {street: \\\"2nd Ave\\\"},\\n phones: [{number: \\\"111 111 9999\\\"},{number: \\\"333 333 9999\\\"}]\\n};\\n\\n// Instantiate View Model hierarchy, using map()\\nvar person = vmCollection.Person.map(personData);\\n\\n// Render template against person object (instance of Person)\\n$(\\\"#result\\\").html(tmpl.render(person));\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n // Update View Model hierarchy, using merge()\\n person.merge(personData2);\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#revert\\\").on(\\\"click\\\", function() {\\n // Revert View Model hierarchy, using merge()\\n person.merge(personData);\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n person.name(\\\"newName\\\"); // Use the name(...) setter\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n person.addPhone(\\\"xxx xxx xxxx\\\"); // Call the addPhone(...) method\\n $(\\\"#result\\\").html(tmpl.render(person));\\n});\\n\\n$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n // Get current data, using unmap()\\n var updatedPersonData = person.unmap();\\n window.alert(JSON.stringify(updatedPersonData));\\n});\",\r\n \"html\": \"\\n\\n\\n\\n
                          \\n\\n\\n\\n
                          \\n\\n\",\r\n \"height\": \"230\",\r\n \"title\": \"Using merge() to update View Models, and unmap() to return to plain objects\",\r\n \"anchor\": \"mergesample\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(See also the [corresponding sample](#jsvviewmodelsapi@mergesample) using JsViews and data-linking.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Overriding generated get/set functions\",\r\n \"text\": \"To override a generated get/set property provided by a compiled View Model you can provide an implementation in the `extend` hash, with the same name as the *get/set* in the `getters` array:\\n\\n```js\\n// Define a myNameGetSet(...)function, to override the compiled name(...) get/set function\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Declare a Person View Model with an overridden name() get/set property\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", ...}, // Compiled name() get/set\\n ...\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n ...\\n }\\n ...\\n },\\n ...\\n});\\n```\\n\\nThe above is equivalent to the generated version except that it adds custom logging to the getter/setter function.\\n\\n**Note:** In the context of JsViews, the View Model get/set properties can be data-linked (one-way or two-way data-binding) -- and will then be invoked automatically during observable changes to the property. (This applies also to overridden properties -- using a variant of the above pattern, described in [the corresponding JsViews topic](#jsvviewmodelsapi@override)).\",\r\n \"anchor\": \"override\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Sample showing some of the advanced View Model features\",\r\n \"text\": \"The next sample is similar to the [previous](#viewmodelsapi@mergesample) one, but specifically highlights some of the advanced features of compiled *View Models*.\\n\\n- It stores compiled *View Models* on a `myVmCollection` hash, as a *View Model typed collection*, rather than on
                          `$.views.viewModels`\\n- It maps from an array of 'people' rather than a single person:
                          \\n `var people = Person.map(peopleData);`\\n- It specifies an `id` key for `Person`. When updating the `phones` array the `id` value is treated as 'primary key', and used to map 'identity':
                          \\n `id: \\\"id\\\"`\\n- It provides an `id()` callback on `Person`, for determining identity -- allowing identification of corresponding *View Model* instances within the people array, and hence preventing unnecessary disposal and re-instantiation (which would destroy state, such as the `comment` value).\\n- It has a `comment()` get/set property that is added as part of the `extend` definition, not the `getters`, so it is not initialized from data, in the constructor. Note therefore that if you set a *comment* on each `person` instance, then click *Update*, then *Revert*, one *comment* is conserved (since that instance is never disposed -- based on the 'identity' determination) but the other is lost since the instance is disposed and then re-created by *Revert*:
                          \\n `extend: {...comment: comment...}`\\n- It has `defaultVal` specified for `name`, `address` and `phones`, either as 'static' values or computed by a callback function:
                          \\n `address: {type: \\\"Address\\\", defaultVal: defaultStreet}`\\n- It overrides the generated `person.name()` *get/set* by a `myNameGetSet` function which includes logging\\n- It passes a JSON string to `merge()` or `map()`\\n(See also the [same sample](#jsvviewmodelsapi@mergesampleadv) using JsViews and data-linking.)\",\r\n \"anchor\": \"mergesampleadv\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"code\",\r\n \"title\": \"\",\r\n \"code\": \"var myVmCollection = {};\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", defaultVal: \\\"No name\\\"}, // Compiled name() get/set\\n {getter: \\\"address\\\", type: \\\"Address\\\", defaultVal: defaultAddress},\\n {getter: \\\"phones\\\", type: \\\"Phone\\\", defaultVal: []}\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n addPhone: addPhone,\\n comment: comment // Additional get/set property, not initialized by data)\\n },\\n id: function(vm, plain) { // Callback function to determine 'identity'\\n return vm.personId === plain.personId;\\n }\\n },\\n ...\\n Phone: {\\n getters: [\\\"number\\\"],\\n id: \\\"phoneId\\\" // Treat phoneId as 'primary key', for identity\\n }\\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\\n\\n// Override generated name() get/set\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\\n this.phones().push(myVmCollection.Phone(phoneNo));\\n}\\n\\n// get/set for comment (state on View Model instance, not initialized from data)\\nfunction comment(val) {\\n if (!arguments.length) {\\n return this._comment;\\n }\\n this._comment = val;\\n}\\n\\nfunction defaultAddress() { // Function providing default address if undefined in data\\n return {street: 'No street for \\\"' + this.name + '\\\"'};\\n}\\n\\n// First version of data - array of objects (e.g. from JSON request):\\nvar peopleData = [{personId: \\\"1\\\", ...}, {personId: \\\"2\\\", name: \\\"Pete\\\",...}];\\n\\n// Second version of data - JSON string (e.g. new JSON request):\\nvar peopleData2 = '[{\\\"personId\\\":\\\"2\\\",\\\"name\\\":\\\"Peter\\\",\\\"address\\\":...}]';\\n\\n// Instantiate View Model hierarchy using map()\\nvar people = myVmCollection.Person.map(peopleData);\\n\\n// Render template against people (array of Person instances)\\n$(\\\"#result\\\").html(tmpl.render(people));\\n...\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData2);\\n ...\\n});\\n...\"\r\n }\r\n ],\r\n \"code\": \"var tmpl = $.templates(\\\"#personTmpl\\\");\\n\\nvar myVmCollection = {};\\n\\n// Compile View Models\\n$.views.viewModels({\\n Person: {\\n getters: [\\n {getter: \\\"name\\\", defaultVal: \\\"No name\\\"}, // Compiled name() get/set\\n {getter: \\\"address\\\", type: \\\"Address\\\", defaultVal: defaultAddress},\\n {getter: \\\"phones\\\", type: \\\"Phone\\\", defaultVal: []}\\n ],\\n extend: {\\n name: myNameGetSet, // Override name() get/set\\n addPhone: addPhone,\\n comment: comment // Additional get/set property, not initialized by data)\\n },\\n id: function(vm, plain) { // Callback function to determine 'identity'\\n return vm.personId === plain.personId;\\n }\\n },\\n Address: {\\n getters: [\\\"street\\\"]\\n },\\n Phone: {\\n getters: [\\\"number\\\"],\\n id: \\\"phoneId\\\" // Treat phoneId as 'primary key', for identity\\n }\\n}, myVmCollection); // Store View Models (typed hierarchy) on myVmCollection\\n\\n// Override generated name() get/set\\nfunction myNameGetSet(val) {\\n if (!arguments.length) { // This is standard compiled get/set code\\n return this._name; // If there is no argument, use as a getter\\n }\\n this._name = val; // If there is an argument, use as a setter\\n console.log(\\\"name set to \\\" + val); // This is an additional line of code, for logging\\n}\\n\\n// Method for Person class\\nfunction addPhone(phoneNo) { // Uses myVmCollection.Phone() to construct new instance\\n this.phones().push(myVmCollection.Phone(phoneNo));\\n}\\n\\n// get/set for comment (state on View Model instance, not initialized from data)\\nfunction comment(val) {\\n if (!arguments.length) {\\n return this._comment; // If there is no argument, use as a getter\\n }\\n this._comment = val;\\n}\\n\\nfunction defaultAddress() { // Function providing default address if undefined in data\\n return {street: 'No street for \\\"' + this.name + '\\\"'};\\n}\\n\\n// First version of data - array of objects (e.g. from JSON request):\\nvar peopleData = [\\n {\\n personId: \\\"1\\\",\\n address: {\\n street: \\\"2nd Ave\\\"\\n }\\n },\\n {\\n personId: \\\"2\\\",\\n name: \\\"Pete\\\",\\n phones: [\\n {number: \\\"333 333 3333\\\", phoneId: \\\"2a\\\"}\\n ]\\n }\\n];\\n\\n// Second version of data - JSON string (e.g. new JSON request):\\nvar peopleData2 = '[{\\\"personId\\\":\\\"2\\\",\\\"name\\\":\\\"Peter\\\",\\\"address\\\":{\\\"street\\\":\\\"11 1st Ave\\\"},'\\n+ '\\\"phones\\\":[{\\\"number\\\":\\\"111 111 9999\\\",\\\"phoneId\\\":\\\"1a\\\"},{\\\"number\\\":\\\"333 333 9999\\\",\\\"phoneId\\\":\\\"2a\\\"}]}]';\\n\\n// Instantiate View Model hierarchy using map()\\nvar people = myVmCollection.Person.map(peopleData);\\n\\n// Render template against people (array of Person instances)\\n$(\\\"#result\\\").html(tmpl.render(people));\\n\\n// Button handlers\\n$(\\\"#update\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData2);\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#revert\\\").on(\\\"click\\\", function() {\\n people.merge(peopleData);\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#changeName\\\").on(\\\"click\\\", function() {\\n people[0].name(\\\"newName\\\");\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#addPhone\\\").on(\\\"click\\\", function() {\\n people[0].addPhone(\\\"xxx xxx xxxx\\\");\\n $(\\\"#result\\\").html(tmpl.render(people));\\n});\\n\\n$(\\\"#result\\\").on(\\\"change\\\", \\\".comment\\\", function(val) {\\n // If comment is modified, update View Model state with new value\\n people[this.getAttribute(\\\"data-index\\\")].comment(this.value);\\n});\\n\\n$(\\\"#getData\\\").on(\\\"click\\\", function() {\\n var updatedPeopleData = people.unmap();\\n window.alert(JSON.stringify(updatedPeopleData));\\n});\\n\",\r\n \"html\": \"\\n\\n\\n\\n
                          \\n\\n\\n\\n
                          \\n\\n\",\r\n \"height\": \"350\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"anchor\": \"\",\r\n \"title\": \"Mapping from JSON data to View Model hierarchy – further features\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding a custom get/set property to a compiled View Model \",\r\n \"text\": \"Finally, here is a sample which extends a compiled *View Model* with a custom `Person.isManager() `*get/set* property. The property is coupled to the `Team.manager()` property -- so setting `Person.isManager(...)` will update the `Team.manager()` correspondingly (and conversely when setting `Team.manager(...)`.\\n\\n`Person.isManager` is not included in the `getters` declaration, so that the constructor for `Person` will not expect an `isManager` parameter to be provided for initialization.\\n\\n(See also the [related sample](#jsvviewmodelsapi@ismanagersample) using JsViews and data-linking.)\",\r\n \"anchor\": \"ismanagersample\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n// Custom function for Person.isManager get/set property\\nfunction myIsManager(val) {\\n if (!arguments.length) {\\n return this === team.manager(); // If there is no argument, use as a getter\\n }\\n if (val) {\\n // Make this team member manager\\n team.manager(this);\\n } else if (this.isManager()) {\\n // Set team manager to null\\n team.manager(null);\\n }\\n}\\n\\n// Compile View Models\\n$.views.viewModels({\\n Team: {...},\\n Person: {\\n getters: [\\n \\\"name\\\",\\n ...\\n ],\\n extend: {\\n isManager: myIsManager // use custom function\\n }\\n },\\n Address: {...}\\n});\\n\\n...\\n\\n//Initialize second team member to be manager.\\nvar manager = team.members()[1];\\nmanager.isManager(true);\\n\\n...\\n\\n// Attach handler for checkbox\\n$(\\\"#result\\\")\\n .on(\\\"change\\\", \\\".isManager\\\", function() {\\n ...\\n member.isManager(this.checked);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n ...\\n```\"\r\n }\r\n ],\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"// Compile template\\nvar tmpl = $.templates(\\\"#teamTmpl\\\");\\n\\n// Custom function for Person.isManager get/set property\\nfunction myIsManager(val) {\\n if (!arguments.length) {\\n return this === team.manager(); // If there is no argument, use as a getter\\n }\\n if (val) {\\n // Setting this.isManager() to true\\n // So make this team member manager\\n team.manager(this);\\n } else if (this.isManager()) {\\n // Setting this.isManager to false, and this team member is currently manager.\\n // So set team manager to null\\n team.manager(null);\\n }\\n}\\n\\n// Compile View Models\\n$.views.viewModels({\\n Team: {\\n getters: [\\n {\\n getter: \\\"manager\\\",\\n type: \\\"Person\\\"\\n },\\n {\\n getter: \\\"members\\\",\\n type: \\\"Person\\\"\\n }\\n ]\\n },\\n Person: {\\n getters: [\\n \\\"name\\\",\\n {\\n getter: \\\"address\\\",\\n type: \\\"Address\\\"\\n }\\n ],\\n extend: {\\n isManager: myIsManager // use custom function\\n }\\n },\\n Address: {\\n getters: [\\\"street\\\", \\\"ZIP\\\"]\\n }\\n});\\n\\n// Initial data \\nvar teamData = {\\n manager: null,\\n members: [{\\n name: \\\"Pete\\\",\\n address: {\\n street: \\\"1st Ave\\\",\\n ZIP: \\\"12345\\\"\\n }\\n },{\\n name: \\\"Bess\\\",\\n address: {\\n street: \\\"Central Way\\\",\\n ZIP: \\\"98765\\\"\\n }\\n },\\n {\\n name: \\\"Henry\\\",\\n address: {\\n street: \\\"Main St\\\",\\n ZIP: \\\"54321\\\"\\n }\\n }]\\n };\\n\\n// Instantiate View Models\\nvar team = $.views.viewModels.Team.map(teamData);\\n\\n//Initialize second team member to be manager.\\nvar manager = team.members()[1];\\nmanager.isManager(true);\\n\\nfunction renderTemplate() {\\n // Refresh template rendering completely\\n $(\\\"#result\\\").html(tmpl.render(team));\\n}\\n\\nrenderTemplate();\\n\\n// Attach handlers for checkbox and buttons\\n$(\\\"#result\\\")\\n .on(\\\"change\\\", \\\".isManager\\\", function() {\\n var memberIndex = $(this).data(\\\"index\\\"),\\n member = team.members()[memberIndex];\\n member.isManager(this.checked);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n .on(\\\"click\\\", \\\".changeManager\\\", function() {\\n var memberIndex = $(this).data(\\\"index\\\"),\\n member = team.members()[memberIndex];\\n member.isManager(true);\\n renderTemplate(); // Refresh rendering, with modified data\\n })\\n .on(\\\"click\\\", \\\".noManager\\\", function() {\\n team.manager(null);\\n renderTemplate(); // Refresh rendering, with modified data\\n }\\n);\",\r\n \"title\": \"Sample: extending Person with an isManager property\",\r\n \"height\": \"294\",\r\n \"jsrJsvJqui\": \"jsr\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvviewmodelsapi\",\r\n \"label\": \"Compiled View Models (JsViews)\"\r\n }\r\n ]\r\n }\r\n ]\r\n },\r\n \"lifecycle\": {\r\n \"title\": \"Life-cycle events\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"paragraph\"\r\n }\r\n ]\r\n },\r\n \"globals\": {\r\n \"title\": \"Global jQuery extensions\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*JsRender* adds the following extensions to the jQuery object, `$` (or to the `jsrender` namespace if using [JsRender without jQuery](#nojqueryapi)):\\n\\n- ***$.render:***\\n - See [`$.render.myTmpl()`](#d.render)\\n- ***$.templates:***\\n - See [`$.templates()`](#d.templates)\\n- ***$.views:***\\n - See [`$.views`](#viewsobject)\\n\\nIt also adds the following 'plugin' extension to jQuery instances:\\n\\n- ***$(\\\"#myTmpl\\\").render(...):***\\n - See [`$(\\\"#myTmpl\\\").render()`](#db.render)\\n\\nSee also [JsViews globals](#jsvglobals)\"\r\n }\r\n ]\r\n },\r\n \"tagsapi\": {\r\n \"title\": \"Registering custom tags: $.views.tags()\",\r\n \"path\": \"\",\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"`$.views.tags()` is used to register custom tags. See *[Using custom tags](#tags)* for an overview, and simple examples.\\n\\nThis topic provides more details, including sections:\\n\\n- [Registering custom tags](#tagsapi@register)\\n- [Custom tag options: Specifying init(), render(), template, baseTag](#tagsapi@options)\\n- [Tag context](#tagsapi@context)\\n- [Custom tag child views](#tagsapi@childviews)\\n- [Rendering else blocks](#tagsapi@elseblocks)\\n- [Custom tag hierarchy](#tagsapi@parents)\\n- [Accessing contextual parameters and helpers](#tagsapi@ctxparams)\\n- [Advanced options](#tagsapi@advanced)\\n- [Methods and properties available on a custom tag instance](#tagsapi@instanceprops)\\n- [Adding tags as private resources for a parent template](#tagsapi@privatetags)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"What is a custom tag?\",\r\n \"text\": \"JsRender custom tags are named tags `{{mytag ...}}`, which you can register, and then use in your templates.\\n\\nA custom tag can optionally use arguments (*args*) and named properties (*props*), [as in](#tagsyntax@tagparams):\\n\\n```jsr\\n{{mytag arg0 arg1 namedProp1=xxx namedProp2=yyy}} ... {{/mytag}}\\n```\\n\\n*__Note:__* When you also use JsViews, custom tags acquire a whole new dimension. -- They become [*tag controls*](#jsvtagcontrols), and you can build rich and complex single page apps cleanly and simply using custom tag controls -- following an MVP or MVVM coding pattern. \"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying tag options for a custom tag\",\r\n \"text\": \"The following tag declaration registers a `{{mytag}}` custom tag:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", tagOptions);\\n```\\n\\nThe `tagOptions` object (hash) specifies the tag options and determines how the tag will function. It can include:\\n\\n- An [init()](#tagsapi@init) method: `init: tagInitFn`\\n- A [render()](#tagsapi@render) method: `render: tagRenderFn`\\n- A [template](#tagsapi@template): `template: tagTemplate`\\n\\nIn addition `tagOptions` can specify tag inheritance (so that the custom tag derives from a base tag):\\n\\n- [`baseTag: ...`](#tagsapi@basetag)\\n\\nIt can also specify the following more advanced options:\\n\\n- [`contentCtx: ...`](#tagsapi@contentctx)\\n- [`convert: ...`](#tagsapi@convert)\\n- [`argDefault: ...`](#tagsapi@argdefault)\\n- [`bindTo: ...` / `bindFrom: ...`](#tagsapi@bindto)\\n- [`flow: ...`](#tagsapi@flow)\\n- [`ctx: ...`](#tagsapi@ctx)\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Registering custom tags: $.views.tags(...)\",\r\n \"text\": \"To register a custom tag, you call the `$.views.tags(...)` API.\\n\\nThere are four alternative signatures:\\n\\n- `$.views.tags(\\\"mytag\\\", tagOptions);` -- where the properties of the `tagOptions` object will typically include a `render: tagRenderFn` (specifying a render() method), and/or a `template: tagTemplate` (specifying a template to be rendered)\\n- `$.views.tags(\\\"mytag\\\", tagRenderFn);` -- simplified form, when the only option being specified is a render() method\\n- `$.views.tags(\\\"mytag\\\", tagTemplate);` -- simplified form, when the only option being specified is a tag template to be rendered\\n- `$.views.tags(namedTags);` This version is for declaring multiple custom tags, and `namedTags` is a hash (with custom tag names as keys and `tagOption` objects as values)\\n\\nHere are the details:\",\r\n \"anchor\": \"register\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"$.views.tags(...)\",\r\n \"name\": \"tags\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagOptions\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"A tagOptions object with a render() method and/or a template property, and optionally other properties or methods\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", {\\n render: function(...) {...},\\n template: ...\\n});\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a custom tag, specifying chosen tag options\",\r\n \"returns\": \"\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagRenderFn\",\r\n \"type\": \"function\",\r\n \"optional\": false,\r\n \"description\": \"Tag render() method. Returns the rendered tag\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", function(...) {\\n ...return rendered content\\n});\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a simple 'render' function as a custom tag\",\r\n \"returns\": \"\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"name\",\r\n \"type\": \"string\",\r\n \"optional\": false,\r\n \"description\": \"name of tag - to be used in template markup: {{name ...}}\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"tagTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": false,\r\n \"description\": \"A string containing template markup to be rendered by the tag (or a selector for a script block template definition, or a compiled template object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags(\\\"mytag\\\", \\\"templateMarkup...\\\");\\n\\n{{mytag ...}} ... {{/mytag}}\",\r\n \"description\": \"Register a template as a custom tag\",\r\n \"returns\": \"\"\r\n },\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTags\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of tag) and values (render function, template, or tagOptions object)\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags({\\n mytag1: {\\n render: function(val) {...},\\n template: ...\\n },\\n mytag2: function(val) {...},\\n mytag3: tag3TemplateString,\\n});\",\r\n \"description\": \"Register multiple custom tags\",\r\n \"returns\": \"\"\r\n }\r\n ],\r\n \"description\": \"Register one or more custom tags\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"For simple samples showing the above alternative `$.views.tags(...)` signatures, see the [*Using custom tags*](#tags) overview topic:\\n\\n- [A custom tag using just a render() method](#tags@render-sample)\\n- [A custom tag using just a template](#tags@template-sample)\\n- [Accessing context within the render() method](#tags@context-sample)\\n- [Accessing context from the tag template](#tags@tmplcontext-sample)\\n\\nThe [*Using custom tags*](#tags) overview also provides samples of custom tags which render block content -- `{{mytag}}...{{/mytag}}`:\\n\\n- [Rendering block content from a custom tag render() method](#tags@renderblock-sample)\\n- [Rendering block content from a custom tag template](#tags@tmplblock-sample)\\n- [A {{runningTotal}} custom tag, using a render() method](#tags@runningtotal-sample)\\n- [A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"](#tags@renderplustmpl-sample)\",\r\n \"anchor\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag options: Specifying init(), render(), template, baseTag:\",\r\n \"text\": \"A custom tag in JsRender has a very simple *'life-cyle'* consisting of two events for which you can optionally provide event handlers: the `init()` event, followed by the `render()` event. (If the custom tag is used in the context of JsViews, additional lifecycle events will also come into play, for data-binding, disposal, etc.)\",\r\n \"anchor\": \"options\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing an init() method\",\r\n \"text\": \"The *init()* method acts as a handler for the *init* event of the custom tag, and is called with the tag instance as `this` parameter.\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx, linkCtx, ctx) { ... },\\n ...\\n});\\n``` \\n\\nThe *init()* method arguments are:\\n- `tagCtx`: the [tagCtx object](#tagctxobject), also available as `this.tagCtx`\\n- `linkCtx`: always 0 unless using [data-linked tags](#linked-tag-syntax) with *JsViews* (See [linkCtx object](#linkctxobject).)\\n- `ctx`: [View context object](#ctxobject)\\n\\nThe following example uses the *init()* method to set the tag template based on the value of the `mode` prop:\",\r\n \"anchor\": \"init\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.template = tagCtx.props.mode === \\\"a\\\"\\n ? \\\"template A ...\\\"\\n : \\\"template B ...\\\";\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{mytag name mode='a' /}}\\n{{mytag name mode='b' /}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.template = tagCtx.props.mode === \\\"a\\\"\\n ? \\\"template A: {{:}} aaa
                          \\\"\\n : \\\"template B: {{:}} bbb
                          \\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render({name: \\\"Jo\\\"});\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"60\",\r\n \"anchor\": \"initsample\",\r\n \"title\": \"Providing init()\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a render() method\",\r\n \"text\": \"The *render()* method acts as a handler for the *render* event of the custom tag, and is called with the tag instance as `this` parameter, and with arguments `arg1, arg2, ...`, corresponding to the unnamed arguments passed in the tag markup, `{{mytag expression1 expression2 ... }}`.\\n\\nIf no arguments are passed in the markup, then the `render()` method will be called with the current data context as argument (unless modified by the [argDefault](#tagsapi@argdefault) option.)\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function(value1, value2) { ... return ...; },\\n ...\\n});\\n```\\n\\nThe *render()* method can optionally be used to define how the tag renders, by returning an HTML markup string.\\n\\nSee the example: [*A custom tag using just a render() method*](#tags@render-sample).\\n\",\r\n \"anchor\": \"render\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a template\",\r\n \"text\": \"The *template* option is used for declarative rendering, as an alternative to providing a *render()* method.\\n\\nSee the example: [*A custom tag using just a template*](#tags@template-sample).\\n\",\r\n \"anchor\": \"template\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Data context of a tag template\",\r\n \"text\": \"If the custom tag is called with an argument: `{{mytag someArgument ...}}` then the template will be rendered using the value of that argument as data context.\\n\\nOtherwise, the data context will be the same as the outer data context.\\n\\n(*Note:* This behavior can be changed using [contentCtx](#tagsapi@contentctx)) \\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Using both a template and a render() method\",\r\n \"text\": \"If the tag has both a *render()* method and a *template*, then the *render()* method is used to render the tag. But if *render()* returns `undefined` (or has no return value), then the *template* is used. \\n\\nSee example: [*A {{runningTotal}} custom tag, with render() method and a template as \\\"fallback\\\"*](#tags@renderplustmpl-sample).\\n\\nIt is also possible to provide both a *template* and a *render()* method, and to make use of the rendered template within the content returned by the render method. (In fact `this.tagCtx.render(...)` will return the rendered template). \",\r\n \"anchor\": \"tmpl-fallback\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying tag inheritance: the baseTag option\",\r\n \"text\": \"A custom tag can inherit from another tag (either built-in or custom).\\n\\nFor example the `{{runningTotal}}` sample, linked above, can be rewritten in a more powerful but compact form, by making it inherit from the `{{for}}` tag (since the functionality of iterating over an array is common to both).\\n\\nTo inherit from another tag, set the `baseTag` option to the name of the tag you want to derive from:\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ...\\n});\\n```\\n\\nCustom tag methods (*init()* or *render()*) can invoke the corresponding base tag method by calling one of the following API variants:\\n\\n```js\\nthis.base(a, b, ...); // Pass chosen arguments\\nthis.baseApply(arguments); // Pass on the calling arguments (or an array of args)\\n```\\n\\nThis is illustrated in the following sample, which takes the *Providing init()* [sample](#tagsapi@initsample) above, and defines a derived `{{mytag2}}` which overrides *init()* and adds an error message when no valid `mode` was specified:\\n\",\r\n \"anchor\": \"basetag\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"mytag2\\\", {\\n baseTag: \\\"mytag\\\",\\n init: function() { // Override the init() method\\n this.baseApply(arguments); // Call the base method\\n this.template = this.template || \\\"Error: Specify mode 'a' or 'b'\\\"; // If no template was assigned, render error message\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{mytag2 name mode='a' /}}\\n{{mytag2 name mode='b' /}}\\n{{mytag2 name /}}\\n```\"\r\n }\r\n ],\r\n \"html\": \"\\n\\n
                          \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n init: function(tagCtx) {\\n this.templates = {\\n a: \\\"template A: {{:}} aaa
                          \\\",\\n b: \\\"template B: {{:}} bbb
                          \\\"\\n }; \\n this.template = this.templates[tagCtx.props.mode];\\n }\\n});\\n\\n$.views.tags(\\\"mytag2\\\", {\\n baseTag: \\\"mytag\\\",\\n init: function() { // Override the init() method\\n this.baseApply(arguments); // Call the base method\\n // If no template was assigned, render error message\\n this.template = this.template || \\\"Error: Specify mode 'a' or 'b'\\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render({name: \\\"Jo\\\"});\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"75\",\r\n \"anchor\": \"basetagsample\",\r\n \"title\": \"baseTag\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The previous `{{runningTotal}}` [sample](#tags@renderplustmpl-sample) was relatively complex. Here is an updated version rewritten to derive from `{{for}}`:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"This version is much simpler and supports sorting, filtering, etc. as well as `start=... end=... step=...`, without any additional code (thanks to the inherited features of `{{for}}`).\\n\\nAlso the fallback rendering for *No line items* is no longer hard-coded in the tag, but instead uses the `{{runningTotal}}...{{else}}...` pattern.\\n\\nNote that `~total()` is a function. The call to `~total()` increments the value and returns the running total.\\n\\n*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function() { // A ~total() helper (now a function)\\n ...\\n tag.totalVal += this.data[totalCol]; // Compute running total\\n return tag.totalValue; // Return value from ~total()\\n }\\n },\\n render: function() {\\n this.totalVal = 0; // Initialize total before rendering\\n return this.baseApply(arguments); // Render\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{runningTotal lineItems start=1 end=4 totalColumn=\\\"quantity\\\"}} \\n ...{{:~total()}}...\\n{{else}}\\n ...No line items...\\n{{/runningTotal}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"244\",\r\n \"title\": \"A {{runningTotal}} custom tag derived from {{for}}\",\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"html\": \"
                          \\n\\n\",\r\n \"code\": \"$.views.tags(\\\"runningTotal\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function() { // A ~total() helper (now a function)\\n var tag = this.ctx.tag,\\n totalCol = tag.tagCtx.props.totalColumn\\n tag.totalVal += this.data[totalCol]; // Compute running total\\n return tag.totalVal; // Return value from ~total()\\n }\\n },\\n render: function() {\\n this.totalVal = 0; // Initialize total before rendering\\n return this.baseApply(arguments); // Render\\n }\\n});\\n\\nvar data = {\\n lineItems: [\\n {category: \\\"book\\\", quantity: 2, price: 3.40},\\n {category: \\\"grocery\\\", quantity: 5, price: 1.01},\\n {category: \\\"grocery\\\", quantity: 2, price: 13.10},\\n {category: \\\"book\\\", quantity: 1, price: 12.50}\\n ],\\n lineItems2: []\\n};\\n\\nvar html = $(\\\"#myTmpl\\\").render(data, {\\n category: function(item, index, items) {\\n return item.category === this.props.category;\\n }\\n});\\n\\n$(\\\"#lineItems\\\").html(html);\",\r\n \"anchor\": \"derivedfor\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Our `{{runningTotal}}` [samples](#tagsapi@derivedfor) so far have initialized the running total to `0` in the render method, and then relied on the rendering process to do the incrementing of the running total. This approach would fail if the rendering sequence was changed for any reason.\\n\\nThe sample below takes the `{{runningTotal}}` tag above, and converts it to a more complete and more powerful \\n `{{purchases}}` tag, again deriving from the `{{for}}` tag. The `{{purchases}}` tag, which is more flexible and more robust, and supports any number of running total columns.\\n\\nThe `~total(expression)` helper function now allows you to provide any expression as parameter. Here, running total values are recomputed for each line, separately, so no longer depend on the render processing sequence:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The `~total(expr)` helper function now accepts an *expression* parameter for each running total -- to be used to compute the incremental amount for each row.\\n\\n*Tag declaration:*\\n\\n```js\\n$.views.tags(\\\"purchases\\\", {\\n baseTag: \\\"for\\\",\\n ctx: {\\n total: function(expr) { // A ~total(expression) helper\\n var tmpl = $.templates[expr] // Get named compiled template for expression, or else...\\n || $.templates(expr, \\\"{{:\\\" + expr + \\\"}}\\\"), // ...if this is first call, create it\\n\\n runningTotal = 0,\\n view = this, // The content view with the ~total(...) helper call\\n items = view.get(\\\"array\\\").data,\\n rowIndex = view.getIndex();\\n\\n for (var i = 0; i <= rowIndex; i++) {\\n runningTotal += +tmpl(items[i]); // Compute running total up to this row, using render function\\n } // of compiled tmpl (either tmpl() or tmpl.render()...)\\n return runningTotal; // Return value from ~total(...)\\n }\\n }\\n});\\n```\\n\\n*Tag usage:*\\n\\n```jsr\\n{{purchases lineItems sort=\\\"category\\\" ...}} \\n ...{{:~total('quantity*price')}}...\\n{{else}}\\n ...No items...\\n{{/purchases}}\\n```\\n\"\r\n }\r\n ],\r\n \"header\": \"\",\r\n \"action\": \"append\",\r\n \"html\": \"\",\r\n \"code\": \"\",\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"550\",\r\n \"url\": \"samples/jsrender/tags/extend-for/sample\",\r\n \"title\": \"A {{purchases}} tag supporting totals for any expression\",\r\n \"anchor\": \"totals-expr\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The above `{{purchases}}` custom tag can be easily updated to support data-binding. See [purchases sample](#samples/tag-controls/purchases@jsv).\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag context\",\r\n \"text\": \"When a custom tag is used in a template then the rendered template instance will be part of the [view hierarchy](#views).\\n\\nThe instance of the tag is an object with properties and methods:\\n\\n- [tag object](#tagobject)\\n\\nAssociated with the tag instance is a [tag context object](#tagctxobject), `tagCtx`, providing most of the useful context for a tag, in particular:\\n\\n- context passed down through the view hierarchy:\\n\\n - current view\\n - current data\\n - parent tags\\n - [contextual parameters](#contextualparams)
                          (see also [*Accessing contextual parameters and helpers*](#tagsapi@ctxparams))\\n\\n- additional context coming from the tag itself, or its markup:\\n\\n - arguments (*args*) and named properties (*props*)\\n - rendered tag template\\n - block content\\n - content of else blocks\\n\",\r\n \"anchor\": \"context\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag instance object\",\r\n \"text\": \"From a tag method (*init()* or *render()*), the `this` pointer is the instance of the tag (a [tag object](#tagobject).)\\n\\nFrom a tag template, the tag instance can be accessed as `~tag`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag context object: tagCtx\",\r\n \"text\": \"From a tag method the `tagCtx` object is available as `this.tagCtx`.\\n\\nIn the [*init()*](#tagsapi@render) method it is also passed directly as an argument (`function(tagCtx ...)`).\\n\\nFrom a tag template, `tagCtx` can be accessed as `~tagCtx`.\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the tag arguments or named properties\",\r\n \"text\": \"The values of arguments can be accessed as `tagCtx.args`, and named properties as `tagCtx.props`.\\n\\nFor example, if we have the following tag, which has two arguments and one named property:\\n\\n```jsr\\n{{sometag title name mode=\\\"edit\\\"}}\\n```\\n\\nthen from within the *init()* or *render()* method of `sometag`, the arguments and named properties can be accessed as:\\n\\n```js\\nvar title = this.tagCtx.args[0];\\nvar name = this.tagCtx.args[1];\\nvar mode = this.tagCtx.props.mode;\\n```\\n\\nand from the tag template, the values can be accessed as `~tagCtx.args` or `~tagCtx.props`, and so might be rendered as: \\n\\n```jsr\\n...title: {{>~tagCtx.args[0]}}
                          name: {{>~tagCtx.args[1]}}
                          mode: {{>~tagCtx.props.mode}}...\\n```\\n\\nIn addition to being available as `tagCtx.args`, arguments are also passed directly as arguments to the *render()* method, so `sometag` might use the following *render()* method, rather than a template, to render similar content:\\n\\n```js\\nfunction sometagRenderMethod(title, name) {\\n return \\\"...title: \\\" + title + \\\"
                          name: \\\" + name + \\\"
                          mode: \\\" + this.tagCtx.props.mode ...;\\n}\\n```\\n\\nThe `tagCtx` object also provides access to the markup expression for arguments and named properties, as `tagCtx.params.args` and `tagCtx.params.props`.\\n\\n(*Note:* Tag property names can include `_` and `.` characters, as in `{{mytag some_.name=... /}}`. If the name includes `.` characters, use the syntax `tagCtx.props[\\\"some_.name\\\"];` to access the value.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing the parent view and the current data\",\r\n \"text\": \"The contextual (parent) view for the tag instance is accessed as `tagCtx.view`. The corresponding (parent) data context is `tagCtx.view.data`.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag child views\",\r\n \"text\": \" \",\r\n \"anchor\": \"childviews\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag rendering with template: \\\"mytag\\\" child view\",\r\n \"text\": \"A custom tag template instance will be part of the [view hierarchy](#views), and the rendered tag may add additional child views to the view hierarchy.\\n\\nIf `{{mytag members}}` renders using its *template*, that template will render as a child view (of type `\\\"mytag\\\"`). The default data context within the *template* will be the first argument passed to the tag (`members` in this case) which will be the `view.data` property of the child view.\\n\\nIf the *template* markup includes template tags (other custom tags, or built-in tags) then there will be corresponding additional child views below the *mytag* view. \\n\\n\",\r\n \"anchor\": \"tagview\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering wrapped block content\",\r\n \"text\": \"- Any tag can wrap [block content](#tagsyntax@blocktag), or use `tmpl=...` to reference external content:\\n ```jsr\\n {{mytag}}...{{/mytag}}\\n\\n {{mytag tmpl=... /}}\\n ```\\n- By default, a custom tag with no *render()* method or tag template will render its block content unchanged. A tag with an argument will move data context to the data passed in the argument: `{{mytag somedata ...}}`.\\n- For a custom tag rendering using a *render()* method, wrapped block content can be included using `tagCtx.render()`.

                          *Note:* To set the inner data context, pass in data as argument: `tagCtx.render(someData)`. Otherwise inner and outer data context are the same.\\n ```js\\n $.views.tags(\\\"mytag\\\", {\\n ...\\n render: function() {\\n return ... + this.tagCtx.render() + ...;\\n },\\n ...\\n });\\n ```\\n See the sample: [*Rendering block content from a custom tag render() method*](#tags@renderblock-sample).

                          \\n (For advanced scenarios the block content is also available as a compiled template object: `tagCtx.content`, so can be rendered using `tagCtx.content.render()`. See the [template as fallback](#tags@tmpl-fallback) sample).

                          \\n- For a custom tag rendering using a tag template, wrapped block content can be included using:\\n ```jsr\\n {{include tmpl=#content/}}\\n ```\\n or equivalently:\\n ```jsr\\n {{include tmpl=~tagCtx.content/}}\\n ```\\n where in each case the inner data context can be modified by passing an argument, `{{include someData tmpl=... /}}`.\\n See the sample: [*Rendering block content from a custom tag template*](#tags@tmplblock-sample).\\n\\nNote that if a custom tag has an external `tmpl=...` reference, **_and_** inline block content, then the external template takes precedence. However, the external template can behave as a wrapper, wrapping the inline block content (see: [*Wrapping content*](#tagsyntax@wrap)).\\n\\nThis can provide for cascading content, as in the following sample:\\n\\n```jsr\",\r\n \"anchor\": \"wrapping\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```js\\n$.views.tags(\\\"mytag\\\", {\\n template: \\\"mytagStart...{{include tmpl=#content/}}.../mytagEnd\\\"\\n});\\n```\\n```jsr\\n{{mytag tmpl='#external'}}wrappedContent{{/mytag}}\\n```\\n\\n```jsr\\n\\n\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n\\n\\n
                          \\n\",\r\n \"code\": \"$.views.tags(\\\"mytag\\\", {\\n template: \\\"mytagStart
                          {{include tmpl=#content/}}
                          /mytagEnd\\\"\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {},\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"106\",\r\n \"title\": \"Cascading content\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Rendering else blocks\",\r\n \"text\": \"Any tag can use [`{{else}}`](#elsetag) blocks. We might for example create a custom tag for rendering lists:\\n\\n```jsr\\n{{list}}\\n First item\\n{{else}}\\n Second item\\n{{else}}\\n Last item\\n{{/list}}\\n```\\n\\nA custom tag can provide specific behavior/rendering for `{{else}}` blocks:\\n\\n- For a tag with a render method, *render()* will be called once for the initial block and once for each `{{else}}` block.\\n- Similarly, for a custom tag with a tag template, the template will be rendered once for the initial block and once for each `{{else}}` block.\\n- During rendering a custom tag can detect which block is being rendered, using `tagCtx.index` (see below), and can then output the content corresponding to the desired functionality.\\n\",\r\n \"anchor\": \"elseblocks\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Tag context objects for {{else}} blocks: the tagCtxs array\",\r\n \"text\": \"A tag with multiple blocks (initial block plus 1 or more `{{else}}` blocks) will have a `tagCtxs` array of `tagCtx` objects, one for each block.\\n\\n- From a tag method the `tagCtxs` array is available as `this.tagCtxs`.\\n- From a tag template, `tagCtxs` can be accessed as `~tag.tagCtxs`.\\n\\nEach `tagCtx` object in `tagCtxs` has an `index` property (`0` for the initial block), as well as the other properties (`args`, `props` etc.) corresponding to the markup (arguments, named properties...) on the corresponding tag (`{{mytag ...}}` or `{{else ...}}`).\\n\\n- Within a tag *render()* method, `this.tagCtx` will be the current tag context object for that block.\\n- Similarly, during rendering of the tag template, `~tag.tagCtx` will be the current `tagCtx`.\\n\\nTo determine the index of the block being rendered, use `tagCtx.index`. \\n\\nThese features are illustrated in the following sample:\",\r\n \"anchor\": \"tagctxs\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Custom `{{list}}` tag:*\\n\\n```js\\n$.views.tags(\\\"list\\\", function() {\\n // render() method\\n var ret = \\\"\\\", // Return value\\n index = this.tagCtx.index, // block index\\n listElem = this.tagCtxs[0].props.numbered ? \\\"ol\\\" : \\\"ul\\\"; // Wrapper
                            or
                              element, based on numbered=true property \\n\\n if (index===0) {\\n ret += \\\"<\\\" + listElem + \\\">\\\"; // First block: add opening wrapper\\n }\\n ret += \\\"
                            • \\\" + this.tagCtx.render() + \\\"
                            • \\\"; // Add li element and block content\\n if (index===this.tagCtxs.length-1) {\\n ret += \\\"\\\"; // Last block: add closing wrapper\\n }\\n return ret;\\n});\\n```\\n\\n*Usage*:\\n\\n```jsr\\n{{list numbered=true}}First{{else}}Second{{else}}Last{{/list}}\\n{{list}}first{{else}}last{{/list}}\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"code\": \"// Define custom {{list}} tag\\n$.views.tags(\\\"list\\\", function() {\\n // render() method\\n var ret = \\\"\\\", // Return value\\n index = this.tagCtx.index, // block index\\n listElem = this.tagCtxs[0].props.numbered ? \\\"ol\\\" : \\\"ul\\\"; // Wrapper
                                or
                                  element, based on numbered=true property \\n\\n if (index===0) {\\n ret += \\\"<\\\" + listElem + \\\">\\\"; // First block: add opening wrapper\\n }\\n ret += \\\"
                                • \\\" + this.tagCtx.render() + \\\"
                                • \\\"; // Add li element and block content\\n if (index===this.tagCtxs.length-1) {\\n ret += \\\"\\\"; // Last block: add closing wrapper\\n }\\n return ret;\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render();\\n\\n$(\\\"#page\\\").html(html);\\n\",\r\n \"html\": \"\\n\\n
                                  \\n\\n\",\r\n \"height\": \"130\",\r\n \"title\": \"Custom {{list}} tag using {{else}} blocks\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"And here is a version of the sample with the same tag implemented using a tag template, rather than a *render()* method.\\n\\nHere we use the *init()* method to assign a tag template dynamically, using a different wrapper (`ol` or `ul`) based on the `numbered` named property:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"*Custom `{{list}}` tag:*\\n \\n```js\\n$.views.tags(\\\"list\\\", {\\n init: function() {\\n var listElem = this.tagCtx.props.numbered ? 'ol' : 'ul'; // Wrapper ol or ul element\\n this.template = \\n // First block: add opening wrapper\\n \\\"{{if ~tagCtx.index===0}}<\\\" + listElem + \\\">{{/if}}\\\"\\n // Add li element and block content\\n + \\\"
                                • {{include tmpl=#content/}}
                                • \\\"\\n // Last block: add closing wrapper\\n + \\\"{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}\\\";\\n }\\n});\\n```\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"height\": \"130\",\r\n \"title\": \"Custom {{list}} tag: Rendering {{else}} blocks from a tag template\",\r\n \"html\": \"\\n\\n
                                  \\n\\n\",\r\n \"code\": \"// Define custom {{list}} tag\\n$.views.tags(\\\"list\\\", {\\n init: function() {\\n var listElem = this.tagCtx.props.numbered ? 'ol' : 'ul'; // Wrapper ol or ul element\\n this.template = \\n // First block: add opening wrapper\\n \\\"{{if ~tagCtx.index===0}}<\\\" + listElem + \\\">{{/if}}\\\"\\n // Add li element and block content\\n + \\\"
                                • {{include tmpl=#content/}}
                                • \\\"\\n // Last block: add closing wrapper\\n + \\\"{{if ~tagCtx.index===~tag.tagCtxs.length-1}}{{/if}}\\\";\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n html = myTmpl.render();\\n\\n$(\\\"#page\\\").html(html);\\n\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Custom tags with no *render()* method and no tag template can also render multiple blocks, using `{{else}}`. Here is an example:\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"Custom `{{mytag}}` which simply renders each block as is:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {});\\n```\\n\\nThe default data context of each block is the value passed to the first argument.\\n\\n```jsr\\n{{mytag last}}\\n First: {{:}}...\\n{{else first}}\\n ...\\n{{else phone}}\\n ...\\n{{/mytag}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                                  \\n\\n\",\r\n \"code\": \"// Define custom {{mytag}} tag\\n$.views.tags(\\\"mytag\\\", {});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = {first: \\\"Jo\\\", last: \\\"Blow\\\", phone: \\\"111-111-1111\\\"},\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\\n\\n\",\r\n \"title\": \"Default behavior for custom tag with {{else}} blocks\",\r\n \"height\": \"72\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tag hierarchy – Accessing parent tags\",\r\n \"text\": \"Custom tags form a hierarchy, and can be designed with functionality or rendering that is based on parent or child tags within that hierarchy, as in the following example where a `{{layout}}` tag determines the layout for child `{{cell}}` tags:\\n\",\r\n \"anchor\": \"parents\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{layout 'vertical'}}\\n {{cell}}one{{/cell}}\\n {{cell}}two{{/cell}}\\n{{/layout}}\\n
                                  \\n{{layout 'horizontal'}}\\n {{cell}}one{{/cell}}\\n {{cell}}two{{/cell}}\\n{{/layout}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                                  \",\r\n \"code\": \"$.views.tags({\\n layout: {\\n render: function(mode) {\\n if (mode === \\\"vertical\\\") {\\n this.vertical = true;\\n return \\\"\\\" + this.tagCtx.render() + \\\"
                                  \\\";\\n } else {\\n return \\\"\\\" + this.tagCtx.render() + \\\"
                                  \\\";\\n }\\n }\\n },\\n cell: {\\n render: function() {\\n return this.parents.layout.vertical\\n ? \\\"\\\" + this.tagCtx.render() + \\\"\\\"\\n : \\\"\\\" + this.tagCtx.render() + \\\"\\\";\\n }\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = { name: \\\"Jo\\\" },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"height\": \"140\",\r\n \"header\": \"\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"The following properties provide access to ancestor custom tags:\\n\\n**parents property:**\\n\\nThe [`parents`](#tagobject@parents) property is a hash of all the ancestor custom tags. In the above sample the `{{cell}}` instances have a `{{layout}}` ancestor tag, which can be accessed from the `this.parents` hash, as `this.parents.layout`. In the sample this is used to determine whether the assigned layout is vertical, and to render accordingly:\\n\\n```js\\nrender: function() {\\n return this.parents.layout.vertical\\n ? \\\"\\\" + this.tagCtx.render() + \\\"\\\"\\n : \\\"\\\" + this.tagCtx.render() + \\\"\\\";\\n}\\n```\\n\\n**parent property:**\\n\\nThe tag instance also has a [`parent`](#tagobject@parent) property -- which is the nearest ancestor custom tag. In the above sample, the `parent` of the `{{cell}}` instance is the `{{layout}} instance`, so we could have replaced `this.parents.layout...` by `this.parent...`, in the above code.\\n\\n**~parentTags contextual parameter:**\\n\\nThe `ctx` property of a tag instance also has a `parentTags` property, equivalent to the `parents` hash. This can be used in the following alternative implementation of the `{{cell}}` tag above, using a tag template rather than a *render()* method:\\n\\n```js\\n$.view.tags(\\\"cell\\\", {\\n template:\\n \\\"{{if ~parentTags.layout.vertical}}{{include tmpl=#content/}}\\\"\\n + \\\"{{else}}{{include tmpl=#content/}}{{/if}}\\\"\\n});\\n```\\n\\nIn fact, in a tag template `~parentTags` and `~tag.parents` are equivalent.\\n\\n**Note:** The tag hierarchy accessed using the above properties such as `tag.parent` consists *__only__* of custom tags. More precisely, it is the hierarchy of [*non-flow tags*](#tagsapi@flow). The built-in tags (`{{for}}`, `{{if}}` etc.) are all flow tags (`flow: true`) whereas custom tags by default have `flow: false`.\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Accessing contextual parameters and helpers\",\r\n \"text\": \"- From a tag template:\\n - [Contextual parameters](#contextualparams) and helpers can be accessed using `~myParamOrHelper`\\n- From a tag method:\\n - Contextual parameters and helpers can be accessed using `this.ctxPrm(\\\"myParamOrHelper\\\")`\\n - (Note: contextual parameters can also be accessed using `this.ctx.myParamOrHelper`, and global helpers can be accessed using `$views.helpers(\\\"myHelper\\\")`)\\n\\n(See also [*Tag Context*](#tagsapi@context))\\n\\nAs an advanced example of custom tag rendering based on contextual parameters, here is a modified version of the above *layout* sample, where instead of wrapping `{{cell}}` tags in a `{{layout}}` tag, we instead wrap in a simple `{{include}}` on which we set a contextual parameter specifying layout: `layout='vertical'`:\",\r\n \"anchor\": \"ctxparams\"\r\n },\r\n {\r\n \"_type\": \"sample\",\r\n \"typeLabel\": \"Sample:\",\r\n \"codetabs\": [],\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"links\": \"links\"\r\n },\r\n \"sections\": [\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"```jsr\\n{{include ~layout='vertical'}}\\n {{cell}}one{{/cell}}\\n {{cell last=true}}two{{/cell}}\\n{{/include}}\\n
                                  \\n{{include ~layout='horizontal'}}\\n {{cell}}one{{/cell}}\\n {{cell last=true}}two{{/cell}}\\n{{/include}}\\n```\\n\"\r\n }\r\n ],\r\n \"jsrJsvJqui\": \"jsr\",\r\n \"html\": \"\\n\\n
                                  \",\r\n \"code\": \"$.views.tags({\\n cell: {\\n render: function() {\\n var res = \\\"\\\",\\n vertical = this.ctxPrm(\\\"layout\\\") === \\\"vertical\\\",\\n parentView = this.tagCtx.view.parent,\\n cellIndex = parentView.cellIndex = parentView.cellIndex === undefined ? 0 : parentView.cellIndex +1;\\n if (vertical) {\\n if (cellIndex===0) {\\n res += \\\"\\\";\\n }\\n res += \\\"\\\";\\n if (this.tagCtx.props.last) {\\n res += \\\"
                                  \\\" + this.tagCtx.render() + \\\"
                                  \\\";\\n }\\n } else {\\n if (cellIndex===0) {\\n res += \\\"
                                  \\\";\\n }\\n res += \\\"\\\";\\n if (this.tagCtx.props.last) {\\n res += \\\"
                                  \\\" + this.tagCtx.render() + \\\"
                                  \\\";\\n }\\n }\\n return res;\\n }\\n }\\n});\\n\\nvar myTmpl = $.templates(\\\"#myTmpl\\\"),\\n data = { name: \\\"Jo\\\" },\\n html = myTmpl.render(data);\\n\\n$(\\\"#page\\\").html(html);\",\r\n \"header\": \"\",\r\n \"height\": \"140\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"\",\r\n \"text\": \"(*Note:* Contextual parameter names can include `_` and `.` characters, as in `{{mytag ~some_.name=... /}}`. If the name includes `.` characters, use the syntax `ctx[\\\"some_.name\\\"];` to access the value.)\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Advanced options\",\r\n \"text\": \" \",\r\n \"anchor\": \"advanced\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying data context within tag content: the contentCtx option\",\r\n \"text\": \"*__Default behavior:__*\\n\\nBy default the data context within the tag is the value of the first argument. (See [View hierarchy -- inner data context](#views@innerdata)).\\n\\nSo if `{{mytag}}` uses a `template` then `{{mytag members/}}` will render the template with `members` as data context. \\n\\nSimilarly if `{{mytag}}` is used as a block tag, then the block content within `{{mytag members}}...{{/mytag}}` will render with `members` as data context.\\n\\n*__Modified behavior:__*\\n\\nTo make the data context for tag content the same as parent context, set the `contentCtx` option to `true`:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n contentCtx: true, // The data context inside {{mytag}} will be the same as the outer context\\n ...\\n});\\n```\\n\\nTo specify a different data context for tag content, set the `contentCtx` option to a function returning the chosen data. (The `this` pointer of the `contentCtx` function is the tag instance. The default data context, `arg0` is passed to it as argument.) \\n\\nFor example, with the following tag option setting, the inner data context is given by the `dataCtx` named property:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n contentCtx: function(arg0) {\\n return this.tagCtx.props.dataCtx; // The returned value will be the data context inside {{mytag}}\\n },\\n ...\\n});\\n```\\n\\nUsage:\\n\\n```jsr\\n{{mytag ... dataCtx=.../}}\\n``` \",\r\n \"anchor\": \"contentctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Providing a default converter: the convert option\",\r\n \"text\": \"On any tag, including custom tags, a converter can be specified directly on the tag (see [*Using converters with other tags*](#converters@othertags)):\\n\\n```jsr\\n{{mytag name convert='toUpperCase'/}}\\n```\\n\\nTo provide a default converter on a custom tag (used as fallback if no converter is specified on the tag), set the `convert` tag option to a function, or to a registered converter name:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n ...\\n convert: 'toLowerCase', // Default converter. (A function or a registered converter name)\\n ...\\n});\\n```\\n\\n\\n\\n\",\r\n \"anchor\": \"convert\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying a default argument: the argDefault option\",\r\n \"text\": \"If a custom tag uses a *render()* method, then the arguments of the tag are passed to the render method:\\n\\n```jsr\\n{{mytag arg0 arg1/}}\\n```\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function(arg0, arg1) {...}\\n});\\n```\\n\\nIf the tag is called without arguments, then the render method will be called with the current data context as first argument, so therefore writing `{{mytag/}}` is equivalent to writing `{{mytag #data/}}` \\n\\nTo override this behavior, set the `argDefault` option to `false`. The first argument will then not default to current data, and the render method will instead be called without arguments.\\n\\n```jsr\\n{{mytag/}}\\n```\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n render: function() {\\n // arguments.length is 0\\n },\\n argDefault: false\\n});\\n```\\n\",\r\n \"anchor\": \"argdefault\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying bound arguments and properties: the bindTo and bindFrom options\",\r\n \"text\": \"The `bindTo` and `bindFrom` options are designed primarily for use with data binding, with JsViews, and allow specifying which arguments/properties are data-bound for two-way binding.\\n\\nIn JsRender, the `bindTo` or `bindFrom` option can be used in conjunction with converters. Set the `bindFrom` option (or the `bindTo` option if there is no `bindFrom` setting) to an array, such as `[0, 1, 2]`, or `[\\\"title\\\", 1]` -- where integers refer to arguments and strings to named properties -- to determine what values are passed to the converter. (If neither `bindFrom` nor `bindTo` are set, then the values of all the [arguments](#tagsyntax@tagparams) will be passed to the converter.)\\n\\nBy default the value returned by the converter will be passed as first argument to the *render()* method. However, if the converter returns an array, then the values will be used to convert each of the targeted arguments or properties specified in `bindTo`/`bindFrom`.\\n\\nSee also\\n- [tag.bndArgs()](#tagobject@bndargs)\\n- [*JsViews* `bindTo`](#tagoptions@bindto)\\n\",\r\n \"anchor\": \"bindto\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying flow behavior: the flow option\",\r\n \"text\": \"A 'flow' tag -- which has the `flow` option set to `true` -- is a tag that does not appear in the [parent tags](#tagsapi@parents) hierarchy, so is not accessed via [`this.parent`](#tagobject@parent), [`this.parents`](#tagobject@parents), `~tagParents` etc.\\n\\nThe built-in tags such as `{{for}}`, `{{props}}` and `{{if}}` are *flow tags* and do not show up in the *parent tags* hierarchy. Custom tags by default are non-flow, and do show up (unless you set the option to `flow: true`).\",\r\n \"anchor\": \"flow\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Specifying default context: the ctx option\",\r\n \"text\": \"The `ctx` option of a tag can be used to provide default values of [contextual parameters](#contextualparams):\\n\\n```js\\n$.views.tags(\\\"mytag\\\", {\\n template: \\\"{{:~mode}}\\\",\\n ctx: {mode: \\\"readonly\\\"}, // Specify default ~mode if not provided by a helper or as a contextual parameter, \\n ...\\n});\\n```\\n\",\r\n \"anchor\": \"ctx\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Methods and properties available on a custom tag instance\",\r\n \"text\": \"A custom tag instance can access the following methods and properties\\n\\n*Tag properties*\\n- [tag.ctx](#tagobject@ctx)\\n- [tag.parent](#tagobject@parent)\\n- [tag.parents](#tagobject@parents)\\n- [tag.tagCtx](#tagobject@tagctx)\\n- [tag.tagCtxs](#tagobject@tagctxs)\\n- [tag.tagName](#tagobject@tagname)\\n- [rendering](#tagobject@rendering)\\n\\n*Tag methods*\\n- [tag.ctxPrm()](#tagobject@ctxprm)\\n- [tag.cvtArgs()](#tagobject@cvtargs)\\n- [tag.bndArgs()](#tagobject@bndargs)\\n- [tag.base()](#tagobject@base)\\n\",\r\n \"anchor\": \"instanceprops\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Adding tags as private resources for a parent template\",\r\n \"text\": \"You can pass in an existing template as an additional `parentTemplate` parameter, on any call to `$.views.tags(...)`.\\n\\nIn that way the tag (or tags) you are registering become 'private tag resources' for the `parentTemplate`, rather than being registered globally:\",\r\n \"anchor\": \"privatetags\"\r\n },\r\n {\r\n \"_type\": \"api\",\r\n \"typeLabel\": \"API:\",\r\n \"title\": \"\",\r\n \"name\": \"tags\",\r\n \"object\": \"$.views\",\r\n \"method\": true,\r\n \"returns\": \"\",\r\n \"signatures\": [\r\n {\r\n \"_type\": \"signature\",\r\n \"title\": \"Add one or more tags as private resources for a parent template\",\r\n \"params\": [\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"namedTags\",\r\n \"type\": \"object\",\r\n \"optional\": false,\r\n \"description\": \"Object (hash) of keys (name of tag) and values (render function or tagOptions)\"\r\n },\r\n {\r\n \"_type\": \"param\",\r\n \"name\": \"parentTemplate\",\r\n \"type\": \"object or string\",\r\n \"optional\": true,\r\n \"description\": \"Owner template – to which this/these tag(s) are being added as private resources\"\r\n }\r\n ],\r\n \"args\": [],\r\n \"sections\": [],\r\n \"example\": \"$.views.tags({\\n mytag1: ...,\\n mytag2: ...\\n}, parentTemplate);\",\r\n \"description\": \"Add multiple tags as resources, to a parent template\"\r\n }\r\n ],\r\n \"description\": \"\",\r\n \"sectionTypes\": {\r\n \"para\": \"para\",\r\n \"data\": \"data\",\r\n \"template\": \"template\",\r\n \"code\": \"code\",\r\n \"sample\": \"sample\",\r\n \"links\": \"links\"\r\n }\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Unregistering tags\",\r\n \"text\": \"To unregister a previously registered tag, pass `null` to `$.views.tags()`:\\n\\n```js\\n$.views.tags(\\\"mytag\\\", null);\\n// Tag \\\"mytag\\\" is no longer registered\\n```\",\r\n \"anchor\": \"unregister\"\r\n },\r\n {\r\n \"_type\": \"para\",\r\n \"title\": \"Custom tags and 'tag controls'\",\r\n \"text\": \"If you use JsViews, your custom tag can be developed into a fully functional tag control, with its own lifecycle, properties and methods, etc. It can be used as a presenter according to the MVP pattern.\"\r\n },\r\n {\r\n \"_type\": \"links\",\r\n \"title\": \"See also:\",\r\n \"links\": [],\r\n \"topics\": [\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"tags\",\r\n \"label\": \"Using custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/jsr/tags\",\r\n \"label\": \"Samples: JsRender custom tags\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"samples/tag-controls\",\r\n \"label\": \"Samples: JsViews tag controls\"\r\n },\r\n {\r\n \"_type\": \"topic\",\r\n \"hash\": \"jsvtagcontrols\",\r\n \"label\": \"JsViews tag controls\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n};"]} \ No newline at end of file diff --git a/documentation/contents-jsvapi.js b/documentation/contents-jsvapi.js index 58cb00f8..3d0b8e88 100644 --- a/documentation/contents-jsvapi.js +++ b/documentation/contents-jsvapi.js @@ -44,10 +44,6 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "hash": "link-targets", "label": "Targets for data-linking" }, - { - "hash": "jsvunlink", - "label": "unlink()" - }, { "hash": "jsvsettings", "label": "Settings" @@ -404,7 +400,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "", - "text": "By passing in `true` as the fourth *'noIteration'* parameter, the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\n\nWithin the template, `{^{for}}` (or equivalently `{^{for #data}}`) can be used to iterate over the array, as in the following example:" + "text": "By passing in `true` as the fourth *'noIteration'* parameter, (or as third parameter if no `helpersOrContext` are passed), the template renders just once, with the array itself as current data, rather than rendering once for each item in the array.\n\nWithin the template, `{^{for}}` (or equivalently `{^{for #data}}`) can be used to iterate over the array, as in the following example:" }, { "_type": "sample", @@ -421,13 +417,13 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "", - "text": "Code:\n\n```js\nmyTmpl.link(\"#peopleList\", people, null, true);\n```\n\nTemplate:\n\n```jsr\n
                                  \n \n \n {^{for}}\n \n \n \n {{/for}}\n \n
                                  \n {^{:#data.length}} people\n
                                  {^{>name}}
                                  \n```" + "text": "Code:\n\n```js\nmyTmpl.link(\"#peopleList\", people, true); // helpersOrContext not passed (so undefined), and noIteration set to true\n```\n\nTemplate:\n\n```jsr\n\n \n \n {^{for}}\n \n \n \n {{/for}}\n \n
                                  \n {^{:#data.length}} people\n
                                  {^{>name}}
                                  \n```" } ], "jsrJsvJqui": "", "height": "190", "html": "\n\n
                                  \n\n", - "code": "var myTmpl = $.templates(\"#personTmpl\");\n\nvar people = [\n {\n name: \"Adriana\"\n },\n {\n name: \"Robert\"\n }\n];\n\nmyTmpl.link(\"#peopleList\", people, null, true);\n\n$(\"#add\").on(\"click\", function() {\n $.observable(people).insert({\n name: \"name\"\n });\n});\n", + "code": "var myTmpl = $.templates(\"#personTmpl\");\n\nvar people = [\n {\n name: \"Adriana\"\n },\n {\n name: \"Robert\"\n }\n];\n\nmyTmpl.link(\"#peopleList\", people, true); // helpersOrContext not passed (so undefined), and noIteration set to true\n\n$(\"#add\").on(\"click\", function() {\n $.observable(people).insert({\n name: \"name\"\n });\n});\n", "title": "template.link(container, array, helpers, noIteration):" }, { @@ -648,41 +644,21 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ] }, "jsvunlink": { - "title": "Unlink a template", + "title": "$.unlink(): removing data-bindings", "path": "", "sections": [ { - "_type": "links", + "_type": "para", "title": "", - "links": [], - "topics": [ - { - "hash": "jsv.d.unlink", - "label": "$.unlink()" - }, - { - "hash": "jsv.db.unlink", - "label": "$(...).unlink()" - } - ] + "text": "The `$.unlink(...)` API is used for programmatically removing previously registered views and data-link bindings on a target HTML element and its content:\n\n```js\n$.unlink(selectorOrElement); // Unregister views and data-binding on container element and content\n```\n\nor equivalently:\n\n```js\n$(selectorOrElement).unlink(); // Unregister views and data-binding on container element and content\n```\n\nCalling `$.unlink()` without arguments will remove views and data-bindings from all HTML content:\n```js\n$.unlink(); // Unregister all views and data-binding\n```" + }, + { + "_type": "para", + "title": "Scenarios for calling $.unlink()", + "text": "In many scenarios, JsViews will automatically remove views and handlers when appropriate, so specific use of `$.unlink()` is rarely necessary.\n\nIn fact, the APIs for [data-linking a template](#jsvlinktmpl):\n\n- [myTmpl.link(container, data, helpers)](#jsvtmpllink)\n- [$.link.myTmpl(container, data, helpers)](#jsv.d.link)\n\nwill generally:\n\n- render the template as new HTML content within the container element\n- register a corresponding [view hierarchy](#views)\n- attach appropriate data-binding event handlers on the new content\n\nIf the new HTML content is later removed from the DOM, JsViews will automatically unregister those views and handlers.\n\nSimilarly, calling the `myTmpl.link(...)` or `$.link.myTmpl(...)` a second time will automatically unregister the previous views and handlers before establishing new ones.\n\nHowever, the [top-level data-linking](#toplink) APIs:\n\n- [$.link(true, targetElem, data, helpers, data, helpers)](#jsv.toplink-true)\n- [$.link(expression, targetElem, data, helpers, data, helpers)](#jsv.toplink-expr)\n\nwill, if called multiple times, add multiple data-bindings to the same target element. In this scenario, calling `$.unlink(targetElem)` can be useful for removing previous bindings..." } ] }, - "jsvtmplunlink": { - "title": "template.unlink()", - "path": "", - "sections": [] - }, - "jsv.d.unlink": { - "title": "$.unlink()", - "path": "", - "sections": [] - }, - "jsv.db.unlink": { - "title": "$(...).unlink()", - "path": "", - "sections": [] - }, "$view": { "title": "The view hierarchy: getting from the UI back to the data", "path": "", @@ -724,7 +700,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "var view = $.view(elem);", - "text": "Each instance of a rendered template or a template block tag is associated with a JsViews *\"[view](#jsvviewobject)\"* object.\n\nViews provide information on how the underlying data objects map to the rendered UI.\n\n**From UI back to data:**\n\nUse `$.view(elemOrSelector)` to get from a DOM element to the corresponding `view` object for that part of the rendered content.\n\nFrom the `view` you can get to the underlying `data`, the `index`, etc." + "text": "Each instance of a rendered template or a template block tag is associated with a JsViews *\"[view](#jsvviewobject)\"* object.\n\nViews provide information on how the underlying data objects map to the rendered UI.\n\n**From UI back to data:**\n\nUse `$.view(elemOrSelector)` to get from a DOM element to the corresponding `view` object (the *'containing'* `view`) for that part of the rendered content.\n\nFrom the `view` you can get to the underlying `data`, the `index`, etc." }, { "_type": "sample", @@ -794,7 +770,8 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "Alternative syntax:", - "text": "If you already have a jQuery object `$(elementOrSelector)`, then it can be convenient to use the following alternative syntax:\n\n```js\nvar view = $(elementOrSelector).view();\n```\n\nThis can be convenient in some scenarios, for example if you want to call another jQuery method on the same target element or selector, before getting the view. You can even chain the calls as in: `var view = $(elementOrSelector).doSomething().view();`\n" + "text": "If you already have a jQuery object `$(elementOrSelector)`, then it can be convenient to use the following alternative syntax:\n\n```js\nvar view = $(elementOrSelector).view();\n```\n\nThis can be helpful in some scenarios, for example if you want to call another jQuery method on the same target element or selector, before getting the view. You can even chain the calls as in: `var view = $(elementOrSelector).doSomething().view();`\n", + "anchor": "alt" }, { "_type": "api", @@ -825,6 +802,12 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "links": "links" } }, + { + "_type": "para", + "title": "Getting inner views", + "text": "An additional signature is available (for advanced scenarios):\n\n```js\nvar typeView = $.view(elementOrSelector, true, type);\n```\n\n-- which finds the containing view for the element or selector, then steps *down* through descendant views (depth first traversal) and returns *the first descendant view of type `type`*.\n\nSimilarly, in the alternative syntax above:\n\n```js\nvar typeView = $(elementOrSelector).view(true, type);\n```\n\n**Note:** The above are equivalent to [var typeView = `$.view(elementOrSelector).get(true, type)`](#viewobject@get).", + "anchor": "innerview" + }, { "_type": "links", "title": "See also:", @@ -915,27 +898,31 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "label": "tag object" }, { - "hash": "jsvviewcontextobject", + "hash": "jsvctxobject", "label": "View context object (ctx)" }, { - "hash": "jsvtagcontextobject", + "hash": "jsvtagctxobject", "label": "Tag context object (tagCtx)" }, { - "hash": "jsvlinkcontextobject", + "hash": "jsvlinkctxobject", "label": "Link context object (linkCtx)" }, { "hash": "eventArgs", "label": "eventArgs object" + }, + { + "hash": "jsvglobals", + "label": "Globals" } ] } ] }, "jsvviewsobject": { - "title": "The $.views object", + "title": "The $.views object (JsViews)", "path": "", "sections": [ { @@ -946,7 +933,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ] }, "jsvtemplateobject": { - "title": "The template object", + "title": "The template object (JsViews)", "path": "", "sections": [ { @@ -972,7 +959,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ] }, "jsvviewobject": { - "title": "The view object", + "title": "The view object (JsViews)", "path": "", "sections": [ { @@ -983,7 +970,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "A view object has the following properties and methods:", - "text": "**JsViews -- programmatic access only**\n\nThe following methods are available only for programmatic access when using JsViews:\n\n- [refresh() method](#jsvviewobject@refresh)\n- [contents() method](#jsvviewobject@contents)\n- [childTags() method](#jsvviewobject@childtags)\n- [nodes() method](#jsvviewobject@nodes)\n- [ctxPrm() get/set method](#jsvviewobject@ctxprm)\n\n**Both JsRender and JsViews** (see [JsRender `view` object](#viewobject))\n\n*The following properties and methods are available when using either JsRender or JsViews (both for programmatic access and declaratively in templates):*\n\n- [type property](#viewobject@type)\n- [data property](#viewobject@data)\n- [parent property](#viewobject@parent)\n- [index property](#viewobject@index)\n- [getIndex() method](#viewobject@getindex)\n- [get(type) method](#viewobject@get)\n- [content property](#viewobject@content)\n- [root property](#viewobject@root)\n- [other properties (tmpl, views, ctx, tag)](#viewobject@other)\n" + "text": "**JsViews -- programmatic access only**\n\nThe following methods are available only for programmatic access when using JsViews:\n\n- [*refresh()* method](#jsvviewobject@refresh)\n- [*contents()* method](#jsvviewobject@contents)\n- [*childTags()* method](#jsvviewobject@childtags)\n- [*nodes()* method](#jsvviewobject@nodes)\n- [*ctxPrm()* get/set method](#jsvviewobject@ctxprm)\n\n**Both JsRender and JsViews** (see [JsRender `view` object](#viewobject))\n\n*The following properties and methods are available when using either JsRender or JsViews (both for programmatic access and declaratively in templates):*\n\n- [*type* property](#viewobject@type)\n- [*data* property](#viewobject@data)\n- [*parent* property](#viewobject@parent)\n- [*index* property](#viewobject@index)\n- [*getIndex()* method](#viewobject@getindex)\n- [*get(type)* method](#viewobject@get)\n- [*content* property](#viewobject@content)\n- [*root* property](#viewobject@root)\n- [other properties and methods -- *tmpl*, *views*, *ctx*, *tag*, *getRsc()*](#jsvviewobject@other)\n" }, { "_type": "para", @@ -1022,7 +1009,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "The contents() method", - "text": "***view.contents(...)***: returns a jQuery object of view content nodes -- optionally filtered by a jQuery selector.\n\n```js\nvar jqMyClassElem = view.contents(true, \".myClass\");\n// jQuery object for element with 'myClass'at any depth within view\n```", + "text": "***view.contents(...)***: returns a jQuery object of view content nodes -- optionally filtered by a jQuery selector.\n\n```js\nvar jqMyClassElem = view.contents(true, \".myClass\");\n// jQuery object for element with 'myClass' at any depth within view\n```", "anchor": "contents" }, { @@ -1080,7 +1067,13 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews } ], "args": [], - "sections": [], + "sections": [ + { + "_type": "para", + "title": "", + "text": "*Note:* The `selector` argument can be jQuery selector string, or alternatively, an HTML Element, or a jQuery object" + } + ], "example": "var jqContents = view.contents(true, \".toRed\");\njqContents.css(\"color\", \"red\");", "description": "Get a jQuery object for the contents of the view: child and descendant nodes, filtered by the selector" } @@ -1136,7 +1129,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "name": "childTags", "object": "view", "method": true, - "returns": "jQuery object", + "returns": "Tag array", "signatures": [ { "_type": "signature", @@ -1185,7 +1178,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "args": [], "sections": [], - "example": "var jqContents = view.childTags(true, \".toRed\");\njqContents.css(\"color\", \"red\");", + "example": "var sliders = view.childTags(true, \"slider\");\nsliders[0].updateValue(25);", "description": "Get instances of {{tagName}} in view (including those nested in other custom tags)" } ], @@ -1259,7 +1252,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "The ctxPrm() get/set method:", - "text": "***view.ctxPrm(name)***: returns the value of the named contextual parameter, within the context of that view.\n\n```js\nvar value = view.ctxPrm(\"color\"));\n// Get value of current contextual parameter \"color\"\n```\n\n***view.ctxPrm(name, newValue)***: observably modifies the value of the named contextual parameter, within the context of that view.\n\n```js\nview.ctxPrm(\"color\", \"green\"));\n// Set value of current contextual parameter \"color\" to \"green\"\n```", + "text": "***view.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the view).\n\n```js\nvar value = view.ctxPrm(\"color\");\n// Get value of contextual parameter (or helper) \"color\"\n```\n\n***view.ctxPrm(name, newValue)***: observably modifies the value of the named contextual parameter or helper.\n\n```js\nview.ctxPrm(\"color\", \"green\");\n// Set value of contextual parameter (or helper) \"color\" to \"green\"\n```\n\nAvailable also as [`tag.ctxPrm()`](#jsvtagobject@ctxprm).\n\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\n\n*__Note:__* to register a listener for observable changes to a contextual parameter, such as `\"~color\"`, defined on a view, use:\n\n```js\n$.observe(view, \"~color\", myListener);\n```\n\n(Similarly on a tag, as in the [*linkedCtxParam* sample](#tagoptions@linkedctxparam) -- with the listener for `\"~mde\"`.)", "anchor": "ctxprm" }, { @@ -1311,6 +1304,12 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "code": "var tmpl = $.templates(\"#tmpl\"),\n\n model = {clr: \"orange\", person: {name: \"Jo\"}},\n\n helpers = {\n set: function(newColor, ev, eventArgs) {\n eventArgs.view.ctxPrm(\"color\", newColor); // Set contextual parameter: \"color\" to newColor\n },\n get: function(ev, eventArgs) {\n alert(eventArgs.view.ctxPrm(\"color\")); // Get current contextual parameter \"color\"\n }\n };\n\ntmpl.link(\"#result\", model, helpers);", "height": "140" }, + { + "_type": "para", + "title": "Other view object properties and methods:", + "text": "Additional properties of the `view` object are used by JsRender and JsViews for processing templates:\n\n- *tmpl*: the template used to render the view\n- *views*: the child views in the view hierarchy\n- *ctx*: object (hash) with the named contextual helpers/template parameters for this view\n- *tag*: the `\"mytag\"` view rendered by a custom tag `{{mytag ...}}`, has a `view.tag` property -- the instance of the `mytag` tag object\n- *linked*: boolean, value `true` in the case of data-linked views (from [`tmpl.link()`](#jsvlinktmpl) rather than [`tmpl.render()`](#rendertmpl))\n- *getRsc(namedCollection, itemName)*: returns a named resource (*converter* function, compiled *template* object, compiled *tag*, *helper* or *viewModel*), as available contextually in the scope of the view (i.e. global, or local as a template resource from one of the parent templates)

                                  The `namedCollection` parameter can be `\"templates\"`, `\"converters\"`, `\"tags\"`, `\"helpers\"` or `\"viewModels\"`). For example:\n ```js\n var upperCvtFunction = view.getRsc(\"converters\", \"upper\");\n ```", + "anchor": "other" + }, { "_type": "links", "title": "See also:", @@ -1331,75 +1330,142 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ] }, "jsvtagobject": { - "title": "The tag object", + "title": "The tag object (JsViews)", "path": "", "sections": [ { "_type": "para", "title": "Tag object properties and event handlers provided as tag options", - "text": "The following tag properties and event handlers can be specified as tag options when registering a custom tag:\n\n*Tag properties (both in JsRender and JsViews -- see [`$.views.tags()`](#tagsapi))*:\n\n- [`baseTag`](#tagsapi@basetag)\n- [`flow`](#tagsapi@flow)\n- [`template`](#tagsapi@template)\n- [`bindTo`](#tagsapi@bindto)\n- [`ctx`](#tagsapi@ctx)\n- [`contentCtx`](#tagsapi@contentctx)\n- [`argDefault`](#tagsapi@argdefault)\n\n*Tag properties (only in JsViews -- see [tag control options](#tagoptions))*:\n\n- [`dataBoundOnly`](#tagoptions@databoundonly)\n- [`boundProps`](#tagoptions@boundprops)\n- [`depends`](#tagoptions@depends)\n- [`attr`](#tagoptions@attr)\n- [`setSize`](#tagoptions@setsize)\n- [`height`](#tagoptions@height)\n- [`width`](#tagoptions@width)\n- [`className`](#tagoptions@classname)\n- [`linkedElement`](#tagoptions@linkedelement)\n- [`mainElement`](#tagoptions@mainelement)\n- [`displayElement`](#tagoptions@displayelement)\n- [`linkedCtxParam`](#tagoptions@linkedctxparam)\n- [`dataMap`](#tagoptions@datamap)\n- [`lateRender`](#tagoptions@laterender)\n- [`trigger`](#tagoptions@trigger)\n\n*Event handlers (both in JsRender and JsViews -- see [`$.views.tags()`](#tagsapi))*:\n\n- [`init()`](#tagsapi@init)\n- [`render()`](#tagsapi@render)\n- [`convert`](#tagsapi@convert)\n\n*Event handlers (only in JsViews -- see [tag control options](#tagoptions))*:\n\n- [`onBind()`](#tagoptions@onbind)\n- [`onAfterLink()`](#tagoptions@onafterlink)\n- [`onUpdate()`](#tagoptions@onupdate)\n- [`onDispose()`](#tagoptions@ondispose)\n- [`convertBack`](#tagoptions@convertback)\n- [`onUnbind()`](#tagoptions@onunbind)\n- [`onBeforeUpdateVal()`](#tagoptions@onbeforeupdateval)\n- [`onBeforeChange()`](#tagoptions@onbeforechange)\n- [`onAfterChange()`](#tagoptions@onafterchange)\n- [`onArrayChange()`](#tagoptions@onarraychange)\n- [`setValue()`](#tagoptions@setvalue)\n- [`domChange()`](#tagoptions@domchange)" + "text": "The following tag properties and event handlers can be specified as tag options when registering a custom tag:\n\n*Tag properties specified as tag options (both in JsRender and JsViews -- see [`$.views.tags()`](#tagsapi))*:\n\n- [`baseTag`](#tagsapi@basetag)\n- [`flow`](#tagsapi@flow)\n- [`template`](#tagsapi@template)\n- [`bindTo`](#tagsapi@bindto)\n- [`ctx`](#jsvtagobject@ctx)\n- [`contentCtx`](#tagsapi@contentctx)\n- [`argDefault`](#tagsapi@argdefault)\n\n*Tag properties specified as tag options (only in JsViews -- see [tag control options](#tagoptions))*:\n\n- [`dataBoundOnly`](#tagoptions@databoundonly)\n- [`boundProps`](#tagoptions@boundprops)\n- [`depends`](#tagoptions@depends)\n- [`attr`](#tagoptions@attr)\n- [`setSize`](#tagoptions@setsize)\n- [`height`](#tagoptions@height)\n- [`width`](#tagoptions@width)\n- [`className`](#tagoptions@classname)\n- [`linkedElement`](#tagoptions@linkedelement)\n- [`mainElement`](#tagoptions@mainelement)\n- [`displayElement`](#tagoptions@displayelement)\n- [`linkedCtxParam`](#tagoptions@linkedctxparam)\n- [`dataMap`](#tagoptions@datamap)\n- [`lateRender`](#tagoptions@laterender)\n- [`trigger`](#tagoptions@trigger)\n\n*Event handlers specified as tag options (both in JsRender and JsViews -- see [`$.views.tags()`](#tagsapi))*:\n\n- [`init()`](#tagsapi@init)\n- [`render()`](#tagsapi@render)\n- [`convert`](#tagsapi@convert)\n\n*Event handlers specified as tag options (only in JsViews -- see [tag control options](#tagoptions))*:\n\n- [`onBind()`](#tagoptions@onbind)\n- [`onAfterLink()`](#tagoptions@onafterlink)\n- [`onUpdate()`](#tagoptions@onupdate)\n- [`onDispose()`](#tagoptions@ondispose)\n- [`convertBack`](#tagoptions@convertback)\n- [`onUnbind()`](#tagoptions@onunbind)\n- [`onBeforeUpdateVal()`](#tagoptions@onbeforeupdateval)\n- [`onBeforeChange()`](#tagoptions@onbeforechange)\n- [`onAfterChange()`](#tagoptions@onafterchange)\n- [`onArrayChange()`](#tagoptions@onarraychange)\n- [`setValue()`](#tagoptions@setvalue)\n- [`domChange()`](#tagoptions@domchange)" }, { "_type": "para", "title": "Additional tag object properties and methods", - "text": "In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\n\n*Tag properties (both in JsRender and JsViews)*\n\n- [parent](#tagobject@parent)\n- [parents](#tagobject@parents)\n- [tagCtx](#tagobject@tagctx)\n- [tagCtxs](#tagobject@tagctxs)\n- [tagName](#tagobject@tagname)\n- [rendering](#tagobject@rendering)\n\n*Tag properties (only in JsViews)*\n\n- [linkCtx](#jsvtagobject@parent)\n- [parentElem](#jsvtagobject@parent)\n\n*Tag methods (both in JsRender and JsViews)*\n\n- [ctxPrm()](#tagobject@ctxprm)\n- [cvt()](#tagobject@cvt)\n- [cvtArgs()](#tagobject@cvtargs)\n- [bndArgs()](#tagobject@bndargs)\n- [base()](#tagobject@base)\n- [baseApply()](#tagobject@baseapply)\n\n*Tag methods (only in JsViews)*\n\n- [refresh()](#jsvtagobject@refresh)\n- [contents()](#jsvtagobject@contents)\n- [childTags()](#jsvtagobject@childtags)\n- [nodes()](#jsvtagobject@nodes)\n- [setValue()](#jsvtagobject@setvalue)\n- [setValues()](#jsvtagobject@setvalues)\n- [updateValue()](#jsvtagobject@updatevalue)\n- [updateValues()](#jsvtagobject@updatevalues)" + "text": "In addition to the above properties and handlers set as tag options, the tag object has the following properties and methods:\n\n*Tag properties (both in JsRender and JsViews)*\n\n- [parent](#tagobject@parent)\n- [parents](#tagobject@parents)\n- [tagCtx](#jsvtagobject@tagctx)\n- [tagCtxs](#tagobject@tagctxs)\n- [tagName](#tagobject@tagname)\n- [rendering](#tagobject@rendering)\n\n*Tag properties (only in JsViews)*\n\n- [linkCtx](#jsvtagobject@linkctx)\n- [parentElem](#jsvtagobject@parentelem)\n- [linkedElems and linkedElem](#jsvtagobject@linkedelem)\n- [mainElem](#jsvtagobject@mainelem)\n- [displayElem](#jsvtagobject@displayelem)\n- [inline](#jsvtagobject@inline)\n\n*Tag methods (both in JsRender and JsViews)*\n\n- [ctxPrm()](#jsvtagobject@ctxprm)\n- [cvtArgs()](#tagobject@cvtargs)\n- [bndArgs()](#tagobject@bndargs)\n- [base()](#tagobject@base)\n- [baseApply()](#tagobject@baseapply)\n\n*Tag methods (only in JsViews)*\n\n- [refresh()](#jsvtagobject@refresh)\n- [contents()](#jsvtagobject@contents)\n- [childTags()](#jsvtagobject@childtags)\n- [nodes()](#jsvtagobject@nodes)\n- [setValue()](#jsvtagobject@setvalue)\n- [setValues()](#jsvtagobject@setvalues)\n- [updateValue()](#jsvtagobject@updatevalue)\n- [updateValues()](#jsvtagobject@updatevalues)" }, { "_type": "para", "title": "Accessing tag objects", - "text": "The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\n\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\n\n```jsr\n{{:~tag.parent.tagName}}`\n```\n\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\n\n```jsr\n{{:~tagCtx.props.mode}}`\n```\n\n### Tag properties and methods (JsViews only):\n\n(Additional details to follow.)" + "text": "The `tag` object can be accessed *programmatically*, for example in event handlers of custom tags, using the `this` pointer.\n\nThe current tag can also be accessed *declaratively* (in a custom tag template, or in wrapped block content) using `~tag`, as in:\n\n```jsr\n{{:~tag.parent.tagName}}`\n```\n\nIn addition, `tag.tagCtx` can be accessed declaratively using `~tagCtx`, as in:\n\n```jsr\n{{:~tagCtx.props.mode}}`\n```" }, { "_type": "para", - "title": "The linkCtx property", + "title": "Tag properties (JsRender and JsViews):", + "text": "(See also the JsRender [tag object](#tagobject@propsmethods) topic.)", + "anchor": "jsrproperties" + }, + { + "_type": "para", + "title": "The tagCtx property", + "text": "***tag.tagCtx**: a [tag context](#jsvtagctxobject) object* providing access to instance information such as arguments/properties/view etc., as in:\n\n```js\nvar propA = tag.tagCtx.props.propA;\n```\n\nIt is also provided as an argument in tag events such as [*onBind(**tagCtx**, linkCtx, ctx)*](#tagoptions@onbind).\n\nAccessed declaratively (in a tag template or wrapped content) as `~tagCtx`.\n\nSee [*Tag Context*](#tagsapi@context)", + "anchor": "tagctx" + }, + { + "_type": "para", + "title": "The ctx property", + "text": "***tag.ctx**: a [view context](jsvctxobject) object (hash) providing access to the [contextual parameters](#contextualparams)*, as in.\n\n```js\nvar rootData = tag.tagCtx.root;\n```\n\nIt is also provided as an argument in tag events such as [*onBind(tagCtx, linkCtx, **ctx**)*](#tagoptions@onbind).\n\nAccessed declaratively as `~tag.ctx`.\n\nSee [*Tag Context*](#tagsapi@context)\n\nSee also:\n- [`tag.ctxPrm()`](#jsvtagobject@ctxprm), below\n- The [`ctx` tag option](#tagsapi@ctx) (for specifying default context on a custom tag)", + "anchor": "ctx" + }, + { + "_type": "para", + "title": "Tag properties (JsViews only):", "text": " ", + "anchor": "properties" + }, + { + "_type": "para", + "title": "The linkCtx property", + "text": "For any data-linked tag, such as `{^{mytag/}}` (*inline* [data-linked tag](#linked-tag-syntax)) , or `
                                  `([tag binding](#link-tags) on a [data-linked element](#linked-elem-syntax)), ***tag.linkCtx*** is a [link context](#jsvlinkctxobject) object providing contextual data-link information, as in:\n\n```js\nvar isTopLevelDataLinked = tag.linkCtx.type === \"top\";\n```\n\nIt is also provided as an argument in tag events such as [*onBind(tagCtx, **linkCtx**, ctx)*`](#tagoptions@onbind).", "anchor": "linkctx" }, { "_type": "para", "title": "The parentElem property", - "text": " ", + "text": "For a [data-linked tag](#linked-tag-syntax), such as `{^{mytag/}}`, ***tag.parentElem*** is the parent (containing) HTML element.\n\nFor a [data-linked element](#linked-elem-syntax) such as `
                                  ` ([tag binding](#link-tags)), whether in a template or with [top-level data-linking](#toplink), ***tag.parentElem*** is the data-linked element (the `
                                  ` in this case).", "anchor": "parentelem" }, { "_type": "para", - "title": "The refresh() method", + "title": "The linkedElems and linkedElem properties", + "text": "The ***tag.linkedElems*** and ***tag.linkedElem*** properties are associated with the [`linkedElement` option](#tagoptions@linkedelement). (See the [*linkedElement* design pattern topic](#bindingpatterns@linkedelem).)\n\nIf the `linkedElement` option is used to establish two-way data binding between an element (or elements) in the tag, and the [`bindTo`](#tagoptions@bindto) tag arguments or properties, then after data-linking (for example, in the [`onBind`](#tagoptions@onbind) event handler of the tag) the `tag.linkedElems` property will contain *an array of jQuery objects for those data-linked elements*. And the `tag.linkedElem` property will contain *a jQuery object for the first of those elements*. \n\nConversely, if `linkedElement` is not set, then in the `onBind` handler the `tag.linkedElems` properties can be ***set** to an array of jQuery objects for chosen tag elements*. (Or, if `bindTo` specifies only one binding, then `tag.linkedElem` properties can be ***set** to a single jQuery object for a chosen tag element*.)\n\nThis provides a programmatic approach to configuring the choice of data-linked elements.\n\nFor example in the [`{{namebox}}`](#bindingpatterns@namebox-linkedelem) sample\n\n```jsr\n{^{namebox first last caption=~label .../}}\n```\n\nThe declarative approach:\n\n```js\nlinkedElement: [\".firstnm\", \".lastnm\", \".cptn\"]\n```\n\ncould be replaced by a programmatic approach: \n\n```js\nnamebox: {\n ...\n template: '...: ...',\n bindTo: [0, 1, \"caption\"],\n onBind: function() {\n this.linkedElems = [\n this.contents(true, \".firstnm\"); // Set linkedElem for argument 0 (first)\n this.contents(true, \".lastnm\"); // Set linkedElem for argument 1 (last)\n this.contents(true, \".cptn\"); // Set linkedElem for property \"caption\" (caption=~label)\n ];\n },\n ...\n}\n```\n\n*Note:*\n- For tags with `{{else}}` blocks see also [`tagCtx.linkedElems`](#jsvtagctxobject@properties)\n- Establishing of two-way binding on `linkedElems` is done after the [`onBind`](#tagoptions@onbind) event, and before the [`onAfterLink`](#tagoptions@onafterlink) event", + "anchor": "linkedelem" + }, + { + "_type": "para", + "title": "The mainElem property", + "text": "The ***tag.mainElem*** property is associated with the [`mainElement` option](#tagoptions@mainelement).\n\nIf the `mainElement` option is used to establish an element in the tag as *main element*, then after data-linking (for example, in the [`onBind`](#tagoptions@onbind) event handler of the tag) the `tag.mainElem` property will contain a jQuery object for the *main element*. \n\nConversely, if `mainElement` is not set, then in the `onBind` handler the `tag.mainElem` property can be ***set** to a jQuery objects for a chosen tag element*.\n\nThis provides a programmatic approach to configuring the choice of *main element*.\n\n*Note:*\n- Setting of `width`, `height` or `id` on `tag.mainElem` is done after the [`onBind`](#tagoptions@onbind) event, and before the [`onAfterLink`](#tagoptions@onafterlink) event\n- For tags with `{{else}}` blocks see also [`tagCtx.mainElem`](#jsvtagctxobject@properties)", + "anchor": "mainelem" + }, + { + "_type": "para", + "title": "The displayElem property", + "text": "The ***tag.displayElem*** property is associated with the [`displayElement` option](#tagoptions@displayelement).\n\nIf the `displayElement` option is used to establish an element in the tag as *display element*, then after data-linking (for example, in the [`onBind`](#tagoptions@onbind) event handler of the tag) the `tag.displayElem` property will contain a jQuery object for the *display element*. \n\nConversely, if `displayElement` is not set, then in the `onBind` handler the `tag.displayElem` property can be ***set** to a jQuery objects for a chosen tag element*.\n\nThis provides a programmatic approach to configuring the choice of *display element*.\n\n*Note:*\n- Setting of `class` on the `tag.displayElem` is done after the [`onBind`](#tagoptions@onbind) event, and before the [`onAfterLink`](#tagoptions@onafterlink) event\n- For tags with `{{else}}` blocks see also [`tagCtx.displayElem`](#jsvtagctxobject@properties)\n", + "anchor": "displayelem" + }, + { + "_type": "para", + "title": "The inline property", + "text": "If ***tag.inline*** is `true`, then this is a [data-linked tag](#linked-tag-syntax) such as `{^{mytag/}}` (also referred to as an ***inline tag***).\n\nIf ***tag.inline*** is `false`, then this is a [tag binding](#link-tags) on a [data-linked element](#linked-elem-syntax) such as `
                                  ` (whether in a template or with [top-level data-linking](#toplink)).\n\nSee also [tag.linkCtx.type](#jsvlinkctxobject)", + "anchor": "inline" + }, + { + "_type": "para", + "title": "Tag methods (JsRender and JsViews):", + "text": "(See also the JsRender [tag object](#tagobject@methods) topic.)", + "anchor": "jsrmethods" + }, + { + "_type": "para", + "title": "The ctxPrm() get/set method", + "text": "***tag.ctxPrm(name)***: returns the value of the named contextual parameter or helper (at the context of the tag instance).\n\n```js\nvar value = tag.ctxPrm(\"color\");\n// Get value of contextual parameter (or helper) \"color\"\n```\n\n***tag.ctxPrm(name, newValue)***: observably modifies the value of the named contextual parameter or helper.\n\n```js\ntag.ctxPrm(\"color\", \"green\");\n// Set value of contextual parameter (or helper) \"color\" to \"green\"\n```\n\nAvailable also as [`view.ctxPrm()`](#jsvviewobject@ctxprm).\n\nSee *[Accessing contextual parameters and helpers](#tagsapi@ctxparams)*.\n\n*__Note:__* to register a listener for observable changes to a contextual parameter, such as `\"~color\"`, defined on a tag, use:\n\n```js\n$.observe(tag, \"~color\", myListener);\n```\n\nSee for example the [*linkedCtxParam* sample](#tagoptions@linkedctxparam) -- with the listener for `\"~mde\"`.", + "anchor": "ctxprm" + }, + { + "_type": "para", + "title": "Tag methods (JsViews only):", "text": " ", + "anchor": "methods" + }, + { + "_type": "para", + "title": "The refresh() method", + "text": "The ***tag.refresh()*** method refreshes (re-renders and data-links) the tag control.\n\nFor example, in the [`{{spinblock}}` sample](#bindingpatterns@spinblock):\n\n- the `render()` method returns content which depends on the value of the `tag.pane` property\n- the custom tag method `cycle()` changes the value of `tag.pane`, then calls `tag.refresh()` to refresh the rendering and data-binding using the new value of `tag.pane`: \n \n\n```js\n$.views.tags(\"spinblock\", {\n render: function() {\n ...\n if (this.tagCtx.index === this.pane) { // This is the selected pane.\n ... + this.tagCtx.render(); // Render block content\n }\n ...\n },\n cycle: function() { // Method to cycle/increment selected pane\n this.pane = (this.pane+1) % this.tagCtxs.length;\n this.refresh(); // Refresh the rendering and data-binding, with the new value of this.pane\n },\n ...\n```", "anchor": "refresh" }, { "_type": "para", "title": "The contents() method", - "text": " ", + "text": "Returns a jQuery object of tag content nodes -- optionally filtered by a jQuery selector:\n\n- ***tag.contents()*** (without arguments) returns the top-level contents of the tag (top-level child nodes, including text nodes):\n ```js\n var jqContents = tag.contents();\n ```\n- ***tag.contents(selector)*** (with a selector argument) returns top-level content elements of the tag, filtered by the selector:\n ```js\n var jqSelectedElem = tag.contents(\".selected\");\n ```\n- ***tag.contents(deep, selector)*** (with `deep` flag: `true`, and selector argument) returns content elements of the tag (any depth) filtered by the selector:\n ```js\n var jqContents = tag.contents(true, \".selected\");\n ```\n\nFor example, in the [`{{spinblock}}` sample](#bindingpatterns@spinblock):\n\n```js\n$.views.tags(\"spinblock\", {\n ...\n onBind: function() {\n // Find the switcher
                                  element, and attach the tag.cycle() method to it, as 'click' handler\n this.contents(true, '.switcher').on(\"click\", $.proxy(this.cycle, this));\n },\n ...\n```\n\nSee the similar API [`view.contents(...)`](#jsvviewobject@contents)\n", "anchor": "contents" }, { "_type": "para", "title": "The childTags() method", - "text": " ", + "text": "Returns an array of custom tag instances, within the content of the tag -- optionally filtered by tag name:\n\n- ***tag.childTags()*** returns the top-level custom tag instances within the tag content:\n ```js\n var childTagsArray = tag.childTags();\n ```\n- ***tag.childTags(tagName)*** returns instances of `{{tagName}}` within the tag content (not nested in other custom tags):\n ```js\n var slidersArray = tag.childTags(\"slider\");\n ```\n- ***tag.childTags(deep, tagName)*** (with `deep` flag: `true`) returns instances of `{{tagName}}` within the tag content (including those nested in other custom tags):\n ```js\n var slidersArray = tag.childTags(true, \"slider\");\n ```\n\nFor example, in the [`{{picker}}` sample](#hierarchypatterns@picker):\n\n```js\n$.views.tags(\"picker\", {\n ...\n onBind: function() {\n ...\n tag.areaslider = tag.childTags(\"areaslider\")[0];\n },\n ...\n```\n\nSee the similar API [`view.childTags(...)`](#jsvviewobject@childtags)\n", "anchor": "childtags" }, { "_type": "para", "title": "The nodes() method", - "text": " ", + "text": "The ***tag.nodes()*** method returns an array of top-level nodes within the tag content (including text nodes):\n\n```js\nvar nodesArray = tag.nodes();\n```\n\nSee the similar API [`view.nodes(...)`](#jsvviewobject@nodes)\n", "anchor": "nodes" }, { "_type": "para", "title": "The setValue() method", - "text": "If a custom tag control uses [`linked elements`]() then calling `tag.setValue(newValue, index)` will set the value of the corresponding linked element. In addition, if the tag control has a [`setValue()`](@tagoptions@setvalue) event handler, then that event handler will be called.\n\nFor block tags, with multiple `{{else}}` blocks, a third parameter can be passed specifying the index of the `{{else}}` block whose linked element is to be updated:\n\n```js\ntag.setValue(newValue, index, elseBlock);\n```\n\nSee the [Programmatic two-way data-binding](#bindingpatterns@setvalue-updatevalue) design patterns topic for additional discussion and examples.\n\nSee also [`setValues()`](#jsvtagobject@setvalues) below." + "text": "If a custom tag control uses [`linked elements`]() then calling `tag.setValue(newValue, index)` will set the value of the corresponding linked element. In addition, if the tag control has a [`setValue()`](#tagoptions@setvalue) event handler, then that event handler will be called.\n\nFor block tags, with multiple `{{else}}` blocks, the [`tagCtx.setValues()`](#jsvtagctxobject@methods) can be used (for the `tagCtx` corresponding to the `{{else}}` block) -- or, alternatively a third parameter can be passed specifying the index of the `{{else}}` block whose linked element is to be updated:\n\n```js\ntag.setValue(newValue, index, elseBlock);\n```\n\nSee the [Programmatic two-way data-binding](#bindingpatterns@setvalue-updatevalue) design patterns topic for additional discussion and examples.\n\nSee also [`setValues()`](#jsvtagobject@setvalues) below.", + "anchor": "setvalue" }, { "_type": "para", "title": "The setValues() method", - "text": "If a custom tag control uses [`linked elements`]() then calling `tag.setValues()` will set the values of the linked elements. In addition, if the tag control has a [`setValue()`](@tagoptions@setvalue) event handler, then that event handler will be called prior to updating each targeted linked element.\n\nFor block tags with multiple `{{else}}` blocks, `setValues()` will set values on the linked elements on the initial tag (the first block). To set values on the linked elements in additional `{{else}}` blocks, use [`setValue()`](#jsvtagobject@updatevalue).\n\nSee the [Multiple two-way binding](#bindingpatterns@multiple-twoway) design patterns topic for additional discussion and examples.", + "text": "If a custom tag control uses [`linked elements`]() then calling `tag.setValues(newVal1, newVal2, ...)` will set the values of the linked elements. In addition, if the tag control has a [`setValue()`](@tagoptions@setvalue) event handler, then that event handler will be called prior to updating each targeted linked element.\n\n```js\ntag.setValues(newValueFor1stElem, newValueFor2ndElem, ...);\n```\n\nFor block tags with multiple `{{else}}` blocks, `setValues()` will set values on the linked elements on the initial tag (the first block). To set values on the linked elements in additional `{{else}}` blocks, use either [`tagCtx.setValues()`](#jsvtagctxobject@methods) or [`tag.setValue()`](#jsvtagobject@setvalue).\n\nSee the [Multiple two-way binding](#bindingpatterns@multiple-twoway) design patterns topic for additional discussion and examples.", "anchor": "setvalues" }, { "_type": "para", "title": "The updateValue() method", - "text": "Calling `tag.updateValue(newValue, index)` will observably update the bound argument or property corresponding to the specified `index` of the [`bindTo`](#tagoptions@bindto) array.\n\nFor block tags, with multiple `{{else}}` blocks, a third parameter can be passed specifying the index of the `{{else}}` block whose bound argument or property is being updated:\n\n```js\ntag.updateValue(value, index, elseBlock);\n```\n\nThe call will use two-way data-binding to update the underlying data specified in the data-link expression.", + "text": "Calling `tag.updateValue(newValue, index)` will observably update the bound argument or property corresponding to the specified `index` of the [`bindTo`](#tagoptions@bindto) array.\n\nFor block tags, with multiple `{{else}}` blocks, a third parameter can be passed specifying the index of the `{{else}}` block whose bound argument or property is being updated:\n\n```js\ntag.updateValue(newValue, index, elseBlock);\n```\n\nThe call will use two-way data-binding to update the underlying data specified in the data-link expression.", "anchor": "updatevalue" }, { @@ -1435,7 +1501,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "The updateValues() method", - "text": "Calling `tag.updateValues()` will observably update the bound arguments or properties specified in the [`bindTo`](#tagoptions@bindto) option array:\n\n```js\ntag.updateValues(newValue1, newValue2, ...);\n```\n\nThe call will use two-way data-binding to update the underlying data specified in the data-link expressions.\n\nFor block tags with multiple `{{else}}` blocks, `updateValues()` will update the bound data-link expressions on the initial tag (the first block). To drive updates on the additional `{{else}}` block bindings, use [`updateValue()`](#jsvtagobject@updatevalue).\n\nThe `bindTo` option defaults to `[0]`, so if there is no `bindTo` setting, `updateValues(value)` will observably update the first argument data path, and will be equivalent to `updateValue(value)`.\n\nSee the [Multiple two-way binding](#bindingpatterns@multiple-twoway) design patterns topic for additional discussion and examples.", + "text": "Calling `tag.updateValues(...)` will observably update the bound arguments or properties specified in the [`bindTo`](#tagoptions@bindto) option array:\n\n```js\ntag.updateValues(newValue1, newValue2, ...);\n```\n\nThe call will use two-way data-binding to update the underlying data specified in the data-link expressions.\n\nFor block tags with multiple `{{else}}` blocks, `updateValues(...)` will update the bound data-link expressions on the initial tag (the first block). To drive updates on the additional `{{else}}` block bindings, use [`updateValue(...)`](#jsvtagobject@updatevalue).\n\nThe `bindTo` option defaults to `[0]`, so if there is no `bindTo` setting, `updateValues(value)` will observably update the first argument data path, and will be equivalent to `updateValue(value)`.\n\nSee the [Multiple two-way binding](#bindingpatterns@multiple-twoway) design patterns topic for additional discussion and examples.", "anchor": "updatevalues" }, { @@ -1452,30 +1518,60 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews } ] }, - "jsvviewcontextobject": { - "title": "The view context object", + "jsvctxobject": { + "title": "The view context object, ctx (JsViews)", "path": "", - "sections": [] + "sections": [ + { + "_type": "para", + "title": "", + "text": "Each view has a view context object: ***view.ctx***, which is a 'hash' whose properties correspond to the set of [contextual parameters](#contextualparams), `~foo` accessible from that view, within a template. (See [*Accessing contextual parameters and helpers*](#tagsapi@ctxparams).)\n\nIt also has the following built-in properties (contextual parameters):\n\n- `ctx.root`: The [root data](#contextualparams@root) (accessed from a template as `~root`)\n- `ctx.tag`: The [tag object](#tagobject) (accessed from a template as `~tag`)\n- `ctx.tagCtx`: The [tagCtx object](#tagobject@tagctx) (accessed from a template as `~tagCtx`)\n- `ctx.parentTags`: [parent tags](tagsapi@parents) (accessed from a template as `~parentTags`)\n\nFor programmatic access to contextual parameters, it may be better to use the [view.ctxPrm()](#jsvviewobject@ctxprm) or [tag.ctxPrm()](#jsvtagobject@ctxprm) API." + } + ] }, - "jsvtagcontextobject": { - "title": "The tag context object", + "jsvtagctxobject": { + "title": "The tag context object, tagCtx (JsViews)", "path": "", "sections": [ { "_type": "para", "title": "", - "text": "- tagCtx.contentView\n- tagCtx.contents()\n- tagCtx.nodes()\n- tagCtx.childTags()\n- tagCtx.cvtArgs()\n- tagCtx.bndArgs()\n- tagCtx.setValues()\n- tagCtx.render()\n- tagCtx.args\n- tagCtx.props\n- tagCtx.params\n- tagCtx.tag\n- tagCtx.ctx\n- tagCtx.tmpl\n- tagCtx.view\n- tagCtx.contentView\n- tagCtx.index" + "text": "When a template is rendered, each tag is instantiated.\n\n```jsr\n{^{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr .../}}\n```\n\nThe tag instance has an associated tag context object, `tag.tagCtx`, giving contextual information for the tag.\n\nSee [*Tag context*](#tagsapi@context)\n\nIn the case of a tag with `{{else}}` blocks it has an array of `tagCtx` objects, `tag.tagCtxs`, one for each `{{else}}` block):\n\n```jsr\n{^{sometag argExpr prop1=propExpr ~ctxprm1=prmExpr ...}}\n ...\n{{else argExpr2 prop2=propExpr2 ~ctxprm2=prmExpr2 ...}}\n ...\n{{/sometag}}\n```" + }, + { + "_type": "para", + "title": "tagCtx properties (JsRender and JsViews):", + "text": "(See also the JsRender [`tagCtx` object](#tagctxobject@properties) topic.)\n\n- ***tagCtx.props:***\n - a hash of the values of the named properties (such as `tagCtx.props.prop1`)\n- ***tagCtx.args:***\n - an array with argument value (such as `tagCtx.args[0]`)\n- ***tagCtx.params:***\n - provides access to argument, property and contextual parameter expressions (such as `tagCtx.params.props.prop1`, `tagCtx.params.args[0]` or `tagCtx.params.ctx.ctxprm1`)\n- ***tagCtx.content:***\n - for a block tag (see [wrapping block content](#tagsapi@wrapping)), the compiled template for wrapped content\n - otherwise, for a tag with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, the compiled external template (same as `tagCtx.tmpl`)\n - otherwise, `false`\n- ***tagCtx.tmpl:***\n - for a tag with an external template, `tmpl=...`, the compiled external template\n - otherwise, for a block tag, the template for wrapped content (same as `tagCtx.content`)\n - otherwise, `false`\n- ***tagCtx.index:***\n - for `{{else}}` blocks, the index of the block (see [`tag.tagCtxs`](#tagobject@tagctxs))\n - otherwise, `0`\n- ***tagCtx.tag:***\n - the tag instance\n- ***tagCtx.view:***\n - the contextual (containing) view object\n- ***tagCtx.ctx:***\n - the [ctx](#ctxobject) (view context) object with the contextual helpers/template parameters for this tag.", + "anchor": "jsrproperties" + }, + { + "_type": "para", + "title": "tagCtx properties (JsViews only):", + "text": "- ***tagCtx.linkedElems:***\n - equivalent to [`tag.linkedElems`](#jsvtagobject@linkedelem)\n - however, for a tag with `{{else}}` blocks such as:\n ```jsr\n {{mytag firstName}}...{{else lastName}}...{{/mytag}}\n ```\n the context is the specific `{{else}}` block -- e.g. for the example above, `tag.tagCtxs[1].linkedElems[0]` might access an `` binding to `lastName`\n\n- ***tagCtx.mainElem***\n - equivalent to [`tag.mainElem`](#jsvtagobject@mainElem)\n - however, for a tag with `{{else}}` blocks such as:\n ```jsr\n {{mytag id=\"a\"}}...{{else id=\"b\"}}...{{/mytag}}\n ```\n the context is the specific `{{else}}` block -- e.g. for the example above, `tag.tagCtxs[1].mainElem` would access an element with `id`: `\"b\"`\n- ***tagCtx.displayElem:***\n - equivalent to [`tag.displayElem`](#jsvtagobject@displayElem)\n - however, for a tag with `{{else}}` blocks such as:\n ```jsr\n {{mytag class=\"a\"}}...{{else class=\"b\"}}...{{/mytag}}\n ```\n the context is the specific `{{else}}` block -- e.g. for the example above, `tag.tagCtxs[1].displayElem` would access an element with `class`: `\"b\"`\n- ***tagCtx.contentView:***\n - the view object for tag content -- whether rendered by the render method or by a template, or wrapped content...
                                  (see [*Custom tag child views*](#tagsapi@childviews))\n - for a tag with `{{else}}` blocks the context is the specific `{{else}}` block", + "anchor": "properties" + }, + { + "_type": "para", + "title": "tagCtx methods (JsRender and JsViews):", + "text": "(See also the JsRender [`tagCtx` object](#tagctxobject@methods) topic.)\n\n- ***tagCtx.render(data, context, noIteration):***\n - if there is a tag template, renders the template\n - otherwise for a template with an [external template reference](#tagsyntax@tmplref), `tmpl=...`, renders the external template\n - otherwise, for a block tag, renders the wrapped content\n - otherwise, returns `\"\"`\n - *Note:* as an alternative, to render wrapped content even if there is a tag template, or an external template (`tmpl-=...`), use
                                  ***tagCtx.content.render(data, context, noIteration)***. (See [sample](#tags@renderplustmpl-sample))\n- ***tagCtx.ctxPrm(name):***\n - equivalent to [`tag.ctxPrm(name)`](#jsvtagobject@ctxprm)\n - however, for a tag with `{{else}}` blocks such as:\n ```jsr\n {{mytag}}...{{else ~myparam=...}}...{{/mytag}}\n ```\n the context is the specific `{{else}}` block -- e.g. accessing `tag.tagCtxs[1].ctxPrm(\"myparam\")` for the example above\n- ***tagCtx.cvtArgs():***\n - equivalent to [`tag.cvtArgs()`](#jsvtagobject@cvtargs)\n - however, for a tag with `{{else}}` blocks the context is the specific `{{else}}` block
                                  \n -- i.e. equivalent to `tag.cvtArgs(tagCtx.index)`\n- ***tagCtx.bndArgs():***\n - equivalent to [`tag.bndArgs()`](#jsvtagobject@bndargs)\n - however, for a tag with `{{else}}` blocks the context is the specific `{{else}}` block
                                  \n -- i.e. equivalent to `tag.bndArgs(tagCtx.index)`", + "anchor": "jsrmethods" + }, + { + "_type": "para", + "title": "tagCtx methods (JsViews only):", + "text": "- ***tagCtx.contents():*** returns a jQuery object of tag content nodes –- optionally filtered by a jQuery selector\n - equivalent to [`tag.contents()`](#jsvtagobject@contents)\n - however, for a tag with `{{else}}` blocks the context is the contents of the specific `{{else}}` block\n- ***tagCtx.nodes():*** returns an array of top-level nodes within the tag content (including text nodes)\n - equivalent to [`tag.nodes()`](#jsvtagobject@nodes)\n - however, for a tag with `{{else}}` blocks the context is the contents of the specific `{{else}}` block\n- ***tagCtx.childTags():*** returns an array of custom tag instances, within the content of the tag -– optionally filtered by tag name\n - equivalent to [`tag.childTags()`](#jsvtagobject@childtags)\n - however, for a tag with `{{else}}` blocks the context is the contents of the specific `{{else}}` block\n- ***tagCtx.setValues(...):*** sets the values of the linked elements. In addition, if the tag control has a [`setValue()`](#tagoptions@setvalue) event handler, then that event handler will be called prior to updating each targeted linked element.\n - equivalent to [`tag.setValues(...)`](#jsvtagobject@setvalues)\n - however, for a tag with `{{else}}` blocks the context is the linked elements in the specific `{{else}}` block\n", + "anchor": "methods" } ] }, - "jsvlinkcontextobject": { - "title": "The link context object", + "jsvlinkctxobject": { + "title": "The linkCtx object (JsViews)", "path": "", "sections": [ { "_type": "para", "title": "", - "text": "paragraph" + "text": "Data-linked tags (such as `{^{mytag/}}` or `
                                  `) provide a `linkCtx` object giving contextual data-link information:\n\n- ***linkCtx.tag:*** the tag instance\n- ***linkCtx.type:*** `\"inline\"` for a [data-linked tag](#linked-tag-syntax), `\"link\"` for [data-linked element](#linked-elem-syntax) (tag binding), `\"top\"` for a [top-level declarative](#jsv.toplink-true) data-linked element binding or `\"expr` for a [top-level programmatic](#jsv.toplink-expr) data-linked element binding \n- ***linkCtx.data:*** the current data context for the tag\n- ***linkCtx.elem:*** the associated HTML element (e.g. the data-linked element `
                                  `)\n- ***linkCtx.view:*** the contextual (containing) view object\n- ***linkCtx.expr:*** the tag binding expression\n- ***linkCtx.attr:*** the [target `attr`](#link-targets) of the tag binding expression\n- ***linkCtx.ctx:*** the [ctx](#jsvctxobject) (view context) object with the contextual helpers/template parameters for this tag.\n" } ] }, @@ -1930,7 +2026,8 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "code": "code", "sample": "sample", "links": "links" - } + }, + "anchor": "alt" }, { "_type": "para", @@ -2025,6 +2122,11 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "_type": "topic", "hash": "linked-elem-syntax", "label": "Data-linked elements" + }, + { + "_type": "topic", + "hash": "jsvunlink", + "label": "$.unlink()" } ] } @@ -2146,7 +2248,8 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "code": "code", "sample": "sample", "links": "links" - } + }, + "anchor": "alt" }, { "_type": "para", @@ -2219,6 +2322,11 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "_type": "topic", "hash": "linked-elem-syntax", "label": "Data-linked elements" + }, + { + "_type": "topic", + "hash": "jsvunlink", + "label": "$.unlink()" } ] } @@ -2253,7 +2361,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "
                                  \n\n", "code": "$.views.converters({\n toString: function(val) {\n return val ? 'male' : 'female';\n },\n toBool: function(val) {\n return val === 'male';\n }\n});\n\n$.views.tags({\n textbox: {\n onBind: function() {\n // Find input in contents\n this.linkedElem = this.contents(\"input\");\n },\n onUpdate: false, // No need to re-render whole tag, when content updates.\n template: \"{{:~tagCtx.props.label}} \"\n }\n});\n\nvar tmpl = $.templates(\"#tmpl\");\n\nvar person = {name: \"Jo\", gender: \"male\"};\n\ntmpl.link(\"#result\", person);\n", - "height": "320", + "height": "310", "title": "Two way binding", "header": "", "action": "append" @@ -2290,12 +2398,12 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "html": "\n\n
                                  \n\n", "code": "var helpers = {\n toString: function(val) {\n return val ? 'male' : 'female';\n },\n toBool: function(val) {\n return val === 'male';\n }\n};\n\nvar tmpl = $.templates(\"#tmpl\");\n\nvar person = {gender: \"male\"};\n\ntmpl.link(\"#result\", person, helpers);\n", "title": "Two-way binding – using helpers as converters", - "height": "130" + "height": "120" }, { "_type": "para", "title": "Converter function signature", - "text": "Both the convert and the convertBack converter functions are invoked with the tag instance as `this` pointer -– as described in this JsRender topic: [*Converter function signature*](#convertersapi@signature). So within a converter function you can access this.tagCtx, this.linkCtx, etc. and from there reach many useful properties and objects.", + "text": "Both the convert and the convertBack converter functions are invoked with the tag instance as `this` pointer -– as described in this JsRender topic: [*Converter function signature*](#convertersapi@signature). So within a converter function you can access `this.tagCtx`, `this.linkCtx`, etc. and from there reach many useful properties and objects.", "anchor": "signature" }, { @@ -2335,7 +2443,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n\n\n\n
                                  \n\n", "code": "var settings = {\n current: {title: \"My title\", color:\"green\"},\n modified: {title: \"My title\", color:\"green\"},\n apply: function() {\n $.observable(this.current).setProperty(this.modified);\n return false;\n },\n cancel: function() {\n $.observable(this.modified).setProperty(this.current);\n $.observable(this.current).setProperty({title: \"\", color: \"\"});\n $.observable(this.current).setProperty(this.modified); }\n}\n\nvar myTmpl = $.templates(\"#myTmpl\");\n\nmyTmpl.link(\"#result\", settings);", - "height": "500", + "height": "480", "title": "linkTo" }, { @@ -2364,7 +2472,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n\n
                                  ", "code": "var myTmpl = $.templates(\"#myTmpl\"),\n data = { first: \"Jo\", last: \"Blow\" };\n\n$.views.converters({\n toFull: function(first, last) {\n return first + \" \" + last;\n },\n fromFull: function(fullname) {\n var names = fullname.split(\" \");\n var last = names.pop();\n var first = names.join(\" \"); \n return [first, last]; // Return array for binding back to the two arguments\n }\n});\n\nmyTmpl.link(\"#page\", data);", - "height": "120" + "height": "105" }, { "_type": "para", @@ -2393,7 +2501,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews "header": "", "html": "
                                  \n\n", "code": "var tmpl = $.templates(\"#tmpl\");\n\nvar person = {name: 'Jo '};\n\ntmpl.link(\"#result\", person);\n", - "height": "418", + "height": "408", "nocss": false, "action": "append" } @@ -2848,7 +2956,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "Radio buttons – dynamic array including id (value)", - "text": "Here we allow the user also to change the `id` value (used as key) -- which requires the more advanced data-link syntax: [`value^{:id}`](#linked-elem-syntax@no-initial-render) to update the `value` of the ``s when the `id` changes.\n\nWe provide two radio button groups -- showing the alternative syntax styles -- data-linking through a `{{radiogroup}}` wrapper tag, or data-linking directly to the ``s. Since both groups data-link to the same `selectedCar` property, the two-way binding keeps them in sync.", + "text": "Here we allow the user also to change the `id` value (used as key) -- which requires the more advanced data-link syntax: `value^{:id}` (see [*syntax for updating only*](#linked-elem-syntax@no-initial-render)) to update the `value` of the ``s when the `id` changes.\n\nWe provide two radio button groups -- showing the alternative syntax styles -- data-linking through a `{{radiogroup}}` wrapper tag, or data-linking directly to the ``s. Since both groups data-link to the same `selectedCar` property, the two-way binding keeps them in sync.", "anchor": "radioeditid" }, { @@ -2866,7 +2974,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "", - "text": "*
                                  Two radio button groups:
                                  -- with `{{radiogroup}}`:
                                  *\n\n```jsr\n{^{radiogroup selectedCar}}\n \n {^{for cars}}\n \n {{/for}}\n{{/radiogroup}}\n```\n\n*
                                  -- and with direct data-linking to the ``s:
                                  *\n\n```jsr\n\n{^{for cars}}\n \n{{/for}}\n```\n\nSince the `id` is also editable, we are data-linking to `id`: `data-link=\"value{:id}\"`. \n\nFor the second style (data-linking directly to the ``) we need to ensure that the `value` is initialized during rendering, using `value=\"{{:id}}\"` (to ensure correct initial selection of the *Ford* radio button -- based on the initial value `\"frd\"` of `selectedCar`) -- in addition to binding to subsequent changes in `id` using `value^{:id}`." + "text": "*
                                  Two radio button groups:
                                  -- with `{{radiogroup}}`:
                                  *\n\n```jsr\n{^{radiogroup selectedCar}}\n \n {^{for cars}}\n \n {{/for}}\n{{/radiogroup}}\n```\n\n*
                                  -- and with direct data-linking to the ``s:
                                  *\n\n```jsr\n\n{^{for cars}}\n \n{{/for}}\n```\n\nSince the `id` is also editable, we are data-linking to `id`: `data-link=\"value{:id}\"`. \n\nFor the second style (data-linking directly to the ``) we need to ensure that the `value` is initialized during rendering, using `value=\"{{:id}}\"` (to ensure correct initial selection of the *Ford* radio button -- based on the initial value `\"frd\"` of `selectedCar`) -- in addition to binding to subsequent changes in `id` using [`value^{:id}`](#linked-elem-syntax@no-initial-render)." } ], "html": "
                                  \n\n", @@ -3636,7 +3744,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n\n\n", "code": "var tmpl = $.templates(\"#tmpl\");\n\nvar person = {};\n\nvar helpers = {\n doSomething: function() {\n alert(\"do something\");\n }\n}\n\ntmpl.link(\"#result\", person); // Render and link the template\n\n// Attach handler to buttons (class 'myButton'), whether in top-level or rendered content.\n$(\".myButton\").on(\"click\", helpers.doSomething);\n", - "height": "45", + "height": "50", "title": "" }, { @@ -3665,7 +3773,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n \n\n\n\n\n", "code": "var tmpl = $.templates(\"#tmpl\");\n\nvar person = {};\n\nvar helpers = {\n doSomething: function() {\n alert(\"do something\");\n }\n}\n\ntmpl.link(\"#result\", person, helpers); // Render and link the template\n\n$.link(true, \"#topLinked\", person, helpers); // Data-link top-level content\n\n", - "height": "45" + "height": "50" }, { "_type": "para", @@ -3698,7 +3806,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n\n", "code": "var tmpl = $.templates(\"#tmpl\");\n\nvar person = {};\n\nvar helpers = {\n doSomething: function() {\n alert(\"do something\");\n }\n}\n\ntmpl.link(\"#result\", person, helpers); // Render and link the template\n", - "height": "45" + "height": "50" }, { "_type": "para", @@ -3741,7 +3849,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews ], "html": "\n\n\n\n", "code": "var tmpl = $.templates(\"#tmpl\");\n\nvar person = {};\n\nvar helpers = {\n doSomething: function(ev) {\n alert(\"do something. id: \" + ev.target.id);\n }\n}\n\ntmpl.link(\"#result\", person, helpers); // Render and link the template\n", - "height": "45" + "height": "50" }, { "_type": "para", @@ -4071,7 +4179,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "", - "text": "The following call:\n\n```js\n$.views.settings.delimiters(\"<%\", \"%>\");\n```\n\nwill change the tag syntax to `<%...%>` for JsRender, and `<^%...%>`) for a data-linked tag in JsViews.\n\nAnd the following:\n```js\n$.views.settings.delimiters(\"<<\", \">>. \"*\");\n```\n\nwill change to `<<...>>` for a JsRender tag, and `<*<...>>`) for a data-linked tag in JsViews.\n\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `[\"<%\", %>, \"*\"]` -- as shown in [this sample](#settings/delimiters@tmpl-for-tmpl).)" + "text": "The following call:\n\n```js\n$.views.settings.delimiters(\"<%\", \"%>\");\n```\n\nwill change the tag syntax to `<%...%>` for JsRender, and `<^%...%>`) for a data-linked tag in JsViews.\n\nAnd the following:\n```js\n$.views.settings.delimiters(\"<<\", \">>. \"*\");\n```\n\nwill change to `<<...>>` for a JsRender tag, and `<*<...>>`) for a data-linked tag in JsViews.\n\nThe chosen delimiters must each consist of two non-alphanumeric characters.\n\n(*Note:* `$.views.settings.delimiters(...);` also accepts as parameter an array such as `[\"<%\", %>, \"*\"]` which can be useful for reverting to a previous set of delimiters -- as shown in -- as shown in [this sample](#settings/delimiters@tmpl-for-tmpl).)" }, { "_type": "para", @@ -4157,7 +4265,7 @@ content.jsvapi = content.useStorage && $.parseJSON(localStorage.getItem("JsViews { "_type": "para", "title": "", - "text": "JsViews has the following advanced settings:\n\n- **useViews** -- *default:* `false`\n- **linkAttr** -- *default:* `\"data-link\"`\n- **noValidate** -- *default:* `false` \n\nand also the following 'private' advanced settings:\n\n- **_jsv** -- *default:* `false`\n- **_wm** -- *default:* current 'wrapMap' settings\n- **_fe** -- *default:* current 'form element binding' settings\n\n***useViews*** controls a JsRender performance optimization, while building the *[view hierarchy](#views)*. In very simple templates there will usually not be any need to access the [`view`](#viewobject). JsRender detects these cases, does not create a view, and hence obtains a slight performance gain. By setting `useViews` to `true`, you guarantee that JsRender will *always* create views for template blocks.\n\n***linkAttr*** determines the JsViews data-link attribute. By default it is `data-link`. If there is a conflict where another module also uses the 'data-link' attribute, then you can choose a different attribute for JsViews data-linking. \n\nFor example, if you set `$.views.settings.advanced({linkAttr: \"link\"})`, then you would write `` instead of `` for data-linking an `` to `name`.\n\n***noValidate*** controls whether JsViews runs validation code during data-linking, to raise an error in the case of invalid HTML structure (such as `
                                  ` or <`div>
                                  `) or HTML/JsViews tag structure (such as `{^{if...}} `). By setting *noValidate* to `true`, JsViews will skip the validation step, with a minor improvement to performance as a result.\n\n***_jsv*** is a 'private' setting (could change in the future). If set to `true` JsRender provides a global `_jsv` variable, which gives access to the internal store of views.\n\n***_wm*** is a 'private' setting (could change in the future). It determines the 'wrapMap' configuration which controls how document fragments are inserted into the DOM during data-linking. (Also used by jQuery DOM manipulation).\n\n***_fe*** is a 'private' setting (could change in the future). If contains the 'form element binding' configuration, which determines the elements (such as `` or `\n```\n\n```jsr\n\n```\n\n```jsr\n{^{textbox name/}}\n```'}],html:'
                                  \n\n',code:'$.views.converters({\n toString: function(val) {\n return val ? \'male\' : \'female\';\n },\n toBool: function(val) {\n return val === \'male\';\n }\n});\n\n$.views.tags({\n textbox: {\n onBind: function() {\n // Find input in contents\n this.linkedElem = this.contents("input");\n },\n onUpdate: false, // No need to re-render whole tag, when content updates.\n template: "{{:~tagCtx.props.label}} "\n }\n});\n\nvar tmpl = $.templates("#tmpl");\n\nvar person = {name: "Jo", gender: "male"};\n\ntmpl.link("#result", person);\n',height:"320",title:"Two way binding",header:"",action:"append"},{_type:"para",title:"Abbreviated syntax and full syntax for data-link",text:'Notice that on the above elements, the `data-link="name"` syntax automatically has two-way data-binding.\n\nThe full syntax for two-way binding is `data-link="{:name:}"`. See *[Data-linked elements](#linked-elem-syntax)* for syntax details.\n\n***Note:*** To specify *one-way binding* only, use the full syntax, but *without the final colon*: `data-link="{:name}`.'},{_type:"para",title:"Converters: convert and convert back ",text:'With two way bindings, you can use a [converter](#converters) for each direction (*from/to*) of the binding: *convert* for converting *from* data to the rendered value, and *convert back* for converting from the user input *back to* the data.\n\nIn the sample above the *checkbox* example is using converters. Without converters the *checkbox* binds to a *Boolean* data value. Here, converters allow it to bind instead to `gender` which is a string with values `"male"`/`"female"`:\n\n```jsr\n\n```\n\nThe alternative syntax for using [converters on other tags](#converters@othertags) also extends to *convert back* -- so you can write:\n \n```jsr\ndata-link="... convert=... convertBack=...\n```\n\nYou can set *convert* and *convertBack* to a converter name, or a function such as a helper or data method. Here is a modified version of the previous sample, using the `convertBack-=...` syntax, in this case set to helper functions:',anchor:"converters"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n``` '}],html:'\n\n
                                  \n\n',code:"var helpers = {\n toString: function(val) {\n return val ? 'male' : 'female';\n },\n toBool: function(val) {\n return val === 'male';\n }\n};\n\nvar tmpl = $.templates(\"#tmpl\");\n\nvar person = {gender: \"male\"};\n\ntmpl.link(\"#result\", person, helpers);\n",title:"Two-way binding – using helpers as converters",height:"130"},{_type:"para",title:"Converter function signature",text:"Both the convert and the convertBack converter functions are invoked with the tag instance as `this` pointer -– as described in this JsRender topic: [*Converter function signature*](#convertersapi@signature). So within a converter function you can access this.tagCtx, this.linkCtx, etc. and from there reach many useful properties and objects.",anchor:"signature"},{_type:"para",title:"Additional advanced two-way binding scenarios:",text:""},{_type:"para",title:"Triggering the two-way binding on blur, rather than on keydown",text:"In the case of *[textboxes](#link-input@textbox)* (or any other two-way data-linked element that takes character entry such as the *[textarea](#link-textarea)*, *[contenteditable](#link-contenteditable)* and some *custom tags* like as the `{^{textbox}}` example above), you can choose when the *to* binding updates the underlying data:\n\n- With `trigger=true` (default setting), changes to the underlying data are triggered as you type (on character entry -- the *keydown* event, or for compatible browsers, the *input* event)\n- With `trigger=false`, changes to the underlying data are made on leaving the textbox (the *change* or *blur* event)\n\nThe *trigger* setting can be modified:\n\n- globally, by using: [$.views.settings.trigger(...)](#jsvsettings/trigger):\n ```jsr\n $.views.settings.trigger(false); \n ```\n- on each tag or element by writing:\n ```jsr\n \n {^{textbox name trigger=false}}\n ```\n\nIn fact you can also set `trigger` to a string with one or more white-space separated event names, such as: \n\n```jsr\n`\n```\n\n-- but generally only the values ***true*** (actually equivalent to `trigger='keydown'`) and ***false*** are useful.",anchor:"trigger"},{_type:"para",title:"linkTo: Linking from/to different underlying data",text:'It can sometimes be useful to be able to choose different targets for the *from* and *to* bindings of a two-way bound element such as a textbox. This is possible by setting the `linkTo` attribute to the desired target data for the *to* binding.\n\nIn the following sample an `` and a `\n```\n\nNote that `linkTo` can also be used with the full syntax, and optionally with converters as in:\n\n```jsr\n\n```\n\nThe user can choose the *Apply* button (or hit *Enter*, for the submit action of the form) to copy values over from `modified` to `current`. *Cancel* reverts the input/select back to the current data:',anchor:"linkto"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\nColor: \n\n\nName:\n\n```\n'}],html:'\n\n\n\n
                                  \n\n',code:'var settings = {\n current: {title: "My title", color:"green"},\n modified: {title: "My title", color:"green"},\n apply: function() {\n $.observable(this.current).setProperty(this.modified);\n return false;\n },\n cancel: function() {\n $.observable(this.modified).setProperty(this.current);\n $.observable(this.current).setProperty({title: "", color: ""});\n $.observable(this.current).setProperty(this.modified); }\n}\n\nvar myTmpl = $.templates("#myTmpl");\n\nmyTmpl.link("#result", settings);',height:"500",title:"linkTo"},{_type:"para",title:"Data-linking to/from multiple arguments, using convert and convertBack",text:"When data-linking binds from more than one argument (using a *convert* converter to combine values), then two-way binding can be made to bind back not just to the first argument, but to all of the arguments. This is achieved by providing a *convert back* converter which returns an array of values, one for each argument, and is shown in the following example: ",anchor:"multipleargs"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'Data-link to two arguments, `first ` and `last`:\n\n```jsr\n\n```\n\n*Convert back* converter `fromFull` returns an array:\n\n```js\n$.views.converters({\n toFull: function(first, last) {\n return first + " " + last;\n },\n fromFull: function(fullname) {\n ...\n return [first, last]; // Return array for binding back to the two arguments\n }\n});\n```'}],html:'\n\n
                                  ',code:'var myTmpl = $.templates("#myTmpl"),\n data = { first: "Jo", last: "Blow" };\n\n$.views.converters({\n toFull: function(first, last) {\n return first + " " + last;\n },\n fromFull: function(fullname) {\n var names = fullname.split(" ");\n var last = names.pop();\n var first = names.join(" "); \n return [first, last]; // Return array for binding back to the two arguments\n }\n});\n\nmyTmpl.link("#page", data);',height:"120"},{_type:"para",title:"Encoding to avoid XSS",text:"Whenever the user has access to the two-way editing feature, it is important to avoid any associated security risk that might arise from HTML injection, or XSS (cross-site-scripting) attacks.\n\nFor example, if UI such as `` allows the user to edit `someValue`, then `someValue` should not be inserted directly into the HTML without encoding. In this scenario, the use of [`{^{:someValue}}`](#jsvassigntag) is therefore to be avoided, and should be replaced with either [`{^{>someValue}}`](#jsvhtmltag) or [`{^{encode:someValue}}`](#convertersapi@encode).\n\nWhen using content-editable elements with two-way binding, they should generally be associated with encode/unencode converters: [`data-link=\"{encode:someValue:unencode}\"`](#convertersapi@encode):\n\nSimilarly if the initial data from the server is untrusted, then direct rendering of unencoded values by the template should be avoided, and in particular [`{{:someValue}}`](#assigntag) should not be used, and should be replaced by [`{{>someValue}}`](#htmltag) or `[{{encode:someValue}}](#convertersapi@encode)`\n\nThese scenarios are illustrated in the following sample, which starts with some 'dangerous' data, and also allows the user to modify or insert HTML markup in the `person.name` property. However the correct use of encoding prevents the HTML markup from being inserted 'as is' into the DOM.",anchor:"encode"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'*Editable UI elements:*\n\n```jsr\n\n\n
                                  \n```\n\n*\'Safe\' rendering:*\n\n```jsr\n{^{>name}}\n\n{^{encode:name}}\n\n
                                  \n```'}],header:"",html:'
                                  \n\n',code:'var tmpl = $.templates("#tmpl");\n\nvar person = {name: \'Jo \'};\n\ntmpl.link("#result", person);\n',height:"418",nocss:!1,action:"append"}]},"linked-paths":{title:"Data-linked paths",path:"",sections:[{_type:"para",title:"",text:'A data-linked template may include [chained paths](#paths@paths) such as `manager.address.ZIP` which step through chained object properties:\n\n```jsr\n\n\n{^{if manager.address.ZIP}}\n ZIP: {^{:manager.address.ZIP}}\n{{/if}} \n```'},{_type:"para",title:"Data-linking to deep changes in the path ('deep linking')",text:'\nThe chained paths can be in the `data-link="..."` expression of [data-linked elements](#linked-elem-syntax) or in [data-linked tags](#linked-tag-syntax): `{^{...}}`. Either way, the template data-binding will automatically \'listen\' to observable changes in the leaf property (`ZIP` in this case). \n\nBut sometimes you may want your template to respond dynamically to changes on objects higher up in the path (*deep changes* on the path). You can specify this by a simple syntax change: replace a `.` with a `^` at the level up to which you want to listen to changes.\n\nFor example, write `manager.address^ZIP` in order to respond not only to leaf changes (to `ZIP`) but also to observable changes in the `address` property of the `manager`. And write `manager^address.ZIP` in order to data-bind also to changes where the `manager` property of the top-level `team` object is swapped observably to another `manager` object.\n\n(If you know that in your app the objects higher up the path will never change dynamically, then stick with the default leaf binding, since that will provide better perf optimization...)\n\nSee also the related discussion and examples on [using `$.observe()` with deep changes](#observe@deep).\n\nHere it is in a sample, with leaf binding only. Editing the ZIP or clicking *"Change leaf values"* triggers template updates. But clicking *"Change manager"* does not work.\n\nClick on ***Try it*** and change paths to `manager^address.ZIP` -- and see how *"Change manager"* now works.',anchor:"deep"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n\n{^{if manager.address.ZIP}}\n ZIP: {^{>manager.address.ZIP}}\n{{/if}}\n```\n\nModify leaf: template values update in response:\n```js\n$.observable(team.manager.address).setProperty({\n "ZIP": team.manager.address.ZIP === "45008" ? "" : "45008"\n});\n```\n\nChange manager: template values do *not* update:\n```js\n$.observable(team).setProperty({\n manager: team.manager === person1 ? person2 : person1\n});\n```\n\n\n'}],html:'
                                  \n \n \n
                                  \n
                                  \n\n',code:'var team = {\n person1: {\n address: {\n City: "New York",\n ZIP: "10035"\n }\n },\n person2: {\n address: {\n City: "London"\n }\n }\n};\n\nteam.manager = team.person1;\n\n\n$("#modifyLeaf").on("click", function() {\n $.observable(team.manager.address).setProperty({\n "ZIP": team.manager.address.ZIP === "45008" ? "" : "45008"\n });\n});\n\n$("#changeManager").on("click", function() {\n $.observable(team).setProperty({\n manager: team.manager === team.person1 ? team.person2 : team.person1\n });\n});\n\nvar tmpl = $.templates("#managerTmpl");\n\ntmpl.link("#result", team);',title:"Leaf binding only",height:"130"},{_type:"para",title:"",text:"Here is the same sample but with the deep path binding to manager: `manager^address.ZIP`"},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n\n\n{^{if manager^address.ZIP}}\n ZIP: {^{>manager^address.ZIP}}\n{{/if}}\n```\n\nModify leaf (ZIP) or manager: template values all update correctly in response\n'}],html:'
                                  \n \n \n
                                  \n
                                  \n\n',code:'var team = {\n person1: {\n address: {\n City: "New York",\n ZIP: "10035"\n }\n },\n person2: {\n address: {\n City: "London"\n }\n }\n};\n\nteam.manager = team.person1;\n\n\n$("#modifyLeaf").on("click", function() {\n $.observable(team.manager.address).setProperty({\n "ZIP": team.manager.address.ZIP === "45008" ? "" : "45008"\n });\n});\n\n$("#changeManager").on("click", function() {\n $.observable(team).setProperty({\n manager: team.manager === team.person1 ? team.person2 : team.person1\n });\n});\n\nvar tmpl = $.templates("#managerTmpl");\n\ntmpl.link("#result", team);',title:"Data-linking to deep changes",height:"130",anchor:""},{_type:"para",title:"",text:"And here is a variant of the same demo, showing changes to all three levels of `manager^address.ZIP`: `ZIP`, `address` and `manager`."},{_type:"sample",typeLabel:"Sample:",codetabs:[],sectionTypes:{para:"para",data:"data",template:"template",code:"code",links:"links"},sections:[{_type:"para",title:"",text:'```jsr\n{^{if manager^address.ZIP}}\n ...\n{{else}}\n ...UK address - No ZIP\n{{/if}}\n```'}],html:'
                                  \n \n \n \n \n
                                  \n
                                  \n\n',code:'var person1 = {\n name: "Pete",\n address: {\n street: "1st Ave",\n ZIP: "34009"\n }\n};\n\nvar person2 = {\n name: "Henry",\n address: {\n street: "Trinity St"\n }\n};\n\nvar data = {\n manager: person1\n};\n\n$("#modifyLeaf").on("click", function() {\n $.observable(data.manager).setProperty({\n name: "Hermione",\n "address.street": "Main St",\n "address.ZIP": "45008"\n });\n});\n\n$("#changeAddress").on("click", function() {\n $.observable(data.manager).setProperty(\n "address", \n {\n street: "New Street",\n ZIP: "99999"\n }\n );\n});\n\n$("#UKAddress").on("click", function() {\n $.observable(data.manager).setProperty(\n "address", \n {\n street: "St James St"\n }\n );\n});\n\n$("#changeManager").on("click", function() {\n $.observable(data).setProperty({\n manager: data.manager === person1 ? person2 : person1\n });\n});\n\nvar tmpl = $.templates("#managerTmpl");\n\ntmpl.link("#result", data);',height:"180",title:"Data-linking to deep changes (three levels)",anchor:"deep3levels"},{_type:"para",title:"",text:'(See also [this sample](#jsvviewmodelsapi@ismanagersample), showing similar deep linking but with computed get/set properties: `data-link="manager()^address().ZIP()"`)'},{_type:"links",title:"See also",links:[],topics:[{_type:"topic",hash:"linked-elem-syntax",label:"Data-linked elements"},{_type:"topic",hash:"linked-tag-syntax",label:"Data-linked tags"},{_type:"topic",hash:"paths",label:"Paths and expressions"},{_type:"topic",hash:"settings/allowcode@security",label:"Expressions and security"}]}]},"link-computed":{title:"Data-linking to computed observables",path:"",sections:[{_type:"para",title:"",text:'Data-linking to computed observables can include:\n\n- data-linking to a computed value (as in [this sample](#computed@getsetdepends)): \n ```jsr\n \n ```\n- two-way data-linking to a get/set property (as in [this sample](#computed@getset)):\n ```jsr\n \n ```\n- data-linking to a deep path that includes one or more computed values (as in [this sample](#jsvviewmodelsapi@ismanagersample) -- where the displayed `ZIP` updates correctly when `team.manager()` changes):\n ```jsr\n \n ```\n- data-linking to multiple targets as in:\n ```jsr\n \n ```\n -- which has two-way data-linking to `name()` and data-linking of the placeholder target to `namePlaceholder()`\n\nSee:\n\n- [Data / View Model](#jsvmodel)\n- [Computed properties and computed observables](#computed)\n- [Samples: fullName() – variants](#samples/computed/fullname)\n- [Samples: Shopping cart - totalAmount()](#samples/computed/shopping-cart)\n- [Compiled VMs - Team manager sample](#jsvviewmodelsapi@ismanagersample)'}]},"link-targets":{title:"Targets for data-linking",path:"",sections:[{_type:"para",title:"",text:'The [full syntax](#linked-elem-syntax@fullsyntax) for data-linked elements is written like this:\n\n```jsr\n\n```\n\nPossible targets include the following:\n- an HTML attribute (such as `title{...}`, `class{...}`, `id{...}`, `disabled{...}` or `data-foo{...}`\n)\n- an HTML element property (such as `prop-muted{...}` for a `