afterRender
works with template bindings, but after converting my templates to components, there does not seem to be any way to use afterRender
. I have tried looking for an example of a component that uses afterRender
, but cannot find anything.
问题:
回答1:
I could not get the method working as per the above post. However i found a workaround on the git issue list and it doesn't require a custom KO Binding.
Add the below line in your component template html or string of code.
Then create a init function in your module / viewModel:
this.init = function() { Do cool DOM stuff here. }
or depending on your viewModel structure:
viewModel: function(params) { return { init: function () { } }; },
Works like a charm. Example of it working is here
http://jsfiddle.net/gLcfxkv6/1/
Thread on knockout git here: https://github.com/knockout/knockout/issues/1533
Thanks to vamps on git for the workaround.
回答2:
The secret here is http://knockoutjs.com/documentation/custom-bindings.html
ko.bindingHandlers.myCustomBinding = { init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { // This will be called when the binding is first applied to an element // Set up any initial state, event handlers, etc. here if (bindingContext.$data.init) bindingContext.$data.init(element, valueAccessor, allBindings, viewModel, bindingContext); }, update: function(element, valueAccessor, allBindings, viewModel, bindingContext) { // This will be called once when the binding is first applied to an element, // and again whenever any observables/computeds that are accessed change // Update the DOM element based on the supplied values here. if (bindingContext.$data.update) bindingContext.$data.update(element, valueAccessor, allBindings, viewModel, bindingContext); } };
so in my component template I do something like
and on the component viewModel I just implement init and/or update, for example:
constructor.prototype.init = function(element, valueAccessor, allBindings, viewModel, bindingContext) { // All the buttons in the buttons group need the same name, // but they all need distinct ids. We use timestamps because // as components, the names and ids should be distinct across // multiple instances of each component. var timeStamp = new Date().getTime(); $('input:radio').attr('name', timeStamp).button(); $('input:radio:eq(0)').attr('id', timeStamp+1); $('input:radio:eq(1)').attr('id', timeStamp+2); $('input:radio:eq(2)').attr('id', timeStamp+3); // Initialize the number-picker $('input[name="number-picker"]').TouchSpin(); };
The Knockout documentation could be improved by pointing out this very useful case. Also, this is such a useful binding, there should be a standard bindings for 'init' and 'update', for example
回答3:
We needed to access DOM elements in a component after switching between different components. We would have liked to use the non-existing "afterRender" binding on components.
We solved it with a Javascript setTimeout, letting KO do its rendering first, and in effect queueing our code after that.
HTML:
The code switching the component:
var compName = ko.observable(); //... compName(switchToComponent); setTimeout(function(){ // this code is queued until after the component is rendered. }, 0);