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.

- 23,641
- 15
- 110
- 157

- 1,958
- 2
- 21
- 30
-
please provide source, maybe in a JSFiddle – Michael Crook Oct 07 '14 at 20:37
-
Looking at the source, it doesn't look like it does. It doesn't use the template engine to render the components, it just merely applies the component model to the component template. – Jeff Mercado Oct 07 '14 at 21:46
-
OK, I am not surprised, components are pretty new, as I had to upgrade to the latest release of Knockout to get them to work. I looks like I may have to understand how createViewModel(params, componentInfo) works. – Eric Kolotyluk Oct 09 '14 at 04:32
-
Sorry, didn't mean to downvote, don't know how that happened... – JakeJ Aug 28 '19 at 14:52
5 Answers
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.
<span data-bind="template: { afterRender: init }"></span>
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.

- 9,241
- 8
- 31
- 46
-
Thanks... This works for now... looks like Knockout will add this as a feature in v3.3 – Paul T. Jan 02 '15 at 21:26
-
3Just be careful nested components dont call afterRender as expected. – Piotr Stulinski Jan 09 '15 at 14:36
-
Thanks... in my use case, I only wanted run a process after the top-most component was done. – Paul T. Jan 09 '15 at 19:32
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
<div class="row-fluid" data-bind="myCustomBinding: 'someValue'">
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
<div data-bind="init: 'someValue'">

- 1,958
- 2
- 21
- 30
-
Hi, i tried to use this but i was not able to get it working. I can see the code executing but it simply doesnt affect the dom elements... so i cannot get for example a telephone number picker to execute :( – Piotr Stulinski Nov 02 '14 at 17:23
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:
<div data-bind="component: compName"></div>
The code switching the component:
var compName = ko.observable();
//...
compName(switchToComponent);
setTimeout(function(){
// this code is queued until after the component is rendered.
}, 0);

- 13,543
- 2
- 56
- 59
As of knockout 3.5.1, you can add a koDescendantsComplete
function to your viewModel
and that will be triggered after the rendering is complete
var viewModel = {
koDescendantsComplete: element => {
console.log( 'Rendered!', element );
}
}

- 979
- 10
- 21
-
This is (as of 3.5.1) by far the most suitable solution for components. As a bonus, the dom node the component is bound to is passed as a first argument. Allowing for convenient listener registration, etc. – Eelke van den Bos Jun 04 '21 at 01:02
Make a new binding, like so
ko.bindingHandlers.initBinding = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
debugger
if (valueAccessor() && valueAccessor().afterRender && bindingContext.$data) {
valueAccessor().afterRender(bindingContext.$data);
}
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
}
};
export default ko.bindingHandlers.initBinding
You don't need the export if you're not using ES6(babel etc).
Then in your component html, you can do something like this
<div class="staff-directory" data-bind="initBinding: {afterRender: afterRender }">
<p>Loaded</p>
</div>
And in your component model
class staffDirectory {
constructor() {
console.log('staff directory loaded');
}
afterRender() {
console.log('afterRender called');
}
}
export default staffDirectory;

- 5,178
- 32
- 42