Tuesday, March 6, 2012

Approaching Beta: What's changing in JsRender and JsViews

Major update to  JsRender and JsViews
In previous posts and elsewhere, I had set the goal of reaching beta for JsRender at the end of February. A major update has just been committed to GitHub for both JsRender and JsViews, which is effectively a beta candidate for JsRender.

This update brings a large number of API changes, new features, and improvements, to both JsRender and JsViews. It follows quite a period of apparent silence on GitHub (as far as commits are concerned), which left some folks with the impression that the project may have become inactive. The truth is quite the 
opposite. JsRender and JsViews are (in my view!) alive and well and growing apace...

So why the silence? In working on the new bits, I had to address the fact that the beta API design I was aiming for would be breaking for many users. Not a big deal usually for alpha software, but in the case of JsRender and JsViews there has been quite a lot of adoption already, so I wanted to avoid causing too much pain with a series of breaking commits. I decided to work on a single breaking update intended to provide a one-step transition to a beta candidate for JsRender (or at least a candidate for a stable beta API), and also introduce much of the future stable beta API for JsViews.

That update has taken a long time to complete, since it is a major rewrite not only of JsRender but also JsViews... The new bits for JsRender have been nearly ready for quite a while now, but the integration between JsViews and JsRender meant also moving JsViews a long way towards its future beta version. That way current users of JsViews can also port their apps to the new JsRender.

What's changed?
This post provides a guide through the changes, and is primarily intended to help existing users of JsViews or JsRender to move to the new version.

It can also be helpful to first-time adopters, but bear in mind that this is still not quite the official beta, so documentation is limited. I hope to provide more documentation (or update this post) as we move to the official beta for JsRender (fairly soon) and JsViews (probably end of April or early May...). In the meantime, take a look too at all the live samples and the corresponding code for JsViews and JsRender.

