Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a reliable, cross-browser way to use polyfills with knockout?

We have a site that is driven pretty much entirely out of knockout and we need to support all major browsers, including Internet Explorer back to IE7 (not IE6).

Chrome already supports almost all of the HTML 5 features that we actually care about, and Modernizr handles the CSS hacks like a champ. But there are times when we still have to resort to polyfills, two notable examples being the placeholder attribute and more recently the <details> element.

Most of the polyfills are or rely on jQuery plugins, which is great in theory. Unfortunately, they also tend to be ineffective at dealing with dynamically loaded content - which there's a ton of when you use knockout (or any templating engine, really). Further complicating matters is that we're using knockout as true MVVM, so there's no decent place to shoehorn in a bunch of JS hacks to reload the plugins (which is probably a good thing as far as our architecture is concerned, but frustrating on this front).

We were able to come up with a semi-reliable implementation using the DOMNodeInserted event (deprecated, I know) for Firefox and IE9. Unfortunately it didn't work in IE8, because legacy IE doesn't support it and it seems damn near impossible to replicate in those browsers. onreadystatechange seemed promising at first but the event tends to fire too early - even if readyState is explicitly checked - and the polyfills miss their targets, so to speak.

The only option we tried that actually worked reliably in IE7/IE8 was using a repeating timeout to rerun the polyfills every 50 ms. Unfortunately, that also consumed an entire CPU constantly, and bumping it up to even 100 ms caused a too-noticeable delay in the UI, so not really suitable for production use.

So: Is there any reliable way of combining traditional polyfill techniques with dynamic content and templating engines like knockoutjs, that works in every major browser down to at least IE7?

(FWIW, we did eventually manage a workaround using knockout's afterRender binding, but that kind of takes the "poly" out of "polyfill". I'm hoping for something that we can write once and then forget about.)

like image 652
Aaronaught Avatar asked Nov 04 '22 03:11

Aaronaught


1 Answers

The way I solved the same problem was to wrap most of my jQuery plugins, and behaviors in general, in knockout bindings (http://knockoutjs.com/documentation/custom-bindings.html). So I had, for example, a placeholder "binding" that I used on each input like <input data-bind="placeholder:'Some Placeholder Text'"/> that either simply set the placeholder attribute or did some IE hack depending on the need.

A broader solution would be to augment knockouts binding provider (http://www.knockmeout.net/2011/09/ko-13-preview-part-2-custom-binding.html). The binding provider is the thing that traverses the DOM (both on load and when dynamically loaded) and identifies bindings. By default, that essentially means it's just looking for data-bind attributes and ko comments, but you can change this to also find attributes like placeholder, input types for date or number inputs, etc, and add your IE hacks.

like image 156
nicholas Avatar answered Nov 09 '22 12:11

nicholas