BorisMoore / jsrender

A lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
http://www.jsviews.com
MIT License
2.67k stars 339 forks source link

Unusual approach to nested $.render() calls leads to a bug when useViews advanced setting is false #333

Closed earshinov closed 6 years ago

earshinov commented 6 years ago

We are having trouble upgrading from v1.0.0-beta to a more recent version.

Please see JsFiddle: https://jsfiddle.net/psqu0ttw/3/ Instead of rendering "1 2" it produces an error (visible in Chrome DevTools).

We have an hierarchy of views, each of which is capable of rendering itself via a call to $.render.

In the example from the fiddle, an outer view renders two inner views in its template. Rendering the first inner view results in a nested call to $.render. Apparently something goes wrong, because rendering the second view fails with an error. In order for the error to occur, the if in the template must be present and have a condition. The condition itself can be anything, though.

The example works correctly using v1.0.0-beta and seems to fail when any recent version is used (tried 0.9.84 and 0.9.89).

earshinov commented 6 years ago

Let me put the code here for convenience:

<script id="tpl-outer" type="text/x-jquery-tmpl">
  {{:a.getHtml()}}
  {{if true}}{{:b}}{{/if}}
</script>

<script id="tpl-inner" type="text/x-jquery-tmpl">
  1
</script>
function renderTemplate(templateId, data) {
  if (!$.render[templateId])
    $.templates(templateId, "#" + templateId);
  return $.render[templateId](data);
}

class InnerView {
  getHtml() { return renderTemplate("tpl-inner", this); }
}

class OuterView {
  constructor(a, b) { this.a = a; this.b = b; }
  getHtml() { return renderTemplate("tpl-outer", this); }
}

var a = new InnerView();
var b = 2;
var outer = new OuterView(a, b);
alert(outer.getHtml());
BorisMoore commented 6 years ago

Ah - yes - there is special perf optimization code that was not used in the v1.0.0-beta - and you have revealed a rather obscure bug in that code, due to your unusual mix of declarative and programmatic rendering. Thanks for letting me know...

I will fix the bug in the next update, but there is a workaround you can use immediately which is to set:

$.views.settings.advanced({useViews: true});

See http://www.jsviews.com/#settings/advanced

With that setting, you should be able to move to any recent version... v1.0.0-beta

earshinov commented 6 years ago

Thank you for the clarification. I think we will wait for the next update.

BorisMoore commented 6 years ago

This has been fixed in release v0.9.90.

If you still see any issues, let me know.

It is probably a good idea in your scenario to set useViews to true ($.views.settings.advanced({useViews: true}); - though with the fix it should still work correctly even if you don't.