JsRender: principal changes
  • {{: ...}} and {{> ...}} tags: The basic tag for outputting data values, {{=some.data.path}}, is now {{:some.data.path}}, and supports converter functions, and almost any javascript expression, as in {{myConverter:someExpression}}.
    It is 
    not HTML-encoded by default.
    To HTML-encode, use the tag 
    {{>someExpression}}.
  • Block tags and inline tags: The syntax for block/inline tags is now similar to HTML element syntax in the use of the '/' character:
    • A block tag is written {{myBlockTag ...}} ... {{/myBlocktag}}.
    • A non-block (self-closing, or inline) tag is written {{myInlineTag/}}.
    • A block tag can become an inline tag if it references a template as content:
      {{myBlockTag ... tmpl="myNamedTemplate" /}}.
  • {{#each}} tag is now {{for}}: There was some confusion around the {{each ...}} tag, in that the name suggested that it only worked as an iterator over an array as in {{#each myArray}}...{{/each}}. In fact it worked also against singleton data objects, and this is made more intuitive by renaming it to {{for ...}}. This means you can write {{for myArray}}...{{/for}}, but for other scenarios you might also write  {{for myObject}}...{{/for}}, which will render against myObject as current data item (data context) for the nested content.
  • Expressions within template tags: JsRender template tags now support almost any JavaScript expression (and also allow parens, to any depth).
    For example, you can write:  {{if  price > 3 && price < (maxPrice - 10)}}Special deal{{/if}}.
    However, unlike with jQuery Templates, the expressions are evaluated within a parsing and execution context which precludes accessing global variables or running any code which arbitrarily assigns or modifies data or state. Only template data properties/methods and registered helper functions/parameters can be accessed. 
  • View properties syntax: To access view properties, such as parent, the syntax is now #parent.
  • $itemNumber is now #index: There is now a zero-based index, identical to the index on view objects when using JsViews. This change is thanks to expression support which has made getting a 1-based index very easy, as in: {{:#index + 1}}.
  • Helper functions: There is now a single concept of a helper function, which can be provided either via the options parameter in the $.render (or the $.link method, if using JsViews), or by registering using the $.views.helpers() API call.
    In either case, a registered helper function myHelper(...) will be accessed within the template using a simpler syntax than before: ~myHelper(...), rather than $ctx.myHelper(...). 
    F
    or example, you can write {{:~myFullNameHelper(firstName, lastName)}}.
  • Template parameters: In addition to helper functions, template parameters can be passed in with options or registered using $.views.helpers() - and then accessed by the same template syntax as helper functions, as in {{:~myParameter}}
  • Aliasing variables for use in nested contexts: If you want to access the data in a parent context, you can now provide a variable (accessed like a template parameter) which will be available within nested context. For example: {{for lineItems ~orderTitle=orderInfo.title}}...{{:~orderTitle}}...{{/for}}
  • Registration APIs: Registering of helper functions, converter functions and custom tags each use an equivalent API pattern: $.views.helpers()$.views.converters()$.views.tags().
  • Registering/compiling templates: This uses a similar API, $.templates(), which also allows defining template properties and resources (below).
  • "Intellisense-friendly" APIs for rendering:  New APIs are provided which are convenient for intellisense. For example, you can now write: $.render.detailsTmpl( person ); 
  • Template resources and settings: Registering templates now supports specifying individual settings for the template, and registering resources such as helpers, converters, other templates, etc. so that they are available only in the context of the registered template, and are not exposed globally to other templates.
  • Layout templates: A template may have a setting: layout: true. This will make it render just once, independently of whether the data supplied is an array, null, undefined, false, or any other data value. A {{for}} tag within the template will then render against the data in the normal way.
  • Debug setting: If a compiled template has the setting debug: true, a debugger; statement will be inserted at the beginning of the compiled template function. This makes debugging declarative templates easier.  
  • Unit tests:  JsRender now includes unit tests.
JsViews: principal changes
  • Views: Previously, both JsRender and JsViews had a concept of a view hierarchy, but the two were distinct. Now a single view hierarchy is created during rendering of templates (and nested templates) and the same view hierarchy is maintained (but augmented with additional methods or properties) during data linking by JsViews. 
  • Declarative data binding: data-fromdata-getfrom and data-to are now consolidated into a single data binding attribute: data-link. This provides for more concise and simpler data binding declarations that support both one-way and two-way binding. See the samples for different use-cases, including binding to multiple target attributes on the same HTML element.
  • Data binding expressions: Data binding expressions are evaluated according to the same contextual and parsing rules as template tag expressions. They can access exactly the same user-registered helper functions, template parameters, or converter functions that are available to template tag expressions - whether registered using $.views.helpers, or passed in with the options parameter in a render() call. In addition, helper functions and template parameters can be passed in with the options parameter of any link() call.
  • Automatic dependency detection :  In data binding expressions it is no longer necessary to put square brackets in paths to specify data-binding dependencies.
    <input data-getfrom="shipping.address[street]" data-to=" shipping.address[street] " /> is now written:
    <input data-link="shipping.address.street" />
    This opens the way to supporting [] syntax for array or property accessors.
  • "Intellisense-friendly" APIs for linking:  As with JsRender, JsViews now provides new APIs which are convenient for intellisense, such as:  $.link.movieTmpl( "#movieList", movies );
  • Disabling linking when rendering a template: If JsViews is loaded, rendered template were previously automatically data-linked. It is now possible to set link: false on a template, or as an option in the render call, or as a tag property: {{for link=false}}, to switch off data linking within a rendered template.
    This is useful, for example, if you want to include template tags within attribute markup, and suppress JsViews HTML comment annotations that were automatically inserted for data-linking purposes.
Missing, or not yet available features
  • Programmatic data linking: Programmatic data link APIs such as addLink have been removed. (They will probably return in modified form for JsViews beta)
  • Unit tests:  JsViews is not so close to beta as JsRender, and does not yet include unit tests. They will be added before it reaches beta.  
Performance and code size
In spite of the many new features, total minified code size for JsViews plus JsRender is similar to the previous update, and performance is slightly better. A performance test page is provided.

Specific examples of porting to the current design
The samples available at github.com/BorisMoore/jsrender (live here) and at github.com/BorisMoore/jsviews (live here) have been changed where necessary to work with current API calls and declarative syntax. In some cases there are new features available which would have provided a more elegant approach to the scenario shown, but the samples have generally been changed in a minimalistic way, to illustrate how to port to the new version. (More samples showing new features will be added at a later point, along with other documentation).

And from here?
The plan is to wait for some feedback or bug reports on this new update, before deciding whether to label this version of JsRender as the official beta. Once it has become beta, I hope to progressively add additional documentation.

In the meantime I will continue to work on moving JsViews towards beta. This may still take a while, since there are some significant changes and improvements in the pipeline. My hope is that it will be available late April or early May... 

219 comments:

  1. Can't say that I like the new {{: syntax over the {{= I found that conveyed the meaning better. In either case have you seen http://mustache.github.com/mustache.5.html

    I like their {{some.data}} syntax to just print variables directly

    I also liked using {{# for builtin tags and custom tags, is that still possible? It seems that the way to do it now is with {{:~ which I find awkward since it is yet more api types to remember.

    I have been using jsrender on my website as a nice replacement for jquery templates that is why I am not sure I like the new api changes and found the older styles a bit more intuitive.

    ReplyDelete
  2. @Roman: The {{:some.data}} comes into its own when you use converter functions. For example, {{html:some.data}} does built-in html encoding. There are many scenarios where you want to provide your own converters, whether for encoding, rendering of dates, custom formatting, etc. The previous syntax of {{=some.data!html}} was I think less intuitive, and did not scale to allow two-way data binding syntax (with JsViews) where there is both a convert and a convertBack.

    Mustache (and also Handlebars) use the {{#foo}}...{{/foo}} syntax not for custom tags in general but for sections (or blocks). So the # is not an indicator of a custom tag.

    By the way, the syntax for custom tags in JsRender is simply {{myTag}}, not {{:~...}}. The {{:~myHelper()}} syntax is for calling helper functions, not custom tags, and corrsponds to what was {{=$ctx.myHelper()}} prior to this update. So it is definitely more compact and simple now.

    Mustache is designed for working directly with data paths without providing the concept of custom tags, so can reserve {{foo}} for data paths, but in JsRender {{foo}} is, as I say, a custom tag. (Handlebars does have custom tags, and also retains the direct {{some.data}} syntax, but this introduces a collision path if you have custom tag called 'some', and a data path 'some').

    That said, I think it is difficult to judge a new syntax (particularly after having got used to another one) until after playing with it for a while, and seeing how it feels in different scenarios. So I hope as you get used to this, you will begin to like it more!

    ReplyDelete
  3. Congrats Boris! I am very excited about the upcoming beta release. I like the changes you made so far ... most of my pages took only a few minutes to update. The biggest changes were that I no longer had to use a helper function in many places ... converters and tags became more powerful.



    Looking forward to the final beta!

    ReplyDelete
  4. Hello, thanks for the library! I have issue using the new version with check box.

    Previously, I used this:
    data_getfrom="checked:[Alarm]", data_to="[Alarm]"

    And now, if I used the following, it would not work:

    data-link="checked:Alarm"

    What should I do?

    Thanks.

    ReplyDelete
    Replies
    1. I think I will be able to update JsViews so <input data-link="Alarm" type="checkbox"/> will be all that you need. However, for now, you can use <input data-link="checked{:done} {:done:}" type="checkbox"/>. See this issue for more detail/explanation...

      Delete
  5. @Boris I do like the custom formatter use case. I will keep an open mind and try the new syntax :) Time to go update my node.js port.

    ReplyDelete
  6. Hi Boris,

    We (my team) are trying to update the jsRender to the new version and I think we found one bug.

    If you do not pass any object to the render function, it fails without any error message.

    i.e : render();

    We have fixed that by passing an empty object like render({});

    Even if it is bad form to render with an empty object, I think it should throw an error.

    Thanks

    ReplyDelete
    Replies
    1. Well, render() does not fail, it returns an empty string. That is by design, and is similar to {{for billingAddress}}, which should not throw an error if billingAddress is undefined (or null) - it should assume there is no billingAddress to render a template for.

      Previously the behavior was a bit different, but I believe the new behavior works better for more scenarios. This design choice was made also in the light of the fact that you can now switch to an opposite behavior by using the new 'layout=true' property. If you can declare a template as a 'layout' template, it will make it it render once, whether or not you pass data to it. (Even for an array, it will render once, and you can then have the template include a header section, followed by {{for}} - which will render out the items - followed by a footer section, for example).

      See the unit tests here and here, for mini examples of the current behavior/design.

      Delete
    2. Hi Boris. This is great library, thank you!

      I have one stupid question: where I should specify that layout = true property?
      I tried to add it as a property of my template object, but it doesn't work.

      // template is jQuery object
      if (!data)
      {
      //data = {}; // this works, html is not empty
      template.layout = true; // this doesn't work
      }
      var html = template.render(data);

      Looks like I'm missing something really simple, can you give some advice?

      Delete
    3. @Graycrow: I don't yet have examples of using the layout feature in step-by-step but there are examples in the unit tests. Take a look there. To mark a template as a layout template, use the following syntax when you declare it:

      $.views.templates( {
      myTemplate: {
      markup: "Content",
      layout: true
      }
      });

      The value of the markup property can be a template string, or the selector to a template script block: "#myTmpl".

      Delete
  7. Hello Boris,
    Great work. I have only one issue with the new code.

    I could do:

    {{#each ['a','b','c']}}
    {{=$data}}
    {{/each}}

    But this doesn't work in the new code:

    {{for ['a','b','c']}}
    {{:#data}}
    {{/for}}

    I can use a helper function eg:

    arr : function(a) {
    return a.split(',')
    }

    {{for ~arr('a,b,c')}}
    {{:#data}}
    {{/for}}

    But that's way more code :-)

    ReplyDelete
    Replies
    1. Another approach you can take is to pass in arr = ['a','b',c'] as a template parameter. Either register it using $.views.helper() or pass it on the options parameter of render() or link(). Then you can do {{for ~arr}}...{{/for}}

      The new design does not parse literals, just as it does not let you give it global variables. ({{for someGlobal}} will not work). This is part of the 'codeless' philosophy, which prevents JsRender executing 'random' code. OTOH expression support is very full, so you can use parens, for example, quite freely in your expressions. And you can use [] as accessors, e.g. {{:phoneNumbers[0]}}. But your example above is different, since the [] literal there is in fact the array constructor...

      Delete
  8. Thanks for the feedback so far. To those who posted questions on how to port specific examples or scenarios, I will try to answer each one, but it may take a few days.
    Bug reports are appreciated too, but it is usually better to post them to the Issue Trackers on JsRender and JsViews, rather than on this blog... Thanks!

    ReplyDelete
  9. I didn't use JsRender/JsView before but used Handlebars. I wonder what's a conceptual difference (if any) between JsRender/JsView and Handlebars?
    We have our own data-binding engine and integrated it with HB with custom helpers. Something line this:
    <input type="checkbox" {{data-bind checked="prop1.prop2"}}/>
    data-bind - is our helper function. It outputs html markup "id='..'" and creates a callback which find the element by generated id and establish a data-binding link.
    We laso had to customise HB to allow it to support functions (not only fields) in data paths.
    Can we use JsRender in the same way? Does JsRender have any advantages?

    ReplyDelete
  10. JsRender is essentially a superset of Handlebars. JsViews adds integrated data binding on top of that.

    JsRender is a lot smaller than Handlebars. It is slightly faster for rendering (and a lot faster for compiling). Take a look at this perf comparison and try it in different browsers.

    It does support functions in data paths, and also provides many other features such as custom encoders/converters, passing in template parameters in addition to data, custom tags that don't collide with data paths, composition of templates associated with any tag, full javascript expression language within tags (but limited exclusively to expression evaluation, without allowing access to global variables or functions, or variable assignment or mutation of any kind), and more. There is a fairly rich set of samples here and here, which you can explore to get an idea of the extensibility and the range of features.

    ReplyDelete
    Replies
    1. Thanks for the description! I'm definetly going to look farther.

      Delete
    2. I'm new to jsRender & jsView, so please forgive any ignorance on my part.

      Would you consider finding a more intuitive shorthand for html encoding? ">" is pretty overloaded IMHO. "e" or something expandable to encoding would make sense.

      You're creating a well crafted work -- one I can't help admiring in its simplicity. Devs won't get to the cool bits though if something like no default encoding or at least an intuitive, simple syntax becomes a distraction.

      From your perspective this is probably ridiculous to focus on when there are other pressing technical challenges. However, developers want to use jsRender & jsView even if it is in alpha/beta, but selling it to managers and team members is tough when admitting there's no default HTML encoding.

      To me, most output to templates will be data fields requiring encoding. Default encoding through {{:myField}} or something as elegant makes more sense. We can implement our own solutions but everyone acting on their own is not a very DRY approach. Will there be a way to plug-in a default encoder and still use the aforementioned syntax?

      Delete
    3. @Cody: Thanks for those thoughts. Encoding is complex, and there is no magic default that works correctly. JsRender by design does not know about the DOM and does not know what the context is of a given tag. The correct encoding for {{...}} within element content is generally {{>...}}, but within attributes it might be JavaScript encoding, URL encoding, etc. depending on the attribute. So JsRender tries to be clear that {{someEncoder: }}: is what you use for a specific encoding. (You can very easily write an attribute encoder, URL encoder, etc. and put {{url:...}} for example.)

      But If you put {{:...}} it is intended to be clear from the syntax that you are not encoding at all. (With data linking you can do two way binding, and write data-link="{:fieldName:}" with no conversion, or data-link="{convert:fieldName:convertBack}" for conversion in both directions, so again the syntax is hopefully suggestive... See this example.)

      I think it is reasonably intuitive that {{>...}} is what you use to encode within element context. And it is as easy to write as {{:...}}. There is also a long form of {{>...}}, which is {{html...}}, so you can use that if you prefer. I think that {{e...}} would be unclear not only about referring to encoding, but also as to what kind of encoding it is using, since, as I say, there are several encoding functions that might be used, for different contexts...

      Delete
    4. Thank you for the reply. I'm converting a project that's pure javascript to use coffeescript+jsrender instead. After that experience, I'm sure I'll have a much better feel for what you're describing.

      Delete
  11. I tried using jsviews for a few local projects last year, it was great enough in alpha version.

    While I come to this post, I would really like to read more on the discussions over the changes since I came over the original idea: "scriptless template syntax". Coz it really enabled very much logical scripts with the syntax, by the changes mentioned in this post.

    Don't get me wrong, I think this is a very great library. Just wanna understand more of the idea behind it's development process.

    Thanks for such a great work Boris. :)

    ReplyDelete
    Replies
    1. That’s a great question, which would justify a complete blog entry for an answer. But I’ll try to give a short(ish) answer here. The goal of JsRender is it allow you to have a lot of power and flexibility over the content you render against data, without forcing you to wrap your data, or to modify the shape of the data itself, in order to achieve the templated views you want. Now often in your rendered views you will want to do things like comparing values across different data properties (e.g if you want to output some content based on {{if shippingAddress !== billingAddress}}) or driving rendered output based on index position, or parent data, etc. If a codeless or logicless templating language forces you to add new data properties like a Boolean shippingAddressNotEqualToBillingAddress in order to have that conditional section, then clean separation is NOT being achieved, since the view/presentation requirements are impacting the model. OTOH if you have real ‘business logic’ to ‘evaluate’ then it is not a good idea to put complex ‘business expressions’ directly in the template. Also it is not a good idea to have the template access global variables or methods, since you may use the same template in a new context, and you don’t know what the side-effects are of those dependencies. Further, there may be security concerns if the template author can call script methods in the page that were not intended to be exposed to the template. JsRender has a rich support for evaluating Javascript expressions – but will not allow access to globals, or external data or objects or methods, and will not allow expressions in the template that would mutate data values directly. At the same time, JsRender makes it very easy to pass in parameters and helper functions in addition to the data, or to call methods that are provided on the data (model) itself. JsRender also now allows a template to be declared along with helper functions that it will call, without those helpers being accessible from any other template.

      So the goal is to have a lot of power and flexibility, while allowing strict control over access to helpers. And to encourage good separation by requiring any rich logic involving business rules to be ‘designed into’ the model, or the custom helper functions, tags, etc. that are registered. These can easily be associated with MVVM or MVP patterns etc. in order to maintain a chosen approach to separation of concerns etc.

      jQuery templates have been extremely popular, in part I believe because of the power and flexibility of the integrated JavaScript expression support. However, jQuery templates did not ‘sandbox’ the expression evaluation, and so it was easy to make the separation ‘fuzzy’. I believe that JsRender does much better in maintaining a similar level of expressive power while ensuring that all expression evaluation is effectively sandboxed in an isolated context, and while providing patterns which encourage clean separation. The ‘codeless’ approach started out with the principle of not doing expression evaluation with global scope access within the template. At first it seemed that this requirement would force the expressive power of the template to be much less than is the case with jQuery templates, but remarkably, it has proven possible to achieve considerable expressive power without contradicting that initial principle.

      Delete
  12. At first my compliments on JsRender and JsViews. I'm currently running a test-case with the pre beta release and i can't wait to use it in a live application. In your article you're talking about linking helpers and converters to a specific template (Template resources and settings). Could you tell me how to bind helpers to a specific template in stead of binding it to all templates?

    ReplyDelete
    Replies
    1. I found an option to create templates with template-specific helpers. The point is that onAfterCreate and afterChange functions won't appear in de template.ctx. Is it possible to create onAfterCreate and afterChange functions and bind them to ONE template?

      Delete
  13. Big thanks for this cool library!

    I have one, probably simple, question: is there any way I can detect when a template has finished rendering? A callback or something, so I can run an additional function?

    Thanks in advance :-)
    Martin

    ReplyDelete
    Replies
    1. There are several options, but you need to use linked data to call the callback onAfterCreate.

      //for all linked data
      $.views.helpers({
      onAfterCreate: function ( ev ) {
      console.log('READY');
      }
      });

      //for single link
      $.link.TmplName( "#container", data, {onAfterCreate: function (ev) {console.log('READY')}} )

      Delete
    2. Thank you for your reply, but I'm afraid it didn't really work.

      I'm using jsrender only (as well as jquery), and have it set up like this:
      script id="recipes" type="text/x-jsrender"
      li class='{{:tags}}'
      ... etc. etc.
      /li
      /script

      (has to omit the brackets for the comment system here... :-)

      $p.templates( "recipes", {
      markup: "#recipes",
      allowCode: true
      });

      And when I get the data via ajax:
      $p("#result").html( $p.render.recipes( data.results ));

      Any suggestions?

      Thank you in advance :-)
      Martin

      Delete
    3. you can put some js-code inside your templates. For example:
      <li class='{{:tags}}'>{{:recipe}}</li>
      {{*
      //you js-code here
      console.log('I'm here');
      }}
      The code inside the template will be called when rendering your template OR you could run the code after calling: $p("#result").html( $p.render.recipes( data.results )); ofcourse.

      however when this doesn't work it's possible to implement JsView. This won't take much time, just include the files from the JsView download in stead of JsRender download. After that you can define a function like:

      $.views.helpers({
      onAfterCreate : function (ev) {
      },
      afterChange : function (ev) {
      },
      beforeChange : function (ev) {
      }
      })

      within the ev argument you can get the view, data, etc.

      Delete
    4. @Martin: For simple scenarios using JsRender, as above, where you are calling $.render.myTmpl(data); then all that call is doing is producing the HTML string by applying the template to the data. It is synchronous, and so you don't need an event to know when it has rendered. If you are inserting it into the DOM by passing it to $.html, as in $.html($.render.myTmpl(data)); then again, it is synchronous, and your code is doing the insertion. So you already know in your code when it is rendered as a string, and when it is inserted into the DOM. You can add 'follow on' code immediately after your line of code above.

      The onAfterChange feature is relevant to more advanced scenarios with JsViews, where data linking is triggering the rendering, but not your scenario, per the code you showed above.

      And using the allowCode feature to insert your own code to notify yourself is possible but unnecessary, given your synchronous rendering scenario. Generally I would recommend avoiding setting allowCode=true, since it encourages mixing of code and presentation, and can be very difficult to maintain. Only use it if you are sure you know what you are doing, and are sure that you don't have an alternative approach available using the other built-in features.

      Delete
  14. converting before setting

    I can't find a way to convert a value when changing the data-object.

    Previously it was possible to do something like this: data-to="[data-object]:converter(this.path, $value)". The code then first converts a value before putting it in the data object. How can i implement this option in the new version?

    ReplyDelete
    Replies
    1. This was a bug that has now been fixed. There is also a new demo showing an example of using two-way data binding with convert and convertBack functions.

      Delete
  15. The observable syntax gave me a bit of headache when I try to monitor array changes. Turns out I need to wrap the array inside another array for this to work. For example

    var a = [];

    $([a]).bind('arrayChange', function(e) {
    console.log('this will work');
    });

    $.observable(a).insert(0, 1);

    Note the $([a]) instead of $(a) when a is an object. This throws me off until I try to step through the code.

    Also, it would be tremendously useful if the observable allows cancelling the events, for example, the user edits away on the current edit view with bad data, but before the data is being set on the modal, we have a chance to validate and prevents the data being updated.

    Another use case would be the users finishes editing on the view but forget to save. We would like to give them the choice of not preserving the change at all. Which is impossible if observable changes are not cancelable.

    ReplyDelete
    Replies
    1. It is standard technique in jQuery that to bind to an array (or to call any plugin method foo() on an array) you must wrap it in an array. It will not work if you just write $(a).foo() - since doing so will always run the foo() method on each of the members of the array, not on the array itself. Whereas $([a]).foo() will apply the method to the array 'a' itself. So this is not specific to observable, and is not 'observable' syntax. It is regular jQuery event binding syntax.

      Your idea of cancelling implies an event bubbling order in which one listener can cancel the change before it gets handled by another listener, or before the data is changed. But in fact there is no control in jQuery on the order of listeners. (Well actually the last to bind gets called last, but it is not a good idea to build a feature which depends on that ordering.)

      However there will be changes to observable coming before it reaches beta, which will make it possible to override $.observable, and get your own beforeChange/afterChange events inserted...

      Delete
    2. Thanks for the reply, I've since worked pass that and stumble upon other problems, the main trouble I'm facing right now is that programmatic variable such as #index, #data, #view does not receive the propertyChange event when property changes. For example, I'd like to only display a picture on the last added item to the array, we can achieve this by following the helper function example. However, when one tries to modify the array through observable.insert, there are multiple items indicated as last as updating the array only updates the view currently affected, not all the array views that may use the #index.

      Since I've just started using the library, I'm not sure if this a valid use case, can you point me to the right direction? Perhaps it is better suited to use an externally tracked variable that also gets set when index of the array has changed?

      Delete
  16. Hello, Is there any way to pass a context to the helpers/tags/converters? Because, I have a lot of View and sometimes that helper methods are replacing another one which have the same name. Using different names for each helper is a possible another way, but passing a context would be better.

    ReplyDelete
    Replies
    1. Yes, on converters, the 'this' pointer is the current view, from which you can get the data, the view index, the rendered HTML nodes, and much more. I have just checked in an update which provides exactly the same feature on custom helper functions too. For tag functions it is similar,
      but 'this' is a 'tagObject' from which you can get this.view for the view, this.props for the named tag properties, and you can also call this.renderContent( data ) to get the rendered output of the associated template (the content template for a block tag...).

      Delete
    2. Thank you, that is great. :)

      Delete
  17. This all looks good. Will JSViews include automatic tracking of calculated values, like KnockoutJS does?

    ReplyDelete
    Replies
    1. Well JsViews already does that: There is an example here which is doing:
      <span data-link="~homeTown(firstName, lastName, address.city, true)" />
      - where the homeTown helper returns a computed string based on all those parameters, and the data-link listens to changes on any or all of them.

      You could also write things like: <span data-link="price*number" /> - which will render the calculated result without going through a separate helper, and will update if any of the dependent variables changes.

      Delete
  18. Does {{if }} inside tag works? ex:
    <div class="utente-detail{{if !opened}} collapsed{{/if}}" id="code-{{:code}}">
    I tried
    {{if !opened}}
    &ltdiv class="utente-detail collapsed" id="code-{{:code}}">
    {{else}}
    &ltdiv class="utente-detail" id="code-{{:code}}">
    {{/if}}

    console give error at line 522 of jquery.view.js (node = node.nextSibling;)

    ReplyDelete
    Replies
    1. @Daniele: If you are using JsViews as well as JsRender, then by default JsViews adds HTML comment annotations which allow it to data link. If you want you can switch off those annotations by setting link=false on any tag. Generally you will always want to do that when you are adding tags within HTML tag markup. So in your example above you can write:

      <div class="utente-detail{{if !opened link=false}} collapsed{{/if}}" id="code-{{:code}}">

      And if you do an {{if}} {{else}} {{/if}} then you would set link=false on the {{else}} tag too:

      <div class="utente-detail{{if !opened link=false}} collapsed{{else link=false}} expanded{{/if}}" id="code-{{:code}}">

      Delete
  19. One of the most interesting changes here to me is the ability to {{for}} through the properties of an object. Is it possible to do this in such a way that I can create a rendered template that does nothing but list the field names and their current values?

    I was thinking something like the following, but was unsure how I could set the alias variable:

    <table>
    <tbody>
    {{for ~app.limits ~field}}
    <tr><td class="name">{{:~field}}</td><td class="value"><input data-link="{{:~field}}" /></td></tr>
    {{/for}}
    <tbody>
    </table>

    ReplyDelete
    Replies
    1. @Dillius: Yes this can be done in a couple of different ways using a custom helper function or tag. I have added a sample to show how to do that. The code is here. See also the issue here.

      Delete
  20. Hello, I have an another question. :) I'm using jsViews for some feed style views. I don't use delta data but I return all data for every update, because returning delta is a bit complicated for my scenario. When users want to update any item in feed, I render them into edit mode, but as soon as any update comes, everything is turning into the default view. How can I prevent an item in edit mode not to update when any observable change made. Is there any feature that I can use for this scenario or do you have any suggestions?

    ReplyDelete
    Replies
    1. You can use $.observable to bind other data than the data you are sending to the server (e.g. cloned data) - and then map from one to the other through your own code. But when JsViews gets closer to beta, or else between beta and v1, there will be more complete features and samples around observability, and there will be the possibility of adding pre and post change handlers where you could allow cancelling etc.

      Delete
    2. Thank you, I'm looking forward about it.

      Delete
  21. Hi Boris,
    thanks for this great library!
    I'm a little confused on using jsview to render a select with data bindings.
    what's the best way to render for example a country select combo with dataModel like this?
    In my scenario the rendered select combo it's always empty also if I insert static <option> in select tag.

    var dataModel = {
    currentCountry : {"code":"IT","description":"italy"},
    countryOptions : [{"code":"IT","description":"italy"},{"code":"FR","description":"france"}]
    }

    <select name="testCountry" data-link="currentCountry.code">
    <aoption value="IT"&gt,italy</aoption>
    <aoption value="FR"&gt,france</aoption>
    </select>

    Thanks

    ReplyDelete
    Replies
    1. Declarative two-way binding to select elements is currently hindered by some issues in IE8 and earlier which prevent correct inclusion of comment-based annotations (currently used by JsViews for binding to arrays) in <ul> or &ltselect> tags. Full support for this is an important piece in upcoming changes I am working on, moving towards beta. For now you have to use code for binding to select - it won't work just declaratively. Improve support for binding to check boxes, radio buttons and textareas is also planned with beta.

      Delete
    2. Update: Data linking to select elements and other form elements is now fully implemented. Demo here

      Delete
  22. Checking out the latest and am nonplussed to find that html encoding is not the _default_. I foresee it being very easy to let XSS attacks slip through. Asp.net MVC Razor and webforms 4.0 at least provided a syntax that typically encodes by default and provides an alternative for explicitly allowing code through that should skip encoding -- that's probably less of a common case and requiring explicit would seem to be the fail-safe (secure by default) option.

    And the syntax is better at least for html encoding, but the "secure" option is much more verbose, which would be a deterrent to doing the right thing {{html vs. {{>

    Any chance that we could run jsrender in a mode that would enable encoding by default and require a different template syntax to emit without encoding?

    ReplyDelete
    Replies
    1. @core24: In fact there is no default. There are two tags, one which encodes and the other that does not, and they are equally succint: {{>expression}} will encode and {{:expression}} will not. There is no discouragement to the secure form. ({{>expression}} is shorthand for {{html expression}} - which is also provided since it is more discoverable if you are looking for the html-encoding form).

      The recommendation is to use {{>expression}} when expression is a data field or if expression may be target for an attack. But sometimes is makes no sense to encode. For example {{>#index}}, if #index is known to be an integer. There is a perf cost to HTML encoding, so it is the responsibility of the app developer to choose the appropriate tag.

      Most template engines simply give the choice between the encoded and unencoded style, just like JsRender does.

      Delete
  23. Boris, I'd like to ask you abount posibility of using jsView with my own objects & data-binding engine.

    I set up a notion for my objects to have properties like this:
    MyClass.prototype = {
    prop1: function (v) {
    if (arguments.length > 0) {
    if (this[field] !== v) {
    this[field] = v;
    this.trigger("change:" + name, this, this[field]);
    }
    } else {
    return this[field];
    }
    }
    }

    trigger and bind - are protopyte's methods (i simplified code) for raising and subscribing event (like jQeury does but for any object - think "Backbone.Events" if you will)

    The idea is:
    var o = new MyClass();
    var v = o.prop(); // get the value
    o.prop("1"); // set a new value and fire "change" event ("PropertyChanged")

    I can see jsView has its own "Observable" notion implementation and all demos use plain objects. I understand that jsView creates some wrappers behind the scene.
    I wonder can I manage this process and can I use my "smart" objects with jsView?
    Tnx in advance.

    ReplyDelete
    Replies
    1. I hope to work on the scenario of using MVVM wrappers, MVP presenter classes etc. with JsViews, some of which should make it into JsViews beta, and some subsequently. Right now it may be too soon to do that easily - you'll need to experiment with current APIs - or you may prefer to wait for more stable APIs and more complete features with or beyond beta.

      Delete
  24. I'm using
    $.templates("destinatariTmpl", {
    markup: '#destinatariTmpl'
    });
    $.templates("testTmpl", {
    markup: '#testTmpl'
    });
    $.link.destinatariTmpl('#box-destinatari',importData);
    well, unlink? can I swap?

    ReplyDelete
    Replies
    1. There is a sample showing linking and then dynamically swapping templates here, code here. You can include data-linked fields in those templates too, using data-link="field" instead of {{:field}}.

      Delete
    2. Hi Boris, I would to swap template and data, I am using it to fill form data, swapping for me is to fill different forms with distinct data. Is it possible? I suppose I can manage it by using two div and undisplay and disabling input of one and other ..

      Delete
    3. @Daniele: JsViews and JsRender are very flexible in allowing you to dynamically change both data and templates and trigger updated rendering in different ways. You can get the view object, change data and or template and call its render method, following the approach in the accordion. But a better approach is to use declarative data binding and observable changes to data. Even the template can be changed via this approach. But for details, if you don't see how to do it from existing examples, it may be better to be patient as JsViews moves forwards towards beta. Once APIs are stabilized I hope to add many more examples, as well as documentation etc.

      Delete
  25. To recent questions waiting on a reply, a heads up that I do plan to answer your questions, but it may be a few more days before I am able to do so! Thanks for your patience!

    ReplyDelete
    Replies
    1. It'd be nice to have some discussion place on jsRender/jsView, like a Google Group.

      p.s. have you seen this: jsperf.com/dom-vs-innerhtml-based-templating/? Kendo've beaten everybody.

      Delete
    2. Yes I plan to create a group or forum once we reach a stable beta API.

      On the perf page, yes, that page changes all the time and often has misleading results because folks misuse the APIs of other templating engines and don't compare apples to apples. String concatenation is string concatenation, and JsRender uses exactly equivalent concatenation to Kendo and doT (without using 'with'). I haven't looked to see what that page is doing to result in apparent differences, yet. But I can say that if you have no features, e.g. do not support data methods, helper functions, default rendering of undefined fields (jagged data) etc. then you will have slightly less code to run during rendering, so may gain a few percent. But you pay for what you get...

      Also it makes no sense at all to choose a template engine that saves a few milliseconds during rendering if the time to render is already a very very small fraction of time taken to compile the template, not to mention fetch the data etc. The user will have strictly zero awareness of the difference in rendering performance. However they may well feel the difference in compilation performance. Example: look at this perf test. If you run that in Chrome you will see that Handlebars renders in say .7 milliseconds, and JsRender in 1.1 milliseconds. So JsRender is maybe 40% slower. But guess what. a) In other browsers JsRender is faster. b) Look at the compile time. Handlebars takes about 850 milliseconds to compile that template. JsRender takes about 290 milliseconds. Those figures are usually far more important than comparing a difference of less than a millisecond in rendering time. Again, you need to consider if you are compiling once and rendering once, or compiling once and rendering 2000 times. And when you render, what other code is running that will impact performance... At the end of the day gaining a millisecond in rendering performance may be important not for the user, but for 'marketing' purposes for the template engine :).

      Delete
    3. @Sergei: BTW on the perf page as jsperf.com, someone had added JsRender, but with an error in the template, which I corrected. I also switched from using myTemplate.render() to myTemplate.fn() which is the method to call for optimized performance on simple templates (when you don't need the view hierarchy - e.g. you are not call #parent within the template). Also I think the Kendo UI version using external templates was creating spurious results, maybe caching the external template rendered result. It has since been removed. The updated test page is: http://jsperf.com/dom-vs-innerhtml-based-templating/395. Currently JsRender is actually the fastest of the engines tested, on all browsers.

      Delete
    4. Wow, interesting. It's quite another story. thnx

      As for comparing milliseconds of rendering simple templates - I agree, it's not as important as just having decent perf and richness of features.

      Delete
    5. @Sergei: I actually made a mistake when I used the .fn API on that jsperf page. The template includes a {{for}} tag, and .fn cannot be used in that case. I fixed the error here: jsperf.com/dom-vs-innerhtml-based-templating/404. So this should now give accurate results. (However someone then removed JsRender from the page again, so it is missing from later versions of that test page).

      Delete
  26. Hi Boris, I'm hoping you can spare some time to help me.

    I'm having IE problems with JsViews. My template is stored as an HTML that I load using jQuery.ajax() and stored as string data in some variable.

    When it's time to render, I create a DIV, set the innerHTML to the raw unprocessed template data, then use jQuery.link:

    // We render the template data onto our DIV
    var tmpl = this.template;
    this.tmplDiv.innerHTML = this.template;

    // Now we link the div with our weather data
    jQuery.link(this.tmplDiv, this.weatherData);

    My 'weatherData' has today.high and today.low values.

    Here's my template:
    <div class="sectionHeader">Today's Weather</div>
    <div class="todayTemp"><span data-link="today.high"/></div>
    <div class="todayTemp"><span data-link="today.low"/></div>

    If FF, this works fine. In IE, nothing renders past the 'today.high' DIV.
    If I remove the <span data-link> elements, everything renders.

    I'm using IE 7 on Windows XP.

    ReplyDelete
    Replies
    1. The first thing would be to write the spans as <span data-link="today.high"></span>, not as self-closing tags...

      Delete
    2. Thanks Boris, that did the trick!

      Delete
  27. I have been a big follower of JSRender from the beginning, and this latest drop seems very powerful. Hopefully, the API is stable now, because i would like to use it in my applications (at least in the demos).

    Anyway, great work Boris, your dedication and expertise really sold me on this. I need something that can run on the server and in a browser, and I think that your JSRender really meets both these requirements.

    ReplyDelete
    Replies
    1. @Jeremy: Thanks for you appreciation :). JsRender API is from my point of view really close to Beta and should not change significantly. The only reason I am not declaring current bits to be an official beta is because I am planning some very significant changes to JsViews APIs for beta (as significant as recent breaking changes to JsRender), and I want to reserve the possibility of adjusting JsRender APIs if necessary to better integrate with those upcoming JsViews changes.

      So if you are prepared to make minor future changes, that should be compatible with usage of current JsRender in applications. I think the current JsRender is already beta as far as code quality is concerned.

      Delete
    2. Very cool, I am definitely ok to make minor changes. I really think you came up with the right compromise between "logicless" and a functional template engine. You are right, Mustache, in my mind, Mustache is just doing the shifting the complexing too much out of the templates which make the overall app code complexity worse. The latest JSRender looks very good, building my demo with it.

      One question, it is possible to have a simple {{:myValue!"no myValue"}} Basically, the ! means that if myValue is false (null, undefined, or empty) it will take the string or value after. I am using this from Freemarker on the sever, and it is very useful in some cases (remove the need to do a big if/else, which is nice in area like tag attributes). Anyway, this is a small wish, and you might have already a way to do this as concise. Would be even cooler if we could chain them {{:myValue!mySecondValue!"you have no values"}} (no pun intended ;)

      Delete
    3. @Jeremy: Yes that is already available, including the chaining. Did you look at the 'default-values-scenario' sample?
      You can simply write: {{:myValue||mySecondValue||'you have no values'}}.

      Delete
  28. How I can to use helper functions in data-link?
    For example: data-link="{:~numToStr(Value, 2) Value:strToNum}". I want replace converter "strToNum" to heler function "~strToNum(2)".

    ReplyDelete
    Replies
    1. @sinvit: Yes, just take a look at the examples, such as here, or here and it should be clear.

      Delete
    2. Sorry? but I don't understand. I try various, but get errors.
      For example {:~numToStr(Value, 2) Value:~strToNum(Value)}, don't work.

      Delete
    3. @sinvit: Did you add your function as a helper? If you need more help, create a jsfiddle sample, and send me an email directly, rather than a comment here. I'll try to reply...

      Delete
  29. Hi, Boris!
    What should I do if I need to render a template for empty string? I have a template to render an array item, usually it renders some string, however sometimes it may get an empty string. In that case I still want to render the template for that string - not skipping it.

    ReplyDelete
    Replies
    1. @antrax: Yes that should work exactly as you ask. See this unit test, and also this one.

      Delete
  30. Hi, Boris!

    I'm looking at potentially using jsviews and jsrender as part of a storefront, mainly so that I can use the same object in different views - ie toggling a product between a grid view, and a light boxed full view, sorting products, filtering and other operations. Now, I plan on using history.js to maintain url states and modernizer/yepnope with polyfills to asynchronously load everything and ensure functionality. This however poses several questions.

    1) Will using JSRender to render primary content prevent search engine detection
    2) Will JSRender cause a flash of unstyled content, specifically on platforms with slower connections and processing capabilities.
    3) Is there any particular advantage to using less.js over the less php to compile less into css while using JSRender
    4) Are there any polyfills necessary to run JSView/JSRender on older browsers
    5) Does template load order matter
    6) Are there any pre-written template prefixes for modernizer
    7) Is there a preferred technique for loading the data to be linked/rendered? Inline JSON Localization?

    ReplyDelete
    Replies
    1. @Thomas: Many of your questions are not specific to JsRender or JsViews. JsRender is just pure string-based template rendering, so has no DOM or browser dependencies, and its use is independent of how you get your data, or load your templates.

      For more advanced use of JsViews, I plan to provide more documentation and tutorial help once we release the beta version, so you may want to wait until we get closer to that version.

      Otherwise, if you simply start by exploring how it works from the samples, then test it in your prototype code, a lot of your questions will probably become clearer. See the sample links above, and articles and blogs such as this excellent MSDN article from John Papa.

      Delete
  31. Hi Boris,

    Is there a way to create local variables in JSRender, something like "assign" in Freemarker (http://freemarker.sourceforge.net/docs/ref_directive_assign.html)? I am writing a JSRender template where one of the HTML element I am building has some conditional content and I want to avoid duplicate logic for populating the element. e.g.
    {{if data.condition1}}
    set some value to local variable A
    {{else}}
    set some diff. value to local variable A
    {{/if}}
    {{if data.someOtherCondition}}
    render something using local variable A
    {{else}}
    render something else using local variable A
    {{/if}}
    Without local variable A, my first "if" logic will be repeated in the second one.

    Please let me know if there is a way to do so. Hope I am clear in my question.

    Thanks!

    ReplyDelete
    Replies
    1. @sandeepsp: Yes I understand your idea, and there are a few ways it can be done. I have created a sample here, which shows one way, using a custom tag and a custom helper. You can also easily achieve it using the allowCode feature. But both approaches take you away from the more 'logicless' and declarative pattern, and introduce a dependency on the processing model (sequence) of the template rendering. So I think it makes sense to keep this as a feature available through JsRender extensibility (custom tags) rather than providing a build in {{assign}} tag.

      Delete
  32. Hi Boris, thanks for your efforts on jsRender!

    Just a sidenote: I'm playing with jsrender to build an application and I was using the {{if}}{{else}} construct. I wrongly wrote some lines of code in the following way:
    {{if a}}
    [...]
    {{else if b}}
    [...]
    {{/if}}
    and this works on desktop browsers as well as on new brand mobile phones (like iPhone 4 and samsung galaxy 2s). On more dated phones (like and HTC desire HD) it breaks the template. Since it was working on my desktop and not on my phone I went through troubleshooting and debugging the code and isolated the cause which was this wrong construct.
    Just wanted to highlight the awkward behaviour that makes it work on desktop systems and not on mobile!

    Now I've switched it to the correct syntax and everything is ok!

    ReplyDelete
  33. please give document link with simple example

    ReplyDelete
    Replies
    1. @Jaw: There are many links to samples provided in the text of the blog above. The simplest ones are in this series. Also, take a look at this recent (and very good) MSDN article from John Papa, which is the first in a planned series on JsRender and JsViews.

      Delete
  34. This may seem an odd question considering that this is script based.

    Have you ever considered adding the basic recommendations for the Section 508 conformance in regards to web page access. I know that its recommended that a web page work without javascript, but I have to assume at some point they will create a new reader that can understand modern scripting.

    ReplyDelete
    Replies
    1. @Larry Smith: It is early days... I think that once JsRender and JsViews release in V1, there will be opportunities to combine server rendering and client-side activation of data linking which will be fully compatible with unobtrusive JavaScript patterns, and accessibility concerns.

      Delete
  35. Hi Boris,

    Accessing parent data in nested tags is currently quite tedious. Content of tags need to reference data of parent tag using this #parent -notation, e.g.

    {{for}} {{:#index}} {{if}} {{:#parent.index}} {{/if}} {{/for}}

    Renaming with ~localVariable=parentVariable helps in some cases a little, but...

    Usually in templating languages and programming in general variables/data of lexical parent is visible in nested context.

    Could you expose the data of parent tags directly to lexical child tags? Then only overlapping property names would need to use #parent or ~var=var -syntax?

    ReplyDelete
    Replies
    1. @Samppa Saarela: The javascript 'with block' concept can easily be leveraged to provide those semantics, but leads to a perf cost, and introduces a more loosely coupled model which may be harder to maintain (with the possible collision/hiding of properties from the outer context).

      But I have been considering adding a feature where you would use {{:~data.foo}} to get any 'inherited' foo data property, while still providing {{:foo}} and {{:#parent.data.foo}} for direct access. I have to determine whether this can be achieved without negatively impacting performance, and whether it will be compatible with data-linking to a ~data.foo path, so we'll see what emerges!...

      Delete
    2. Douglas Crockford's "use strict"; explicitly doesn't allow the "with" statement

      Delete
  36. Hello Boris,

    Lets say that I have following data (simplified):
    var data =
    {
    Array1: [ {"Key":1},{"Key":2}],
    Array2: [ {"Name":10}, {"Name":20}]
    };

    With the following template:
    script id="tmpl1" type="text/x-jsrender "
    Key: {{:Key}}
    Names: ?? Names from Array2 ??
    /script

    Execute template with data.Array1
    var html = $("#tmpl1").render(data.Array1);

    Is it possible from the template to access data.Array2? (In this particular case I dont want to pass in just data and make a {{for}} loop on Array1 in the template).

    ReplyDelete
    Replies
    1. @Eric: If you only pass the first array to the render method, then the template cannot access the second array.

      Here are a couple of ways you can achieve what you want:

      a) Pass the data object to the render method, with a {{for}} loop for the first array. Access the second array using #parent.parent.data.Array2, or by passing a '~array2' template parameter to the nested context:

      <script id="tmpl1" type="text/x-jsrender">
      {{for Array1 ~array2=Array2}}
          Key: {{:Key}}
          Names:
          {{for ~array2}}
              {{:Name}}
          {{/for}}
      {{/for}}
      </script>

      var html = $("#tmpl1").render( data );

      b) Pass the second array to the render method as a template parameter:

      <script id="tmpl1" type="text/x-jsrender">
      Key: {{:Key}}
      Names:
      {{for ~array2}}
          {{:Name}}
      {{/for}}
      </script>

      var html = $("#tmpl1").render( data.Array1, { array2:data.Array2 });

      Delete
  37. Hi Boris,

    I'm really enjoying the bidirectional data binding support with nested templates (also the overall performance compared to tmpl).

    Looking forward to the select-option support, which will complete my requirements.

    thanks

    ReplyDelete
    Replies
    1. Yes, I am working at the moment on the changes needed in data binding to provide full support for binding to select elements. The difficulty is caused by IE eliminating any comment tags that are inserted as content under select elements. JsViews uses comment tags as binding annotations. So it is a major change, but is looking very promising.

      Delete
    2. Boris - don't mobile devices strip comments out too when they minify?

      Delete
    3. Update: Data linking to select elements and other form elements is now fully implemented. Demo here.

      @John Papa: The comment annotations used by JsRender are happening only in the browser, inserted as innerHTML (though now JsViews no longer does that when inserting option, optgroup, li, tr, or td tags). They are not being loaded on HTML from the server, so minification should not be happening here...

      Delete
  38. Hi Mr. Boris,

    This is a great article. I am currently trying to use JSRender and it works fine but when I tried my work in IE7 the render does not seem to work. Do you have any tips on what might be causing this? Any answer would be much appreciated.

    Thank you.

    ReplyDelete
    Replies
    1. Here is my template code:
      {{if CategoryTitle != null}}
      {{:CategoryTitle}}
      {{/if}}

      Inside my ajax call, I created a loop and here is how I load the item on my template:
      $.each(cls.d, function(index, item) {
      $('#tblSearch').append($.render.categoryTemplate(item));
      });

      This code is working fine on other browsers, even IE8 and 9 but not on IE7.

      Delete
    2. @Mar Anthony: JsRender has no DOM dependency so should work the same in all browsers. Check whether $.render.categoryTemplate(item) returns the expected string value. If so, then the problem is unrelated to JsRender...

      Delete
  39. Hi Boris. I am rendering a number of pages (sections) in jquery mobile format with jsrender. The pages render ok and I can use jqm's .page() function to apply jqm styles. I am however stuck when it comes to jqm events handlers. I need to open some pages in a dialog and as of yet I cannot get a jqm .changePage() event to fire to open (change to) a rendered section opening it as a dialog, or even as an ordinary page. Do you have an example anywhere that may be of use or any suggestion on who I should apply jqm events to rendered pages.

    Many thanks,
    Stephen

    ReplyDelete
    Replies
    1. @Stephen: jQuery mobile does a lot of re-rendering, re-wrapping of dom nodes, etc. so it may not be so easy out of the box to integrate it with JsViews, which is intended to work with a data-driven, template-rendered, DOM. I hope to work on making it easy to use JsViews with jQuery mobile (I started looking at it, and it looks like it will be possible) – but specifics will have to wait until after JsViews reaches beta, at the earliest. So until then I can't help directly or offer examples. By all means send me email directly if you make some headway, (to share your results or ask help on specific problems).

      Delete
  40. Hi,

    Our team is starting to migrate to JsRender and JsViews from jQuery Templates. On jQuery Templates, we use the {{wrap}} tag to render tabbed html layout. Does JsRender or JsViews have the similar feature? Thanks.

    ReplyDelete
    Replies
    1. @joshcu: No, there is no built-in {{wrap}} tag, but writing custom tags is a whole lot easier than with jQuery Templates, so it should be fairly straightforward to write your own {{wrap ...}}...{{/wrap}}, or {{tabs ...}}...{{/tabs}} tag.

      The function you provide in your custom tag declaration returns the rendered result of that tag, and has access to the wrapped content of the tag. So you can define how it interprets the wrapped content, as different tab content sections, etc. Take a look at the samples declaring custom tags, such as this one, and the way JsRender itself implements {{for}} and {{if}}.

      Delete
    2. Thanks for the reply, Boris. Though it's still a puzzle to me on how to produce the tabbed content. Honestly, I've just followed the examples of using {{wrap}} from jQuery Templates, like using the stateIndex to display which "tab" would show its content. So I don't exactly know how to start with that kind of functionality using JsRender/JsViews. Can I seek your help for this migration we need?

      Thanks in advance!

      Delete
    3. Regarding {{wrap}} for jQuery template, we used it because we need the nested tabbed layout as what is shown as a demo for this.

      Delete
    4. @joshcu: For now I have to put the priority on completing some important feature work for an upcoming commit, which is a key step towards reaching beta on JsViews, and includes some major improvements around creating custom tags. Once that commit is in, I will see whether it would make sense to provide a demo of a tabs control, (implemented as a custom tag {{tabs ...}}) as a sample showing how to use those new features.

      Delete
    5. @joshcu: There is now a sample demo of a tabs control here on GitHub.

      Delete
  41. Hi, I would like to do this :
    1) My user chooses how to show the data
    2) The App downloads the template and store locally on device (I am using JQueryMobil)
    3) the data is shown by using the template downloaded

    Is it possible to apply a dynamic template ? Downloading and store them for later use... ?

    TIA

    ReplyDelete
  42. Hi Boris - when will programmatic data linking be available?

    I started with the MS AJAX library, which was scrapped for the original version of this project, then it got scrapped for the jQuery UI team's rewrite that never materialized and now 2 years after the origin of the jquery project and a full year after our previous discussion in the comments about the direction of this project it's still incomplete and has even stepped backwards in that it doesn't even have one of the most important features anymore.

    ReplyDelete
    Replies
    1. @Chris: First, obviously I share the pain of that history, and I am at least doing my part to try to get to a better place! As to stepping backwards, I think far more that has been added than has been taken away, so I hope the outlook is more positive than that! You can still use previous versions, or jQuery DataLink if they fit your scenarios better. But as to moving forward, I am trying to reduce, where possible, upcoming breaking changes. The addLinks feature was not compatible with the new declarative design, and was also I think, less critical because there is a work around: you can use the existing events to do programmatic data linking:

      $(person).on("propertyChange", function(ev, evArgs){
        if (evArgs.path === "name") {
          $("#nameInput").val(evArgs.value);
        }
      });

      $("#nameInput").on("change", function(){
        $.observable(person).setProperty("name", this.value);
      });

      As to when it will come back in a more compact form: probably not until after the declarative design has been finalized. By all means add an issue to the GitHub repo, with any specific feature request/design/scenario that is important to you.

      Delete
  43. Thanks Borris. The navigation model in JQM does make everything a little more complex.
    Best regards,
    Stephen

    ReplyDelete
  44. Hi Boris, I'm trying to have a drop down data-linked to a collection, similar to following:

    {{for mainCollection}}
    <select data-link="{convert:subCollection:convertBack}">
    <option>0</option>
    <option>1</option>
    <option>2</option>
    <option>3</option>
    </select>
    <span data-link="subCollection.length"></span>
    {{/for}}

    My converters look like the following:

    $.views.converters({
    convert: function(collection) {
    return collection.length;
    },
    convertBack: function(length) {
    ??? = new Array(length);
    }
    });

    What can I put in the ??? to get a handle on the subCollection used in the converter, to update it when the user chooses a different option in the drop down? I've tried looking into the this object from within the convertBack function, but none of the properties seem to give me the subCollection (there is a this.tgt, but modifying this.tgt.subCollection doesn't update the span's text). Any help would be much appreciated!

    ReplyDelete
    Replies
    1. I've also tried returning new Array(length) from convertBack, but no luck with that either.

      Delete
    2. I ended up solving this by using an .on('change' ...) handler instead of a converter function, which uses $.observable($.view(this).data.subCollection) to modify the collection.

      Delete
    3. @George: In the convertBack handler, the this object has a src property which is the HTML element (select in this case) and a tgt property which is the data item (item in your mainCollection, with the subCollection property). So you should be able to achieve your scenario either by using converters, or by your onChange approach.

      Delete
  45. Hey Boris, it looks like the current version of jsViews is not stripping out the comments when link=false is used within a template. It works fine when passing it in during the link creation, however.

    ReplyDelete
    Replies
    1. @Kevin: Yes, thanks, that was a bug, which has now been fixed.

      Delete
  46. Is there a bug with {{if}} statements with link=true? It's more than possible that I'm misunderstand how its meant to be used, but here's a simple test case that renders, but doesn't update with $.observable changes. {{for}}'s with link=true seem to work. The example you have (http://borismoore.github.com/jsviews/demos/step-by-step/03_tree-view_recursive-nested-each.html) directly change view.data, but I'd expect it to work with $.observable to be consistent.

    (html characters remove so I could submit...)

    %div#test

    %script#t(type="text/x-jsrender")
    hello {{if test link=true}}there{{/if}}

    %script(type="text/javascript"
    $.templates({
    t: '#t'
    });
    var d = {test: false};
    $.link.t(d, '#test');
    setTimeout(function () {
    $.observable(d).setProperty('test', true);
    }, 3000);

    Also, any idea when you'd expect jsrender/jsviews to officially hit beta? Thanks for these libraries!

    ReplyDelete
    Replies
    1. @Viraj: Yes you are right that {{for myArray}} does update automatically when myArray changes observably, but other tags including {{if expr}}, and {{:expr}} or {{>expr}} do not. This is one thing which I plan to change, to make for a more consistent design. I am working on an approach in which none of the tags is actively data-bound by default, but that all the tags can be bound by adding an ! to the syntax. So while {{for xxx}}, {{if xxx}}, {{:xxx}} etc. would not respond to observable changes, {{!for xxx}}, {{!if xxx}}, {{!:xxx}} etc. would.

      This is one of the significant planned changes which are the reason for not yet making JsRender and JsViews officially beta. Not sure how long it will take to get there. Maybe a 2 or 3 months still. There is a lot to do before the final stable implementation, with documentation etc. But I am moving as fast as time allows...

      For now, you can achieve similar behavior to your desired data-bound {{!if ...}} in a few ways. The following can give you some ideas:

      hello <span data-link="test ? 'there' : ''"/>
      hello <span data-link="html{if test tmpl='myTmpl'}"/>
      hello <span data-link="css-visibility{:test?'visible':'hidden'}">there</span>
      hello <span data-link="visible{:test}">there</span>

      BTW to include HTML tags in comments, just replace the '<' characters by '&lt;'

      Delete
  47. How can I get a reference to the view from outside the view? This isn't clear from the samples and I only see the view used similarly to $.views(this).

    I'm converting an app from the MS AJAX Library and was able to maintain a reference to the dataview to call refresh() on it when data changed so that if's and such would re-evaluate. I see from an example that the view here has a refresh() method, but I'm having trouble getting there to call it.

    ReplyDelete
    Replies
    1. Also, you mentioned setting the debug setting on a compiled template, but don't show how anywhere.

      I should add that for the most part, switching from the MS AJAX Library and the previous editions of jquery tmpl, that jsviews and jsrender have been pretty awesome. I'm made comments before about the delays and editions being dropped in favor or starting over and over again but I've finally started taking the plunge to jsviews and have enjoyed things thus far.

      Delete
    2. @Chris: The view() method is both a jQuery instance plugin method and a jQuery static method. By providing a selector, rather than a node, you can get a view for anywhere in the DOM.

      Here is the syntax:
      $.view(node) or $(node).view() returns the view containing the node.
      $.view(selector) or $(selector).view() returns the view that contains the first selected element.

      For setting debug on a compile template, there are a couple of examples in the unit tests: here and here.

      For example you can write:

      $.templates(null, {
      markup: "#myTmpl",
      debug:true
      });

      Delete
  48. I would like to render Html Helpers in Asp.Net MVC using Jquery.

    I have been working with JQuery templates like this:

    var element1 = '@Html.TextBoxFor(m=>m.{{=key}})';
    $.template("txtboxtmpl",element1 );
    $.tmpl("txtboxtmpl", obj).appendTo("#Container");

    But it is failing(doesn't compile), since it's expecting an identifier in place of {{=key}} .

    Would this be possible to do in JsRender or JsViews? If so, how?

    ReplyDelete
    Replies
    1. @sukumar: I haven't explored using MVC Razor views to generate client-side JsRender templates, but it looks like you need to use the untyped helper @Html.TextBox("{{:key}}"). That will produce an input with the name set to the key your provide in your client-side obj. Beyond that I would need to understand better how you are intending the client-side data and the server-side model to relate to each other.

      Delete
  49. Hi, thanks for all your hard work. I have a simple example here, displaying quite a bit of data.

    http://www.petermessenger.com/JsRenderDemo.htm

    With latest version of chrome, this takes 400 milliseconds to render. IE9 takes 1.275 seconds to render.

    But IE7 take over 16 seconds. Do you have any suggestions how we can get better performance for IE7 users?

    ReplyDelete
    Replies
    1. I have spent some time looking at your code. You are doing a lot of catenation of strings. This causes lots of problems in IE7 (see https://developers.google.com/speed/articles/optimizing-javascript)

      Swapped around the code a bit so it uses arrays and the join method. This doesn't seem to have any impact on performance for the later browsers, and cuts the render time on IE7 down to 7 seconds.

      http://www.petermessenger.com/JsRenderDemo2.htm

      Delete
    2. @Peter: Thanks. As they say in that article, "concatenating is actually slightly more efficient on IE8 and other non-IE browsers such as Chrome", so while I used to always use the push/join technique, I switched to concatenation in JsRender, considering IE7 a less important target than the other browsers. But I will try to follow up on investigating the real differences in each browser, and consider whether to switch back. I may wait till being ready for beta first though, and then go into some more specific perf optimization work... Your running sample is a great help...

      Delete
  50. Hi Boris,
    I have a strange behavior with jsviews.

    I have a data model "data":
    var data = {
    people: []
    };
    and a sample dataModel "sampleData"
    var sampleData = {
    people: [{
    name: "Umberto",
    shirtColor: "blue"},
    {
    name: "Vale",
    shirtColor: "pink"}
    ]
    };

    before I link the people data with jsviews I reset the data, set data=sampleData and then compile the template (peopleTemplate) and link it to data model ($.link.peopleTemplate(data, "#linkedOutput");)

    when I add people with observable:

    $.observable(data.people).insert(data.people.length, {
    name: "Pinco Pallino " + counter++,
    shirtColor: "White"
    });

    the new people is add in data.people array, but the same people is added in sampleData!

    It's a normal behavior?

    Here http://jsfiddle.net/joeyramone76/6P5rB/47/embedded/result/ a jsFiddle demo to reproduce the problem.

    ReplyDelete
    Replies
    1. @joeyramone76: If you are setting data = sampleData, then from that point they are the same object, so inserting into data is now of course the same as inserting into sampleData. Maybe what you wanted to do was take the items from sampleData.people, and insert them into the data.people array. You can do that by doing $.observable(data.people).insert(sampleData.people) or $.observable(data.people).refresh(sampleData.people).

      Delete
    2. Thank you Boris! Now with $.observable(data.people).refresh(sampleData.people) it's all ok!

      Delete
  51. Hey Boris - first of all, what you have done with jsRender/Views is incredible. Writing apps with it is fun, natural, and lean - in a way I don't think any other current JS "framework-ish" thing I've dabbled with is. It makes other *js approaches that deem themselves "lightweight" seem ham-fisted and unwieldy by comparison - so much so that I've come to refer to jsR/V as "featherweight". Just awesome and fun to work with - thank you for making it.

    I've noticed that there are a couple beta-ish frameworks coming down the pike like Meteor that support "live-remote-linked" data ( http://www.meteor.com/#screencast ). In the screencast, they say you can use Meteor with any templating engine (so I assume it would go with jsR/V?) to achieve that effect, but at first blush I feel like I would rather not add another dependency like that - especially if I could get basically the same thing with just jsR/V.

    I haven't had to do anything like this yet, but I'm definitely interested in it..so my question is: For the long game would you recommend that I figure out how to do this with "pure" jsV/R (and maybe some other featherweight component/library) or should I just figure out how (if?) to do it with Meteor in cases where "live-remote-linking" is the thing to do?

    ReplyDelete
    Replies
    1. @TheGrapeApe: It's good to hear what you appreciate in JsRender/JsViews...
      On the remotely linked data, that is very related to some of the long-term scenarios that interest me for JsViews, but to achieve it requires not just JsViews but also a server (or service) story for round-tripping data, and possibly using a push model. So JsViews may get smarter (e.g. async data-linking) but won't be sufficient on its own. For now, you could definitely make it work with current JsViews along with your own server story. It could involve something pretty lightweight, e.g. SignalR, without necessarily going all the way towards as complete a platform as Meteor...

      Delete
  52. Hi Boris, Nice work on jsrender and jsviews. I'm trying to use the converters for localization, but I want to send some additional variables to the converter function. Is that possible?

    now working: data-link="{converter:variable:}"
    need something like this: data-link="{converter:variable, decimals:}"

    ReplyDelete
    Replies
    1. After some research I found a way to convert a variable with additional variables, but I can't find a way to do the same for backward converting.

      convert: data-link="{:~converter(variable, decimals)}"
      convert back: data-link="{:~converter(variable, decimals):variable:_convertBack(variable, decimals)}" ???

      I think something like this would be easy to use: data-link="converter:variable, decimals:convertBack"

      Delete
    2. @Dennis: I have an example coming in the next commit which covers exactly that. I'll post a link from here when it is available.

      Delete
    3. @Dennis: The converters example if up now, here: step-by-step/08_bit-and-int-converters. The converters have been modified to make it easier to get the context you need, and to provide variables, for example by setting the value or other attributes on the element, or by adding expando properties. That way the converter syntax stays simple, and compatible with a future plan to supported chained converters.

      Delete
  53. humm...am I missing something? it seems doesn't work. Thx

    {{for Notes}}
    {{:#data}}{{if #index == length-2}},{{/if}}
    {{/for}}

    ReplyDelete
    Replies
    1. @mike: There is an example of exactly that in the first of these examples. You are getting length in the context of the current item, which does not have a length. You can either write {{if #index == #parent.data.length-2}}, or you can pass the length of the array in from the outer context as in the linked example:
        {for Notes ~count=Notes.length}}
          {{:#data}}{{if #index == ~count-2}},{{/if}}
        {{/for}}

      Delete
  54. @Boris: What's the status on jsviews now? Getting closer to beta?

    ReplyDelete
    Replies
    1. @anonymous: Yes, making a lot of progress with the final set of features for JsViews, so definitely getting closer. Not far from my answer higher up. I would estimate late September or early October for beta for both JsViews and JsRender.

      Delete
    2. @anonymous: I have updated the JsRender Readme to provide this information on expected dates for Beta.

      Delete
  55. @Boris: thanks for modifying the converter function. The ability to use the context within the converter helps me to localize variables with some additional arguments wich can be set within the context.

    A slide problem that still occurs is the lack of flexibility to bind contexts to templates (anyway I can't find a way to bind a context to a template within the templates). I've got a situation like below.

    There are multiple templates that use the contactperson template to view contactpersons on debtors, companies en suppliers. However the context wich belongs to the contactperson differs. for example the context for a contactperson wich belong to a supplier or company has the function addDepartment and a contactperson wich belong to debtors has a function called addRelation, also the validation function is different.

    Is there a way to set the context of a template within the templates?
    like: {{for contactperson tmpl="contactpersonTmpl" ctx="contactpersonDebtorCtx" /}}

    ReplyDelete
    Replies
    1. @Dennis: Yes, you can certainly pass different helpers to the same template used in different contexts. And you can also declare helper functions to be associated with a specific template, as part of the template registration/compilation. Your question provided me with the encouragement :) to add a couple of new samples, to document better these aspects. You can find them here: accessing parent data, here: passing in context and here: associating helpers with templates.
      The last one is a direct response to your example scenario...

      Delete
  56. Hi Boris!

    First of all, great work on JsRender and JsViews!

    I was wondering wether it's possible to use data-linking with a function that is both a getter and a setter, but takes a key-argument to access the correct property?
    Something along the lines of data-getfrom="attribute('name')" and data-to="attribute('name', $value)" ?

    Couldn't find any information on it.

    Thanks!

    ReplyDelete
    Replies
    1. +1

      This is something that gets really useful when your model used has more logic than just a simple data model. Having named getters and setters for your attributes is not always a good idea if your model inherits some base model which has it's own methods (naming collisions etc).

      Delete
    2. Yes, you can do that. Here is an example

      data = {
        firstName: "box",
        firstName: function(val) {
          if (val !== undefined) {
            this._firstName = val;
            return;
          }
          return this._firstName;
        }
      };

      <input data-link="firstName" /> <span data-link="firstName" ></span>

      The following issue on GitHub is about the same scenario...

      Delete
    3. Thanks for the reply!

      However, my scenario is a bit different, as I have setters/getters that takes the attribute to get/set as the first parameter and the value field as a second parameter.
      setAttribute('name', 'newName'), getAttribute('name') etc.

      Tried your proposal, but the problem is getting the property-key into the function as well.

      Delete
    4. Knut - have you tried using converters?

      Like this? -
      $.views.converters({
      setAttribute: function( key, val ) {
      yourData[key] = val;
      },
      getAttribute: function ( key ) {
      return yourData[key];
      }
      });

      Delete
    5. Hi,

      I've looked into it, but was hoping that there was some way of doing this natively.
      Since I need to use converters on some of my properties already (for other reasons), using converters for regular getters and setters seems a bit excessive.
      If it's not possible, I think I'm better off redesigning my models.

      Thanks though!

      Thanks though!

      Delete
    6. @Knut and @TheGrapeApe: The problem with parameterized getters and setters is that there are many ways it can be done, and JsViews cannot natively support all possible designs. You need to be able to tell JsViews the parameters you want to pass in with both the setter and the getter (which could even be different from each other). Take a look at this 'Two way data-binding with converters' sample which uses the value attribute on inputs to pass parameters (in this case the bit-mask) to the converters. You may be able to adapt this technique.

      You could also add an issue on JsViews with a feature request, giving more context on your scenario. This issue may already may be relevant to you, and you could look at the other ones such as this, too. There is also a request for chained converters I may be able to support in the future...

      Delete
    7. @Boris
      Realize that it will be hard to support this feature, so I changed my models to have named getters and setters like you suggested earlier.

      Thanks for your time, and keep up the good work!

      Delete
  57. Just a quick question - when I run $.link I get really bad performance from some parts of jQuery - in 8.0 the buildFragment functions profiles at almost 3.5 seconds per call..has anyone else seen this behavior or have any idea how to improve performace on this?

    ReplyDelete
    Replies
    1. @Brent: Would you be able to put a sample on jsfiddle that shows the perf issue? I can try to take a look. The current update I am working on takes over some of the buildFragment work from jQuery, so I am interested in the perf aspect...

      Delete
    2. I have an example up at: http://qoor8r.com/jsviewsdebug.html (If you want me to move it to jsFiddle I can do that too, if it's better). Thanks so much, Boris - love your work with js Render and Views.

      Using IE 9.0.9 and jQuery min 1.8.0, I get the following at the top of my script profile:
      Function Count Inclusive time (ms) Inclusive time % Exclusive time (ms) Exclusive time %
      offsetWidth 2,603 4,491.45 38.59 4,491.45 38.59
      buildFragment 3,483 4,140.41 35.58 3,532.35 30.35

      Delete
    3. Oh - also when you use jQuery 1.7.x, the culprit is "clean" instead of "buildFragment" if that helps.

      Delete
    4. Update - I stripped out some things that HTML lint was complaining about..that improved performance, but it's still over 1 second per call...is that about the bes I can hope for?

      Delete
    5. @Brent: Is the perf cost just on the initial rendering, or is it also during subsequent user interaction?

      I see you are using the jQuery accordion, and loading much more into the DOM than is actually seen by the user. The philosophy of JsViews is more to dynamically render content and insert it when the user actually sees it. (e.g. expanding the accordion), so that you don't incur that high "initial rendering and inserting into the DOM" cost. So a very useful test would be to see if you can create an equivalent page in which you are not using data-link to insert content, but simply rendering with jsrender and using $().html() or $.append() to insert in the DOM - and then using the accordion etc. as before for dynamic behavior. In that case all of the buildFragment or clean calls will be nothing to do with JsViews. See whether the performance is any better doing it that way. If not, then you probably need to rethink how you do the accordion etc...

      Delete
    6. @Boris - After the intial render, it works like a charm. I think your suggestion of dynamically rendering the content as the user opens respective accordion sections would probably make it perform much better, but that would mean hooking up a lot more events so I'll probably just decide to live with the initial-load performance hit (it's not that bad for the application's use case, really...and on Chrome for whatever reason, it's hardly noticeable).

      I still love js render and views...but I'm taking away a pattern lesson here of "render in the smallest chunks possible, just in time for the user to see it" as you suggest. I think I had an unrealistic expectation for the perf cost of rendering (I didn't think it would clock in at 1000ms per object like it apparently does), so I'll keep that tempered in the future. ...another lesson that I came up with a little anecdotal evidence for was "when you can pick between a converter and a helper - use a converter" but helpers really do let you pull off some crazy stunts.

      One last question - are there any books/references out there other than your examples on gitub? I haven't found any really good ones.

      Delete
  58. I've got a quick question on view.refresh().

    I've been using this to refresh views, but it seems like it also works very well when refreshing a given part of a view $.views('#someelement .myclass'); This result is the contents of #someelement .myclass getting an update, but the rest of #someelement stays intact. However, this breaks if I have an "IF" statement inside .myclass. What happens then is that the whole view (#someelement) is re-rendered. Is this a known limitation?

    ReplyDelete
    Replies
    1. @Erik: Looking more closely, this works correctly for me. See this jsfiddle. If you have a repro that does not work, can you post to JsViews Issues?

      Delete
  59. Could you add the ability to merge classes to elements rather than replace them. As in our system we set validation classes such as required, and also use jquery datepicker. Jquery datepicker adds some of its own classes which get overridden by data-link class if specified.
    In our system we've implemented a:
    data-class-required='{:required}'
    Meaning if required is true, then the required class is added otherwise removed. And for the static classes: data-class='datepicker date'

    ReplyDelete
    Replies
    1. @Matt: Yes, I plan to provide that at some point, (e.g. a way to use data binding to toggle individual classes). It would be great if you want to add a JsViews issue to track that feature request (or discuss design)...

      Delete
  60. Hi Boris,
    First of all, congrats on your successful framework design and thoughts.
    I am interested to get daily updates on this. How I can do this?

    ReplyDelete
    Replies
    1. @Anup: For now, you can subscribe to comments on this blog, or other blog posts, and you can "watch" the projects on GitHub. I hope also to set up a forum for discussion, along with full docs and tutorials, etc. but that will be after releasing the beta, or around V1.0.

      Delete
  61. Hi Boris,

    Great work, great projects!

    We're in late September now. And I'm eagerly awaiting Beta.

    Are you still on-track for a late September or early October Beta?

    What issues do you see remaining between here and there?

    Thanks again for the great work!

    ReplyDelete
    Replies
    1. @SY: I hope Beta for both JsViews and JsRender will be end of October, and V1.0 end of calendar year. No huge issues though. I will shortly upload an update with some major changes, and will then gradually document (or provide samples) for the new features it contains...

      Delete
  62. Little afternoon hack that shows some of the stuff you can do when you combine jsRe/Views with stuff like RaphaelJS. Enjoy. http://qoor8r.com/rdi.html

    ReplyDelete
  63. Boris thanks again for this awesome piece of technology!

    I am a little concerned about serving content to google though.
    I know this has nothing to do with jsRender per-se...but it would be nice to have maybe a php renderer of this templates too.

    So I'd make templates only once and serve them via js to users and via html (dynamically created by php) to spiders

    are there any good pointers in this direction? good practices?

    ReplyDelete
    Replies
    1. I guess, you could use "degradable" principle and put the information for search indexers in the noscript tag. At least, even Google recommends this approach. I myself have implemented it the following way. On PHP side I have a Helper for an initial table renderer which renders Javascript for my custom client-side grid, and also packs a bunch of JSON of actual data for the first page of the table. And it also puts some data in the noscript tag. By default, it puts the same data as in the JSON variables, but you can format it more nicely with paging links not only for searchbots but also for users who do not have JS.
      On the client side, when my PHP table loads, if JS is not enabled, users and search bots will see the contents in the noscript. But for users with JS, that JSON data which I packed with initial render, will be picked up by Javascript templating engine (of your choice) and the first page of the table will be filled in.

      Delete
    2. @Damir: Yes, this is orthogonal to JsRender and JsViews, and I don't have additional specifics on it at this point. For server-rendered JsRender templates, a PHP renderer would be a great plan, and I have plans to invest in rendering in Node.js etc. But that is for after V1...

      Delete
    3. Well, we really only need to deliver the html version to crawlers, which already has a workaround built in. Hash bang fragments allow for client-side ajax variables that fallback to a server-side query when crawled. Something like www.foo.com/#!hello-world/ would fallback into http://www.foo.com/?_escaped_fragment_=hello-world. Couple that with a decent permalink structure and htaccess file, and we're ready to go in terms of routing.

      We also have the option of bypassing hash bangs, and using [meta name="fragment" content="!"] to trigger the fallback.

      In terms of actually rendering the html itself, the approach I've been tinkering with is to use preg_replace_callback in a similar fashion as the wordpress shortcode system to embed variables within the template. The actual template itself then would be an html snippet with shortcodes embedded that would compile into either a script, or the content itself.

      Delete
    4. Another excellent option is to use a standard permalink-driven menu that is then rewritten with javascript to use hash bang syntax. This could very easily be a much better option, and certainly a much simpler one. It also has the added bonus of simplifying resource loading to a degree, as you can initialize something like RequireJS.

      Delete
    5. Yes, I know all the practices for serving ajax content the correct way, so the google can access each url with spider trough escaped_fragment.... I also implemented history api http://diveintohtml5.info/history.html ... it is better since you would get regular URLs...but the problem is not there...

      the problem is to SERVE the same content to crawler as you would to the end user...google is penalizing sites that serves different content as they do to users. so I need something to serve google my data the same way as jsrender does....

      so one way, very awkward and not really an option..... open a website, generate content with jsrender than onRenderFinish use an ajax requset that would ave statically the html generated... so I can serve it next time in [noscript][/noscript]"

      the oter way is to have the template in php...for example: list_item.tpl.php... and then have inside something like: [li][php]echo_var($row["myfield"], "{{:myfield}}";[/php][/li] and then serve the content accordingly to the output var: list_item.tpl.php?output=html or list_item.tpl.php?output=jsrender

      the third and the best way would be, to have a plane jsrender template list.item.tpl.js .... but with a php port of jsrender.... so I would use in php like this jsrender::render("mytpl", $row_data);

      the third way would be the est option for me in terms of maintainability

      Delete
    6. I think node.js is the solution for me... if I only could make it work :(

      Delete
  64. Hi Boris, I'm using jsrender with success in many cases but there is one problem: the table data grows slowly, but the data is very dynamic (about 150 lines is sent to the browser every 500ms). The table data is sent via WebSockets, and every time the data arrives the table is rendered again using the function 'render' of jsrender. The browser window is getting very slow. Do you have any suggestions to solve this problem?

    ReplyDelete
    Replies
    1. @Sandy: Take a look at all the samples using JsViews. JsViews is able to incrementally render the DOM when items are added or removed from rendered collections. Here is an example.

      Delete
  65. Hi Boris,
    Thanks for your work.
    I googled and found this : http://borismoore.github.com/jquery-ui/grid-spf-observable/observable-previous/index.html
    I liked this example because it lets me insert or delete rows at any row in the table.
    When I downloaded from : https://github.com/BorisMoore/jsviews
    it doesn't contain this example.
    I tried downloading the source code, and some other files I did not have (such as grid.js), but I haven't got the example working.
    Given the development taking place on jsrender and jsviews, is the original example I looked at obsolete?
    If not, can you point me at a bundled up working version please?
    Neil.

    ReplyDelete
    Replies
    1. On further investigation, Boris, I think I want to use code I found in here : /BorisMoore-jsviews-c72d2d5/demos/step-by-step/04_editable-data.html and then place the add row logic into the onclick event of each row. I imagine I will then have a line of code that looks something like the existing code : $.observable( movies ).insert( movies.length, { except that 'movies.length' will instead be an index number of the row where I want to insert.
      Neil.

      Delete
  66. In IE8 I needed :checked pseudo css selector for checkbox and radio elements. Then, I decided to use a javascript helper function for that control. It worked fine with user inputs but not when jsViews sets the value. As a result I modified a few lines in jsViews:

    #192 if (target.type === CHECKBOX) {
    attr = "checked";
    // We will set the "checked" attribute
    sourceValue = sourceValue ? attr : undefined;
    // We will compare this ("checked"/undefined) with the current value
    $(target).trigger("change");
    }

    I added a trigger to the change event of the element. That solved my problem. I don't know if it is necessary by default but it may help to someone in my condition.

    ReplyDelete
    Replies
    1. @Ibrahim: Thanks. I wonder if you could also create an issue on JsViews GitHub for this request/suggestion. It'll help me to track it.

      Delete
    2. I actually forgot it because a lot of time passed over it, but I'll create it now. :)

      Delete
  67. Hi Boris,
    I want to limit text upto 20 or 40 characters. How it is possible?
    Please help.

    ReplyDelete
    Replies
    1. @Anup: I'm not sure what you mean. If you mean as input validation, you can look at jquery-validation... It can be used together with JsViews. JsViews does not currently have integrated validation code.

      Delete
    2. @Anup You can basically use maxlength attribute on standart html inputs. If you are using a textarea you can write your own function or use something like this: http://www.stjerneman.com/demo/maxlength-with-jquery

      Delete
  68. Hi Boris and thanks for great work!

    With jsviews i would like to bind two (json)fields to an input element which is the base for a jquery-ui-widget. I get it working like this: < input data-link='{:Quantity:} data-locked{:FixedQuantity}' /> and from my widget I can get the proper values for Quantity and FixedQuantity. If I from my widget change the value of the input element the updated Quantity field is reflected back in my json-data source but not the FixedQuantity (data-locked) field. Is there a way to bind/link data-attributes like this, or do you have an idea how it can be solved?

    Regards
    Eric

    ReplyDelete
    Replies
    1. @Eric: Your binding will bind from the data to the data-locked attribute. But if something-else (the widget...) is changing the attribute, there is no cross-browser event available to listen to that change. (Only the DOM Mutation Events...). You would need to hook into your widget code to listen to the change and call setProperty from there to update your FixedQuantity data property.

      Delete
  69. Is it possible to write a simple plugin to format "text/x-jsrender" typed scripts as html in Visual Studio? If I can find a way I'm willing to try it.

    ReplyDelete
    Replies
    1. @Ibrahim: There is already a plugin available for Visual Studion 2012: Web Essentials.

      It adds syntax highlighting within script blocks (of type other than text/javascript). It also provides hightlighting on {{foo }} tags.

      In a future release it will likely be built in...

      Delete
  70. Hi I'm loving the way observable works in JsViews but I like a couple other parts of Knockout. Before I consider converting to JsViews I have a couple questions. Will you be able to say something like the following in a future version?:

    <tbody data-link="for: data">

    This allows me to link my whole template up without a script block and will be valid HTML.

    A couple other minor points. It would be great if you could hook up click events using the data-link attribute. Oh and I slightly prefer the data-bind syntax in Knockout.

    I understand JsViews is undergoing some serious changes ready for a beta release. Are any of the issues above being tackled in the next release?

    Thanks

    ReplyDelete
    Replies
    1. @Jimmy: Thanks for those questions. Yes, basically all those directions should become available with the next release. I'll probably give you a more detailed reply here in a few days...

      Delete
  71. Dear Boris,

    Your work is great. Thanks for working on JsRender. It seems to be the best way ever to describe page visual element structures.

    I am concerned about the SEO over JsRender/ed/ pages. Do you have plans for JsRender to be able to take data from HTML like the code below so SE could index the contents?

    $('.templatable').each(function(elem){
    var tname = elem.attr('rel');
    if (tname) {
    var data = fromHtmlToJsObject(elem);
    var html = $('#'+tnane).render(data);
    elem.html(html);
    elem.removeClass('notrendered');
    }
    });

    <script id="movieTemplate" type="text/x-jsrender">
    <tr title="{{attr:availability}}">
    <td>{{loc:title lang='EN'}}</td>
    <td>{{loc:title lang='FR'}}</td>
    <td class="synopsis">{{:synopsis}}</td>
    <td class="synopsis">{{>synopsis}}</td>
    </tr>
    </script>

    <div class="templatable notrendered" rel="movieTemplate">
    <ul>
    <li class="availability">Available in 'X&Y' Cinemas</li>
    </ul>
    </div>

    Thanks

    ReplyDelete
    Replies
    1. @Enrique: Sorry I didn't get back to you on this. Currently my priority is to reach beta and V1, and SEO such as your approach above won't be a target feature. But after V1, yes, that scenario will be relevant. My initial/primary concern will be to allow server rendering using the same template as in the client (browser), and simply activate the data-binding in the browser once the page is loaded. So then SEO would be addressed by the initial page content. I hope this approach will be simpler than the kind of processing you describe above, and will address SEO requirements.

      Delete
  72. Jason,your work is great,I m waiting for beta.How long it takes to release beta?

    ReplyDelete
    Replies
    1. @Jason: I am hoping to release Beta at the end of February. Making good progress, but it is a lot of work - with some very powerful features coming with JsViews beta.

      Delete
  73. I have a question about mechanism of data-bindding: when a complicated, nested template is binded to a variable, if the variable changes, the whole template will be re-rendered?

    to make it clear, for example, the variable is:
    {
    "a": 1,
    "b": 2,
    "c": [
    { "d": 3 },
    { "e": 4 },
    { "f": 5, "g": [ 6, 7, 8, 9] }
    ]
    }

    when I add new element to g, the whole template will be re-rendered?

    ReplyDelete
    Replies
    1. @ Hieu Vo: If your template is data-binding to g, for example by using {{for g}} (or with the latest version of JsViews, where data-binding is opt-in, {^{for g}}) then inserts and removals will render incrementally. Just the added/removed item will get inserted into/removed from the DOM

      Delete
  74. So I'm trying to understand the event handling support. Is there a simple example showing how I can get a notification when my model has been updated with a bound jsView?

    ReplyDelete
    Replies
    1. @dan: You can bind to the propertyChange or arrayChange events, or you can use $.observable.observe(object, path1, path2, ..., myCallback);

      The second approach is very flexible. It allows you to listen to multiple objects and paths, including 'deep observability' where you listen to any changes on a path "a.b.c.d", by using the syntax "a^b.c.d". Not a lot of samples showing this, but you have this: 02b_editable-data.html, and many examples in the unit tests, such as here.

      Delete