Wednesday, October 12, 2011

jQuery Templates and JsViews: The Roadmap

Update: JsRender is now close to beta, and JsViews has many new features which also bring it closer to beta.
See Approaching Beta: What's changing in JsRender and JsViews for details on the latest changes.

From jQuery Templates to JsViews
This post provides some details and some context on the relationship between jQuery Templates, JsRender and JsViews, and provides information about the current roadmap.

History of jQuery Templates
jQuery Templates started out in March 2010, and went through a series of steps:
  • March 2010: John Resig posted a prototype
  • from May 2010 onwards: I worked on a fork of John's prototype (as did many others)
  • October 2010: My fork was pulled into the jQuery Templates repo, and it was decided to make this a jQuery Official Plugin:  (along with the Globalization and Data Link plugins, created primarily by Dave Reed, also at Microsoft). 
  • October 2010 - April 2011: I continued to iterate on the code on jquery/jquery-tmpl - taking it to Beta1 then working towards Beta2.
  • April 2011: The jQuery Project decided to change the status of official plugins. From that point the version of jQuery Templates at jquery/jquery-tmpl was owned by the jQuery UI team. I collaborated with jQuery UI on moving templates forward. 
  • April 2011 onwards: jQuery UI decided to put  jquery/jquery-tmpl  on hold - and asked me not to continue with fixes and updates under that repository. The plan was first to establish their templating requirements, and from there move on to determining what template engine they would use.
Meanwhile: JsRender and JsViews
At the same time (April 2011) I was working on an updated approach to jQuery Templates: JsRender and JsViews. JsRender uses pure string-based rendering without any DOM (or even jQuery) dependency, and JsViews integrates JsRender templates with data linking, to provide data-driven templated views.  I gave a preview of this work at the April 2011 jQuery Conference.

The jQuery UI team asked me to continue that ongoing development in my own repository rather than under the jQuery project. Meantime we collaborated on establishing design and feature requirements for templates in jQuery UI.

More recently jQuery UI decided that they did not want to use the jQuery Template syntax for their future templating engine, and instead opted for a logicless syntax (or as I prefer to say, codeless - since there would still be {{each}} and {{if}} tags) similar to Mustache and Handlebars. This led me to develop a version of JsRender using that style of markup. The result is the JsRender template engine that I showed at the October jQuery Conference, which is considerably faster that jQuery Templates, and remains very flexible thanks to the ease and power of creating custom tags and helpers (which include some features not found in Handlebars or Mustache - such as chaining of tags, intermixing of named and positional parameters, postfixed encoding syntax etc.)

Personally I had mixed feelings about the new codeless syntax. One big concern was that it will require porting of existing jQuery Template apps to the new syntax, and in the case where the templates include a lot of inline JavaScript expressions, it will mean either creating new custom tags, or falling back on the 'opt-in' {{*... }} tag for inline code.

But on the positive side, it provides better separation of presentation and behavior, and includes some other new features and improvements that provide considerable advantages, including the ease of creating custom tags, and the improved performance. So finally I am pretty excited by the new approach and what it brings...

Moving forwards with JsViews and JsRender
Currently JsViews and JsRender include a number of samples which can provide the basis for using them already for front-end development. Although there is not yet any documentation as such, and there has been no publicity (until now), they are nevertheless already being used at the prototype level by some important sites (notably by Hotmail - who are about to go into production using JsViews). That said, I anticipate some changes in JsViews, so it may be better to wait a bit longer before doing too much development using the JsViews platform. JsRender on the other hand is I think getting close to a stable Beta-release API.

Templates in jQuery UI 
As far as jQuery UI is concerned, the current expectation is that jQuery UI will use JsRender templates, or at least use JsRender as the starting point for jQuery UI templates. No  decision has been made yet on whether jQuery UI will use JsViews for data linking and binding.

Roadmap summary:
  • jQuery templates: Will remain at Beta1, and be superseded by JsRender templates, and JsViews.
  • JsRender: Soon move to Beta – then on to V1
    jQueryUI plan to use JsRender. (TBD whether it will migrate to jQuery project in GitHub...)
  • JsViews: Move to Beta (after JsRender) and then on to V1 …
    May also be used by jQueryUI

