knockout / tko

🥊 Technical Knockout – The Monorepo for Knockout.js (4.0+)
http://www.tko.io
Other
275 stars 34 forks source link

template binding's afterRender handler does not get invoked on DOM render #30

Closed vikashpisces closed 7 years ago

vikashpisces commented 7 years ago

I am trying out TKO 4.0 in ES6 semantics with transpilation done using Babel.

When I use template binding and pass a class method to afterRender, the method does get invoked but the reference of this becomes window Object. However, if the same class method is added to click binding, method gets invoked and there this reference points out to class or the viewmodel.

Not sure if this is an issue with TKO 4.0 or ES6 compilations. If someone can help me on this with a sample working example of afterRender using ES6 and TKO 4.0 would be of great help at this time. As we have planned for migration from KO to TKO for good performance reason.

I am attaching my tried code zipped below:

Thanks is advance.

side-bar.zip

krnlde commented 7 years ago

You could try either the autobind feature from core-decorators or instead use an arrow function to preserve the this context

brianmhunt commented 7 years ago

@vikashpisces It would help to see a jsFiddle.

vikashpisces commented 7 years ago

@brianmhunt I have a jsFiddle created which illustrates the problem.

In the jsFiddle, you can see error in console when afterRender callback of template binding is being invoked on DOM render. The same works with click binding (button element is commented out in the jsfiddle provided). It will be nice of you if you can provide a solution for this with a brief description on what is going wrong in my code.

Thanks in advance.

brianmhunt commented 7 years ago

@vikashpisces The first issue is that you're using Knockout 3.4 in the jsFiddle.

You can use the TKO library (i.e. KO4 alpha) here: https://unpkg.com/tko@4.0.0-alpha2/dist/ko.js

This version works: https://jsfiddle.net/bmh_ca/q0hh2vta/3/

Let me know if there's an issue .

(Sorry for short comment -- got to run!)

brianmhunt commented 7 years ago

Just to complete my prior comment - You need to use $data.afterRender in order to get the bound version of afterRender. This is because the afterRender function might be found on $data, $context, the globals or an alias (e.g. foreach ... as:).

If there is anything we do to improve this, please share and we can re-open.

vikashpisces commented 7 years ago

@brianmhunt Thanks a lot for the quick help on this. Binding renderhandler to $data or using fat arrow worked for me.

One thing I would like to highlight that $data was always default current context. Whether to mention it or not, binding's current context was $data. I am not sure what has changed in that context. It could be the ES6 compiler which is causing this issue.

If any support from KO provided on this part can help people who are migrating to ES6. Otherwise every places default context need to be mentioned explicitly.

Thanks @brianmhunt & @krnlde for your time.

brianmhunt commented 7 years ago

This issue did occur in 3.4, as you can see from the first fiddle ... but I really don't know the rationale... @mbest - any idea why afterRender is being passed null as this, instead of $data?

mbest commented 7 years ago

I think the rationale is that afterRender (and afterAdd, etc.) are meant for UI manipulation mostly and so aren't especially meant to manipulate the model.

brianmhunt commented 7 years ago

Got it thanks @mbest.

I think with ES6 classes being used as view models the expectation has probably changed. (As per this issue)

There's no technical reason we can't do this, is there?