Question

I'm trying to render HTML for embedding Flash objects using Knockout.js' native templating faculties. jQuery.tmpl does the job perfectly well, however I cannot use it due to conflicts with the Knockout-sortable plugin.

Here's an example of flash plugins quirking with the native templating: http://jsfiddle.net/7y3ub/35/
In Chrome, the player just never shows up. In Firefox, the player will show up if you change the channel while the checkbox is checked. Rechecking the box however makes the player vanish again.

The 'if' binding is necessary due to the fact that there may be many instances of flash plugins loading and unloading over the duration of the page.

From what I can tell, the HTML needs to all be in place by the time the object/embed tags enter into the visible DOM. This is why jQuery.tmpl would be great in my case. I've tried forming the HTML string myself, but I do not know how to apply and maintain the bindings that the new markup contains.

Bottom line, I either need a way to instantly render the HTML while still supporting bindings, or find a way to make jQuery.tmpl and Knockout-sortable compatable with each other.


Here's an example of the incompatability: http://jsfiddle.net/7y3ub/41/
The code in that example will work perfectly if you simply unreference jQuery.tmpl. http://jsfiddle.net/7y3ub/42/

The error message in the console seems to imply that the context is not being adjusted properly, or rather the implied foreach is not executing. The message becomes even more unusual in this tweak where the SubItem objects are replaced with simple strings: http://jsfiddle.net/7y3ub/43/

Was it helpful?

Solution

I am not sure about the jQuery Tmpl incompatibility. I will have to look into that further. It would be nice though, if you did not need to use jQuery Tmpl just for this purpose.

Looks like some browsers (Chrome especially) have an issue with dynamically setting the src on an embed element. Here is an issue: http://code.google.com/p/chromium/issues/detail?id=69648. Here is a similar question: Dynamically change embedded video src in IE/Chrome (works in Firefox)

So, to make this work, we have to avoid using the attr binding on the element, as it will cause this issue.

A simple way to make this work without having to fall back to a different template engine is to use the html binding on the object element. It would be like:

<p data-bind="if: StreamEnabled">
  <object width="320" height="240" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" data-bind="html: Template">
  </object>
</p>​

With JavaScript like:

var ViewModel = function() {
    this.StreamEnabled = ko.observable(false);
    this.Channel = ko.observable("saltwatercams");
    this.Template = ko.computed(function() {
        return "<param name=\"movie\" value=\"" + this.Channel() + "\"></param><embed width=\"320\" height=\"240\" type=\"application/x-shockwave-flash\" src=\"http://cdn.livestream.com/grid/LSPlayer.swf?channel=" + this.Channel() + "\"></embed>";
    }, this);
};

It is unfortunate that we need to build the "Template" in our view model, but it seems like a reasonable workaround to this issue.

Sample here: http://jsfiddle.net/rniemeyer/CWPwj/

As an alternative, you could consider using a custom binding. Perhaps one that clones the node, applies the attr binding, and swaps it with the original. This would avoid embedding the template in the view model. I can't see other uses for this binding other than this scenario, but here is a sample implementation: http://jsfiddle.net/rniemeyer/rGP7z/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top