80 comments:

  1. Thanks so much for this concise history and roadmap of jQuery templating. We are using the current beta jQuery Templates heavily at my company, so I was surprised to learn it won't progress beyond that!
    However, I enjoyed your talk at the jQuery conference in Boston, and am definitely looking forward to a stable jsViews and jsRender.

    ReplyDelete
  2. Hello.
    What is V1?? Release 1?
    And how long will take integration with jQuery UI?

    ReplyDelete
  3. @Nik: Yes V1 = version 1 = release 1.
    You will be able to (can already) use existing jQuery UI widgets within JsViews and JsRender - along the lines of this demo.
    In the future, many jQuery UI widgets will use templates internally, and the default templating they use will probably be JsRender. The timeline for that depends on the jQuery UI release schedule, and they have not yet provided any commitments on dates.

    ReplyDelete
  4. This is great stuff Boris! I'm wondering where I can go to ask questions or advocate for some of the templating functionality? E.g. I wanted to see what expressions are handled in {{#if [expression] }}... . Currently seems like I can't compare a data element to a constant using == or > or < ? (I had to make a custom template to do so but it doesn't have the nice "else" functionality).

    ReplyDelete
  5. Problem is, jQuery-ui progresses at a glacial pace, and they are all over the map.

    I would love to see tmpl properly handed-off to people who obviously continue to care about it.

    ReplyDelete
  6. @Steven: Me too, but looks like that can't happen. However JsRender is in fact the next version of jQuery Templates (in that it corresponds to exactly the direction I was going in with jQuery Templates, at the point where I had to move the development out of the jquery.jquery.tmpl repository). I think it has an excellent future. It is faster, more extensible, opens the door to server-side rendering, and in addition, the integration with JsViews opens a huge additional set of possibilities.

    ReplyDelete
  7. @SynapticLove: You can add issues to JsRender or to JsViews. At some point I'll set up a forum, for discussions, too, but for now you can post questions in the context of issues, or here on this blog. I may also be able to field questions sent to my email, if I am not too swamped :).
    For 'if' expressions - That's an example of using an inline javascript expression in jquery templates, which is not supported in JsRender (codeless), or not in the same way. You can either use custom tags, or the inline code tag {{*...}}

    See for example these samples:
    custom helper tags
    allow code
    chained tags
    (and corresponding code, e.g. chained tags)

    ReplyDelete
  8. @SynapticLove: Oh and BTW custom tags can also integrate the 'else' functionality. See this line of code, for example.

    ReplyDelete
  9. Just wondering - what is the impact on knockout.js? Their advanced functionality seems to be tied very closely with tmpl. We (our team) were frustrated that tmpl part was quite poorly documented and was difficult troubleshoot. We gave up on it, although we all loved the core knockout...

    ReplyDelete
  10. I think ultimately knockout.js is likely to switch to using JsRender by default. (Particularly because like knockout itself, JsRender has no jQuery dependency - and also because now it is clear jquery.tmpl will stay at Beta1).

    Another interesting aspect is how knockout relates to JsViews. They both have a concept of observable objects and arrays, but knockout requires observability to be embedded in the MVVM wrapper classes. JsViews has a more lightweight observability layer which is independent of MVVM classes (and which is likely to be shared with jQuery UI, and potentially some other platforms too).

    ReplyDelete
  11. Great templating engine! Is there a way to skip HTML encoding on certain JSON properties? {{=HtmlEnabledText}}

    ReplyDelete
  12. @Vincent: Yes, absolutely, you can use alternative encodings, or none at all.

    For no encoding, add an exclamation mark (bang) as in {{=name!}}.

    You can also register custom encoding functions, and then use them as in {{=name!myEncoding}}.

    {{=name}} is equivalent to {{name=!html}} - the default encoding.

    See sample:no-encoding for a simple example.

    ReplyDelete
  13. I just wish there was an easier way to do simple comparisons. For example, in jquery.tmpl, you could do:

    <div class="base{{if varName == 'None'}} none{{/if}}">${varName}</div>

    However, this simple comparison is much more difficult in the new engine. First, you've got to set:

    $.views.allowCode = true;

    And then your template ends up looking something like this:

    <div class="base{{* if($view.data.varName == 'None'){ result += ' none'; } }}">{{=varName}}</div>

    This is quite a bit more complicated to implement and much more difficult to interpret.

    Any chance of being able to implement something like:

    <div class="base{{#if equals(varName, 'None')}} none{{/if}}">{{=varName}}</div>

    Where maybe we have some functional helpers like equals(), not(), gt(), lt(), gte(), lte().

    I can understand dropping to code view for more complex operations, but it seems like there should be a way to at least perform some simple comparisons w/out having to drop to the overly complex code syntax.

    ReplyDelete
  14. After some research, you actually can do simple conditional logic in your templates:

    http://blog.pengoworks.com/index.cfm/2011/10/21/Using-simple-conditional-logic-in-JsRender

    ReplyDelete
  15. @Dan: Yes, as you point out in your blog, this feature is indeed already there, though only added very recently. But you are right that it is quite likely to change. I'm exploring a couple of alternative approaches, since the syntax of the current implementation (and some aspects of the behavior) are not as intuitive as I would like. I absolutely agree that this scenario needs to be provided for without having to fall back on code or on creating custom tags...

    ReplyDelete
  16. @Dan: Heads up that I have removed the eq/ne etc. feature because a better design is on the way... Hope to get it committed within a few days...

    ReplyDelete
  17. I am very disappointed to hear about the decision to drop jquery tmpl, which seems to be a part of some political fallout between MS and the jQuery team.

    I would be very interested to know the reasoning behind all of this. jQuery tmpl was going in the right direction, and I find it fascinating that you were told by the jQuery team not to continue to fix the template engine. Sounds like political needs come first over the needs of the users of jQuery.

    ReplyDelete
  18. @Matt: No, there has not been any fallout at all between MS and jQuery. Indeed we are continuing to collaborate very actively, and the jQuery UI team are providing input to the design of JsRender, with a view to using it within jQuery UI. (Note that it is too soon to know for sure whether or not it will be used by the new jQuery UI Grid, for example, but it is very likely...).

    I pointed Richard Worth from the jQuery UI team to your comment, and he may add a comment here to give more context on their current direction.

    In fact the purpose of this blog post was also to provide some more informative context beyond what is currently on the jquery.tmpl repository and the jQuery documentation site, to help understand the plan. My personal recommendation to users of jquery.tmpl is not to move to JsRender yet. Stay with your current jquery tmpl templates for now, until JsRender comes out in a Beta version. At that point, it will probably be a good plan to make the switch to JsRender...

    ReplyDelete
  19. Yes, I want to follow up on what Boris said both in this post and in his last comment (just before mine). The jQuery and jQuery UI teams continue to work quite closely with Microsoft and with Boris as well as with all other parties interested in the future of a supported template plugin within the jQuery project. We have a close and positive working relationship. Microsoft is a generous and dedicated sponsor of the jQuery UI Grid project, of which Template plays a large part.

    If there was any kind of political fallout whatever it was 100% internal within the jQuery project, though I wouldn't categorize it as such. The two blog posts Boris linked to above tell the story pretty well, and there isn't really anything that's missing, as far as what happened. I'll provide the links again for convenience:

    Oct 2010 http://blog.jquery.com/2010/10/04/new-official-jquery-plugins-provide-templating-data-linking-and-globalization/

    Apr 2011 http://blog.jquery.com/2011/04/16/official-plugins-a-change-in-the-roadmap/

    So in late 2010 the jQuery project accepted code contributions from Microsoft and told the world more or less "these projects will have official support from the jQuery project going forward"

    About 6 months later it was clear that the sub-team that was to be stood up within the jQuery project to manage these and other projects like it (in many cases, plugins that would be inside of jQuery core if it weren't for filesize) hadn't come together. Unfortunately this meant for about 6 months there wasn't a clear direction or project owner/manager within the jQuery team for these important pieces. Upon recognizing this we talked internally and said more or less "either we create this official plugins team we said we'd create and make it function, or we decide that plugins have to live within existing sub-teams such as jQuery Core, jQuery UI, or jQuery Mobile". As explained in the second link just above, we decided on the latter. That's pretty much it.

    The impact on the globalization plugin was the jQuery UI team took it over and has pretty much finished the major changes it initially set out to make. These are explained at http://blog.jqueryui.com/2011/10/state-of-the-jquery-ui-grid/

    The impact on the data-link plugin is no sub-team within the jQuery project has decided to adopt it (or something like it), at least for now. The strongest candidate sub-team would be jQuery UI, and it's under review.

    The impact on the jquery-tmpl plugin is the jQuery UI team decided to release and support a template plugin that they design and build per there normal process. We worked really hard on the wording in the April 2011 post, I quote

    "The jQuery UI project will take ownership over plugins on which it has a current or future dependency: Templating, Globalization, and bgiframe. The jQuery UI team plans to begin work anew on templating and globalization, starting with the normal process for UI plugins: Collaborative development on a spec. While some may perceive this as a setback, given existing progress on the current jquery-tmpl plugin, it is really an opportunity for us to work in tandem with the community — Microsoft included — to develop an implementation that will be effective and flexible."

    so I think that's a more accurate description than what Boris wrote in the above post

    "From that point the version of jQuery Templates at jquery/jquery-tmpl was owned by the jQuery UI team." (continued...)

    ReplyDelete
  20. (...continued) Oct 2010 was the point at which the jQuery team owned the jquery-tmpl project, as of it moving into the jQuery GitHub project. The jQuery UI team has never taken ownership of the jquery-tmpl plugin. That was certainly an option, but it isn't what happened. What happened was the jQuery UI team took responsibility for a future supported template plugin as an official part of jQuery UI, and consequently an official template plugin for the jQuery project. I feel that's an important distinction. So it wasn't that the jQuery UI team said "don't work on jquery-tmpl" it was that the jQuery team said "WE're not going to work on jquery-tmpl any longer. jQuery UI is going to own a supported template solution for jQuery within the jQuery UI project. As to what that will look like and how they'll go about designing and building it, you'll have to talk to them" and if you talked to us and asked "When's the next version of jquery-tmpl coming out?" we'd say "As we develop specifications and requirements for the jQuery UI Template plugin, we're evaluating all popular and interesting jQuery and JavaScript template engines, including jquery-tmpl. One or more of these may serve as a starting point, but regardless we'll learn what we can from any and all."

    All this work was done in the open and included members of the jQuery UI team, Boris (from Microsoft), Mike Samuel (from Google) as well as many community members and jQuery team members, such as Yehuda Katz and Rick Waldron. Here are some examples:

    http://jquery.org/updates/2011/05/01/grid-status-update/
    http://jquery.org/updates/2011/06/20/grid-status-update-8/
    http://jquery.org/updates/2011/06/22/grid-status-update-9/
    http://jquery.org/updates/2011/07/19/grid-status-update-10/
    http://jquery.org/updates/2011/07/27/grid-status-update-11/
    http://jquery.org/updates/2011/08/04/grid-status-update-12/

    As more time went by, it became clear that many fundamental design decisions made during this process rendered jquery-tmpl an unsuitable candidate as a starting point for the jQuery UI Template plugin. The more clear that became, the more we felt it necessary to communicate to people that we wouldn't be putting anything more into jquery-tmpl, and that our next template plugin would be different, likely significantly different. It's too early to say more than that, because we don't know much more than that at this point. What we do know we've said and will continue saying on http://wiki.jqueryui.com/Template/ and http://wiki.jqueryui.com/Template-Comparison and http://blog.jqueryui.com/

    ReplyDelete
  21. jQuery is a mostly-volunteer organization with limited resources so we have to focus on a few priorities.

    Fortunately, this isn't a scenario where there is a gaping hole that nobody has filled. There are plenty of templating systems out there for nearly every situation. I saw Boris' jsRender/jsViews talk at jqcon a few weeks ago and it looks sweet. There is also mustache.js and Yehuda's handlebars.js enhancement to it. I've used mustache.js with jQuery on several projects and it worked well.

    Nobody involved is discouraging anyone from working on the current jquery-tmpl plugin, it's all there in the Github repo. Create a fork and modify it, or work with others to add features and fix bugs. If you're currently using jquery-tmpl on a project and it works, there is no urgent need to swap it out.

    ReplyDelete
  22. Hello,

    Is there any update on eq/ne? I'm working on a simple project that needs some simple conditional logic in an {{#each}} loop. Thank you!

    ReplyDelete
  23. Or perhaps a better question would be how can I accomplish the following. I'm looping through an object array and need to check the "Name" property of the current item in the loop. I realize my JsRender syntax isn't quite right. What would be the proper syntax?
    {{#each Properties}}
    {{#if .Name eq= 'Description'}}
    {{=Value}}
    {{/if}}
    {{/each}}

    ReplyDelete
  24. @Magnum: There is a major update on its way, which I think will allow you to do:
    {{#each Properties}}
    {{#if Name==='Description'}}
    {{=Value}}
    {{/if}}
    {{/each}}
    I'm just validating some scenarios before committing the update. Should be this week...

    ReplyDelete
  25. Boris,

    Thanks for the follow-up. Sounds great - I look forward to the next update!

    ReplyDelete
  26. I just made a major update to JsRender and JsViews which provides a lot of new feature support, including using comparison operators, as in {{#if name==='Description'}}
    or {{#if amount<100}}
    or {{#if person.role!=null}}.

    In addition, there is support for registering helper functions and calling them from within the tags, such as:

    {{=$ctx.format(name, "upper")}}

    or accessing getter methods on the data (view model) such as

    {{=person.fullname('last_first')}}.

    Many other things too - some of which are shown in the samples: borismoore.github.com/jsrender/demos/index.html.

    ReplyDelete
  27. Boris,

    As I can see on github page for jsrender:

    > Optimized for high-performance pure string-based rendering, without DOM or jQuery dependency.

    Do you mean to make it possible to use jsrender from server nodejs/Rhino environments, for example?

    ReplyDelete
  28. @C.III: Yes absolutely, that is an intended scenario. Some folks are already looking at creating nodejs wrappers for JsRender. You may be interested in this discussion (on a jquery-tmpl issue) which talks about related things...

    ReplyDelete
  29. Boris,

    I like where you are taking JsRender; great job! I'm evaluating the merits of JsViews vs Knockout. I read your reply to Felix, but I'd like to know why you went down the route of JsViews instead of joining forces with Knockout and Steve Sanderson.

    For example, the current landscape for these libraries is that one could use KO and JsRender, or KO and its native templates, or use JsRender and JsViews. Its great to have options, but I'm struggling to really see the pros and cons of JsViews compared to KO. Can you elaborate please?

    John Papa

    ReplyDelete
  30. @John Papa: Steve and I did discuss the idea of 'joining forces'. But one thing we were not able to overcome was a fundamental difference in the concept of observability between the two platforms.

    KO's philosophy is I think more of a turnkey: 'do it like this' approach, and everything will ‘just work’. So it requires the data to be wrapped in KO observable classes, which then allows KO to determine dependency graphs based on calls to the getter. It automatically adds listeners (registers subscriptions) to listen for observable changes – based on the call graph.

    JsViews has the goal of interoperability: it does not impose any specific data model pattern, but lets you use any approach you want, from using simple raw javascript objects and arrays obtained directly from JSON requests, to using MVVM or other wrapper classes as your (view) model. It also seeks to be less ‘eager’ in adding listeners. It adds listeners based on how you specify your bindings, rather than adding listeners to all data objects, even when the data may be immutable, or at least is not expected to change in the scenario being targeted. In JsViews, you specify when you want live data binding by using the declarative syntax: data-getfrom="a.b[c.d]". In this example, the square brackets tell JsViews that you want to listen to observable changes when the 'c' property of 'b', or the 'd' property of 'c' change, but not when the 'b' property of 'a' changes.

    Also JsViews tries to avoid adding any markup or DOM elements that you don’t explicitly include in your template markup or code. So JsViews will not wrap your specified content in additional DIVs, for example. JsViews will do live binding when collection change events occur on arrays, and will add and remove rendered template instances, without requiring (or adding) an element wrapper around the template. The way it achieves that is by adding HTML comments as markers for the nested views structure of your rendered HTML. So it is adding content, but not at the level of modifying the element hierarchy of the HTML content.

    KO takes a somewhat different approach, and as I understand it, does add wrapper divs in some scenarios. (Also I personally worry that the KO automatic dependency graph computation may not be robust, in that I have not understood how all possible call paths are exercised. And it worries me that KO is actually instantiating objects or making getter calls under the hood in order to exercise those call graphs and hence attach the appropriate listeners. But I may be missing some details on how it works.)

    ReplyDelete
  31. Boris,

    Thanks for the detailed explanation on JsViews and KO. I'm very eager to dive into JsViews to see how it could be used to build an app. I've got some great KO examples and would love to do some comparisons side by side.

    I love what KO does for me, but I would prefer if I did not have to create observables to wrap the properties. Consider my point of view more of a POCO approach where the classes are not wrapped. Other than this, KO has been excellent and its a small price to pay for a great data binding ramework in JavaScript. A solid data binding library really helps create apps quicker and make them more maintainable. I see more and more companies moving towards HTML5 and JS with larger dev teams. So maintenance, consistency, separation of concerns, and scalability are important. KO brings this now. But again, I am VERY excited to see how JsViews shapes up.

    Thanks again.


    -- John Papa

    ReplyDelete
  32. Boris, I've just stumbled across this and am now considering JsRenders and JsViews for possible use on a new project. KnockOut is another alternative, but I do like the way you can make plain objects observable (although see my second question below), plus it seems this project is the future for official jQ templating (despite Richard's somewhat non-committal info?) I have two questions:

    1. What is the reason for the naming convention of "data-getFrom" vs "data-to" (or "getFrom" vs "to" properties in options for addLinks)? Wouldn't "data-from" be more concise and symmetrical? I'm guessing there's some reserved word conflict, but I don't see it?

    2. Is there any way to wrap calls to $.observable().setProperty() inside property setters in the parent object, in order to make all assignments to that property trigger binding updates? Or will that just create an infinite loop?

    Thanks, and keep up the good work.
    Tim

    ReplyDelete
  33. I'm trying to make a very basic test with 3 fields, where field3 = field1 + field2 (eg a calculator that adds two numbers)

    It appears I can use data-getfrom="[someFunction()] which is pretty awesome. However I then need to watch for property changed on field1 and field2 to manually trigger field3 updates? Is there an easier way to do this?

    ReplyDelete
  34. @fineline (Tim): there are three binding attributes you can use:
    a) data-to updates the target data when the UI value changes
    b) data-from updates the target UI when the source data changes
    c) data-getfrom is the same as data-from except that it also updates the target UI when you first link it to the data. It initializes, if you will.

    For your second question, it depends what you mean by the parent object. If you are referring to an object wrapping your data, with a setter on it (i.e. you are using a view model class, or equivalent, wrapping the data, rather than just using plain objects) then yes, you can certainly include a call to observable setProperty within that setter. It shouldn't lead to a loop.

    ReplyDelete
  35. @Betty: If calculatedField is a helper function, taking two parameters, not actually a field on your data then you can do as follows:
    data-getfrom="calculatedField([field1], [field2])"

    Examples in the demos:
    code: data-getfrom="html: homeTown([firstName], [lastName], address[city], true)"
    code: data-getfrom="$ctx.yesNo([content], content, 'empty todo...')"

    If you in fact have setters and getters, so you are using a VM wrapper or equivalent, then if you follow the convention that the function field1 and field2 are each both a setter and a getter (behaving as a getter if invoked without a value: var val = data.field1() and a setter if you pass a value:
    data.field1(newValue)...), then if field3 is a calculated field on your model (a getter that depends on field1 and field2) everything can work.

    What you do is to treat field3 as if you were passing it parameters, in order to tell JsViews that it depends on field1 and field2. In fact field3 can ignore parameters and simply return the calculated value:

    <input data-getfrom="[field1]" data-to="[field1]"/>
    <input data-getfrom="[field2]" data-to="[field2]"/>
    <span data-getfrom="field3([field1], [field2])"/>

    ReplyDelete
  36. @boris Awesome!

    <span data-getfrom="[field1+field2]"/>
    also almost appears to work, except that the dependencies on field1 and field2 aren't hooked up, pity because that would have been fairly clean

    ReplyDelete
  37. This is really fantastic! I've been playing with this all day and have come across a question I couldn't answer with the demos:

    Say I have:

    var someJSON = {
    aProperty: [
    {id:43, data:'value'},
    {id:67, data:'other value'}
    ]
    }

    How do I return just the first object in the array of aProperty?

    I tried {{=aProperty[0].data}}

    Also, how would I return a value in the array aProperty that matched a specific condition on one of it's properties, say id == 67?

    ReplyDelete
  38. @Zachariah: Because of the 'codeless' philosophy, the idea is that {{=dataExpression}} does not allow generic JavaScript expressions. dataExpression is basically limited to dot-separated paths, strings, numbers, function calls, and simple comparison tests. In any other case, you have to put your code in a helper function. (Separation of concerns - no code in the markup).

    So in your first case you could do:

    {{=$ctx.getArrayProperty(0,languages,'name')}}
    where getArrayProperty is declared as:

    $.views.registerHelpers({
        getArrayProperty: function(i, data, property) {
           return data[i][property];
        }
    });

    You can use a similar approach for the second case too.

    ReplyDelete
  39. Hello Boris,
    Is there any way we can pass the entire array to template?

    I mean in examples I saw that template is repeated depending # of items in array but can I pass entire array to template just as JQuery Template does?

    ReplyDelete
  40. @Sunny: The default behavior is to iterate over the items of an array, and concatenate the results. But of course you can pass your array as a property of an object, by doing
    $.render({ people: peopleArray}, template);
    and then access the array as
    {{=people.length}}
    or
    {{#each people}}
    etc., within the template.

    You can also pass an array (or any other 'secondary' data) in as context by doing
    $.render( data, template, {people: peopleArray});
    and accessing it as
    {{each $ctx.people}}
    etc.

    See also the related discussion here.

    ReplyDelete
  41. Hi Boris, thanks for the clarification and all the work you have done. I am curious, will jsRender / jsViews support the possibility of putting template in an external file?

    ReplyDelete
  42. Hi Boris, I need a better documentation, something like a tutorial, I wrote an application that render a table and clicking on cell open an input box, then with return or tab the new value is stored in a data that could be sent to server as json to store in db. I have done it with current jquery template.

    I would know if and how I can implement this with render and view, view sound good for application.

    It would be wonderful if you write an example like that ;)

    ReplyDelete
  43. Hello Boris, I'm using jsViews on my project to render a news feed like facebook's. I'm using {{#each comments}} for comments with a nested template. I wanna show last 3 comments only, so i need to know each's index. How can I get it or are there any better way to do it with jsViews?

    ReplyDelete
  44. Thanks, I solved this problem with a helper function and I wanted to share, but still I don't know if it is a good solution.


    CommentVisible: function (view) {
    if (view.parent.data.length > 3) {
    if ((view.parent.data.length - (view.itemNumber - 1)) > 3) return "display:none";
    }
    return "";
    }

    ReplyDelete
  45. @Ibrahim Varol: That approach is rendering all the items, but hiding the earlier ones. An alternative, if you want to render only the last three would be to register a helper along the lines of:

    $.views.registerHelpers("last", function(arr, n){ return arr.slice(-n); });

    then use it as follows
    {{#each $ctx.last(comments,3)}}

    See also the related issue here: https://github.com/BorisMoore/jsrender/issues/22

    ReplyDelete
  46. @Daniele: Documentation will get better as we reach Beta. Currently my priority is to get to Beta quality, and make any necessary changes to APIs ready for Beta. That way we can avoid breaking changes after Beta. You scenario should work fine with JsRender and JsViews, but if the current samples are not enough to help you port from jquery templates, I would encourage to to wait for Beta. It will be easier then, and more stable. :)

    ReplyDelete
  47. @Boris Moore That approach in the related issue, looks more robust. I'm now familiar with observables.I'd really like the beta version. Thank you :)

    ReplyDelete
  48. How much did Google pay to kill (Microsoft's) jQuery templates?

    ReplyDelete
  49. @tullandaa: This blog post tries to give an honest and accurate account of the current status of jQuery Templates. We should be glad that there is an independent open-source movement, and that big and powerful companies like Microsoft and Google are actually contributing to that movement. They are doing so because open-source is successful and it is in their interest to collaborate. I don't think random suggestions of undercover manipulation helps the open-source movement very much. Let's encourage collaborative efforts that we see, and not make accusations if we don't have any real evidence that they are actually well-founded.

    jQuery Templates was never 'Microsoft's'.

    This is just my take, but I am fairly well placed to know what I am talking about :).

    ReplyDelete
  50. This sounds and looks promising, but I'm curious what you would recommend right now for a high traffic site. I'm definitely wary of using something that is not even beta, but I also don't like the idea of jumping in with something that has been deprecated. I have also been looking at handlebars.js, but the performance implications for mobile worry me a little.

    ReplyDelete
  51. @Jason: I mentioned in another answer above: "My personal recommendation to users of jquery.tmpl is not to move to JsRender yet. Stay with your current jquery tmpl templates for now, until JsRender comes out in a Beta version. At that point, it will probably be a good plan to make the switch to JsRender...".

    Now if you are not already using jquery.tmpl, but creating a new site, or new content, then it's your call. You will need to deal with any breaking changes - some of which will be coming very soon.

    I hope JsRender will be at Beta by the end of February, but if you need JsViews too, that will take a bit longer...

    ReplyDelete
  52. Hi Boris! Been working with jsrender/view now for a while and I think it's great. Good work!

    I changed from using render to instead using link, and now {{=$itemNumber}} is always 1. Am I doing something wrong? Or do I need another approach?

    This is how i bind: $("#table-clients").link(clients, "#clients-template");

    This is my insert: $.observable(clients).insert(clients.length, data.d);

    This is my template:
    <input type="hidden" name="clients-{{=$itemNumber}}" value="{{=UserID}}" />

    Thanks in advance!

    ReplyDelete
    Replies
    1. @erik: When you insert a new item, JsViews detects the observable change and asks JsRender to render just the inserted item, which it then inserts into the HTML at the right point. JsViews is optimised for perf and for maintaining state on the other rendered items - so does this rather than rendering the whole list whenever you insert or remove an item.
      See this sample for data-linking to the index of the item, so that even if you insert items above, the index is fixed to be correct, thanks to data binding. But for your scenario you can either use some kind of ID property on the data if available, or you can provide a helper function to return the index of the data in the array: {{=$ctx.indexInArray($data,$parent.data)}}.

      Delete
  53. Any plans to get these onto Nuget?

    ReplyDelete
    Replies
    1. @omegaluz: Yes, I hope we will do that, but not until after Beta.

      Delete
  54. Added a method to ObservableArray:
    sort: function (method) {
    var oldItems = this._data.slice(0);
    this._data.sort(method);
    triggerArrayEvent(this._data, { change: "refresh", oldItems: oldItems });
    return this;
    }

    ReplyDelete
  55. My only issue with my sort function is it resets everything back to the original template, so items that were in edit mode switch back to view.

    Should I be using a property on each item to store its current mode instead of just setting .tmpl?

    ReplyDelete
  56. @Betty: Yes, if you want different templates to be used by different items, or a single template that renders differently for different modes, then you will need to store that state somewhere, either on the data, or via helper functions on some other parallel data store. There is a plan for providing a 'presenter' feature later which will allow you to instantiate a presenter object associated with each view item. So you would use that to carry state, and not have to bake it into the data. But for now, the simplest way is just to use the data.

    ReplyDelete
  57. I'm trying to figure out how to do a simple if condition:

    [select]
    {{#each Planets}}
    [option value = "{{=name}}" {{#if name === from}}selected{{/if}}]
    {{=name}}
    [/option]
    {{/each}}
    [/select]

    "Planets" and "from" are both passed to render(), but I'm not sure how to reference "from" from inside the each loop

    ReplyDelete
  58. @Dylan: The content of the {{each}} tag is a nested template, so it renders a nested view for each Planet. You can get to the view object by using $view, and then get to its properties, including its data property (the current data item) or step up through parent views and get to their data items. See this example.

    So in your case you need
    {{=$parent.parent.data.from}}.
    $parent is short for $view.parent, so $parent is the parent view (which has the Planets Array as data item), and $parent.parent is its parent view, (which has as data item the object with the Planets and from properties).

    ReplyDelete
  59. Thanks Boris - that did it! I think I was seeing $view in the examples and dismissing the example because I'm not (yet) using jsViews.

    Thanks for responding so quickly.

    ReplyDelete
  60. Hello again, my problem is with each this time too. I'm trying to do client side paging. I've tried two method to do that. First, I tried this:
    {{#each ViewData.Documents.splice(Page*ViewCount,Page*ViewCount+ViewCount) tmpl="#DocumentItem"}}
    {{/each}}
    When i use this method, it does not update on methods like sort, filter or with any update.
    ---
    Second:
    {{#each $ctx.PageView(ViewData.Documents,Page,ViewCount) tmpl="#DocumentItem"}}
    {{/each}}

    Second method does not work correctly because, it can not find $ctx.PageView function after first call for an unknown reason. When I do a debug "$context" parameter seems undefined.

    What can I do? Thanks.

    ReplyDelete
  61. @Ibrahim: What you are doing is a fairly advanced scenario, and should definitely be possible with JsViews. However you are getting into some features which play on the strong integration between JsViews and JsRender - using the {{#each}} along with fairly complex observable data-linking. I am working hard trying to get an update out for JsRender which is close to being a Beta candidate, and a version of JsViews that integrates with that. There are quite a few major changes coming; it will be both simpler and more powerful. My next stage will be to take JsViews towards a Beta candidate too.
    So I won't spend time trying to help you solve your scenario with the current bits, since would probably be better to hold back on your paging scenario until the Beta candidates are available... If you need to do it with current bits, then you're kind of on your own there :-) and will just have to debug into it and figure!

    ReplyDelete
  62. Ok, thanks. I will hold back it until the beta candidates are available. :)

    ReplyDelete
  63. Maybe I'm confused at how helpers work, but shouldn't in the following example these methods be identical?

    In the helper tags test, the helper function only alerts during initialization, whereas in the function test, the alert triggers on every update outside of initialization.

    #modifications from 06_data-binding2.html

    data-getfrom="[firstName]" data-to="[firstName]:{{=$ctx.test($value)}}"

    data-getfrom="[firstName]" data-to="[firstName]:test($value)"

    $.views.registerHelpers({
    test: function( value ) {
    alert('test');
    return value;
    }
    });

    function test( value ) {
    alert('test');
    return value;
    }


    On a side note, I'd be very interested in seeing a MVVM example.

    ReplyDelete
  64. @Tom Sieverding: The data- attributes are about data-linking and can result in code running each time the data is modified, or when the user interacts with the element. But the {{}} tags are JsRender template tags which are used to render, and that's all. The {{=...}} tag will only run during rendering, not when the user clicks on the text box. (JsRender is all about pure string-based template rendering and knows nothing about HTML elements or interactivity.)

    ReplyDelete
  65. I still feel like the decisions to abandon jQuery Templates, regardless of motivation, hurt the community as a whole.

    Many of us were excited enough to jump onto a beta product, caveat emptor and all, only to have the rug pulled out from under us.

    Then, rather than at least moving forward with the existing stuff, we're left hanging in the wind with no options but to wait for someone else to write something completely different (barring forking and maintaining jQuery tmpl ourselves).

    So, it's been 16 months since the decision was made, and we have nothing new to use. In software development time, that's an eternity.

    Regardless of the motivations, it left me with a seriously bad taste in my mouth and makes me hesitant to use anything new produced by the jQuery team for fear of another "oops! we changed our minds! message.

    ReplyDelete
    Replies
    1. I agree, we had something working and then all of a sudden let's make something entirely new! It will be much better, blah blah - then over a year with nothing to use on a production site... it seems to be the norm with jquery core development, this pulling out the rug, just look at what happened with the plugins site for example...

      Delete
    2. Why do people always come from a position of assuming that free software is somehow obliged to be written the way they want it with the features built how they want it? It's free. You didn't pay for it, or contribute to it, or anything. So what makes you think you have a right to complain when something is changed?

      If you want a feature that is removed, just fork it and do it yourself, or pay someone to do it for you. No one owes you anything!

      I'm not actually trying to be mean or antagonistic here, but I wanted to point out that the default position should be one of "thanks for whatever effort you've put in" rather than "it doesn't do it the way I want it so you suck".

      Delete
  66. Hi Boris. First, very impressed with jsRender & jsViews; can't wait til they go beta. Second, a question - how can I maintain document context in nested templates? For instance, let's say I have the following markup in an iframe:

    <script id="columnTemplate" type="text/x-jquery-tmpl">
    <td>{{=$data}}</td>
    </script>

    <script id="rowTemplate" type="text/x-jquery-tmpl">
    <tr>{{#each Columns tmpl="#columnTemplate"}}</tr>
    </script>

    <table id="myTable"></table>

    ...and let's say that I'm binding this from some javascript in the parent, outside of that iframe, like:

    $('#myTable', window.frames[0].document).html($.render(someData, $('#rowTemplate', window.frames[0].document)));

    The rows will get rendered correctly, but the columns won't. I suspect the #columnTemplate isn't being searched for in the context of its parent (the #rowTemplate), but instead being looked for in the outer parent document. Is that a bug? Is there a way to search for the #columnTemplate in the document context of the #rowTemplate (maybe by modifying {{#each Columns tmpl="#columnTemplate"}}?), or a workaround short of merging the nested templates into one?

    Thanks!

    George

    ReplyDelete
    Replies
    1. @George: I never replied to this, because use of different iframes, and templates declared as script blocks in the different iframe documents is an advanced scenario, and I don't have a specific proposal/pattern for controlling the access to those templates from different frames. In fact I think that more advanced applications would be advised not to use templates declared in script blocks, but instead use a service-based approach where in effect the templates are loaded (and then compiled) as strings. I expect to provide more specific support for those aspects in the future, but for now, it is up to each application to provide/choose an implementation, if more advanced template management is required.

      Delete
  67. Hi Boris,

    There's is a difference between template and layout. What I continually see repeated over the web, and here, is the template word being applied less correctly. Dictionary wise:

    template: "something that serves as a model for others to copy"
    layout: "the way in which the parts of something are arranged or laid out"

    I trust you will review it!
    Cheers

    ReplyDelete
    Replies
    1. JsRender is a client-side template engine. The term "template" has become standard in the Web for this kind of library, as well as for server-side technologies which render HTML content against data. See for example this Wikipedia article.

      Delete
  68. Hi! Is it possible to do data binding with conditional templates? I'm trying to write a login status template ("Hello, Unknown! >Login?<" vs "Hi, User123! >Sign out?<") that would re-render on data-bound property change.

    Is it possible (and I should look for a stupid error of mine), or maybe I should stop trying? :)

    ReplyDelete
    Replies
    1. @Artur: You can use the `visible` data-link target. Lot's of examples here: step-by-step/07_form-elements.html. Soon it will also be possible to bind to {{if and {{else - but not in the current version...

      Delete
  69. When is the beta going to come out... We want to use this in our new project, but I am not too sure if this reliable as of now..

    ReplyDelete
    Replies
    1. @Prashanth: For current status, see the JsRender readme, and also my response to that question here.

      Delete
  70. https://github.com/codepb/jquery-template
    what is the difference between your & this project?

    ReplyDelete
    Replies
    1. jQuery-tmpl is the official jQuery Templates plugin. See above for the history. (It was moved back to my GitHub project by the jQuery UI team, since I was the primary developer of jQuery Templates - when they decided no longer to develop it themselves)

      The project you link to above has no connection whatsoever to jQuery Templates. It was created a lot more recently, and the design and functionality are completely unrelated to jQuery Templates. They chose to give their templates the same name!! Probably they took advantage of the confusion to attract some interest in their project...

      Delete