3

I am building a knockout\jQuery plugin that creates it's own UI when invoked, like so:

<input type="text" name="filter" id="filter" />

// renders ui
$("#filter").myPlugin();

Usual jQuery stuff. However, as part of the behavior I wish to make use of knockout templates. It seems though that knockout only recognises templates that are in the page when it first loads.

Here's a concise example that shows the problem:

<div id="container">
    <div data-bind="template: { name: 'fieldsTemplate', foreach: FilterRows() }">
    </div>
</div>

And the js:

var fieldstemplate = $('<script>', { type: "text/html", id:"fieldsTemplate" });
var row = $('<ol>').html("<li>row</li>").appendTo(fieldstemplate);

fieldstemplate.insertAfter($("#container"));

var model = { FilterRows: ko.observable(["row"]) };
ko.applyBindings(model);

This produces the following error:

Uncaught TypeError: Cannot read property 'length' of null knockout-2.2.1.js:8

I've also created a JS fiddle of the problem here: http://jsfiddle.net/roysvork/EcFRc/

Bascially I'm wondering whether I need to take another approach here, or if there is a way I can 'parse' the dom to refresh knockouts knowledge of the templates?

Thanks in advance!

beyond-code
  • 1,423
  • 1
  • 12
  • 20
  • 1
    You can certainly use an alternative method of loading a template, but just wanted to mention that for your original issue this is really related to the way that you set the `script` element's contents. You would want to use `text` to set the content like: http://jsfiddle.net/rniemeyer/uWbQt/. The error is not because it can't find the template, but instead because it believes that the template has no content. Hope that helps. – RP Niemeyer Jun 10 '13 at 13:42
  • Ahh brilliant, thanks Ryan. Seems the the other thread was a bit overkill in the end! It was an interesting adventure into the workings of the template engine though at least. – beyond-code Jun 10 '13 at 14:27

1 Answers1

1

You can override the template source engine. You can either override the default template source, or write a custom template binding and only override the template source for that binding.

To set default template engine you can checkout this plugin that i've done

https://github.com/AndersMalmgren/Knockout.Bootstrap/blob/master/src/Knockout.Bootstrap.js#L27

To overide the template source from a custom template bindng you can do

ko.renderTemplate(template, bindingContext.createChildContext(data), engine /* reference your template engine */, element, "replaceChildren");
Anders
  • 17,306
  • 10
  • 76
  • 144
  • I think I follow... so you're saying one potential solution is to provide an alternate template source that can be specified as a string? – beyond-code Jun 10 '13 at 11:06
  • Yes, a very basic string template source can be found in this plugin I wrote https://github.com/AndersMalmgren/Knockout.Combobox/blob/master/src/knockout.combobox.js#L318 – Anders Jun 10 '13 at 11:08
  • Cool thanks for the input... I actually need to use ko.renderTemplateForEach() but this doesn't seem to accept the engine as a parameter, is this something you've come up against? – beyond-code Jun 10 '13 at 11:28
  • Disregard that last comment, after looking over the source some more I see that we can attach the template engine to the options. – beyond-code Jun 10 '13 at 11:42
  • I was just about to answer :D – Anders Jun 10 '13 at 11:44
  • Gah... fairly major setback. ko.renderTemplateForEach() is not exposed in the minified version of the library, so I can't use it unless I internalise it inside my plugin :/ – beyond-code Jun 10 '13 at 13:27
  • Sorry didn't know that, thats why you shouldn't code against the debug version :D You can write a own bindng that uses the standard template binding, but before calling it sets the global template source to your custom string template source, and after render sets it back..A bit ugly. Or use the ko.renderTemplate and sort out the foreach part yourself – Anders Jun 10 '13 at 13:40
  • By the way, you can always wrap your template with a foreach binding and use the ko.renderTemplate function like http://jsfiddle.net/5jKHD/1/ – Anders Jun 10 '13 at 13:46
  • This is what I ended up with: http://jsfiddle.net/roysvork/AKr3c/ Thanks again for your help. – beyond-code Jun 10 '13 at 14:23
  • I would say its better to use the provided template source API instead. – Anders Jun 10 '13 at 14:42
  • Better, but I must say that I do not understand why you need use jQuery at all.. oh well – Anders Jun 10 '13 at 15:06