How is one supposed to properly dispose of a widget in v2.0? From what I have read this is supposedly done automagically when removed from the DOM, but removing my widget from the DOM using say jQuery.remove() doesn't cause canDeactivate() or deactivate() to be called. Is there a specific way it has to be removed from the DOM for the deactivation callbacks to be called?
Yes, in fact there is, and it's kind of easy to miss because it isn't documented very well.
Knockout has a utility function ko.utils.domNodeDisposal.addDisposeCallback(element, callback)
. This function makes sure the callback is invoked when the element is disposed of. However, 'disposed of' is very specific in this case. jQuery.remove()
won't trigger it. The way to dispose of the node is to use ko.removeNode(element)
, which not only removes the DOM element (and its children), but also does some extra cleanup in terms of bound event handlers and such. (I'm sorry, the details are a bit hazy. You can always check Knockout's implementation if you want more detail on this.)
Internally, when disposing of a view, Durandal uses ko.removeNode
. Therefore, when a view is removed, all elements are removed as well and any disposeCallbacks set up using the aforementioned utility function will be invoked. I'm fairly sure that Durandal hooks into this process to trigger the callback for deactivate.
TL;DR: try ko.removeNode(element)
instead of jQuery.remove(element)
. That will trigger your deactivate callback.