Hooking Lifecycle Callbacks
Key Points
- The view locator, view model binder, composition engine and activator all look for callbacks related to their individual functions.
- Composition involves the view locator, the view model binder and it's own DOM manipulation.
- Activator callbacks are not executed unless an
activatoris present oractivate:trueis set on the compose binding.
There are various services which play a role in the construction of a screen or of part of a screen. Each of these services looks for callbacks on your objects that pertain to its own unique functionality. Below is a list of the services which may be involved and an explanation of the available callbacks in each context.
View Locator Callbacks
When the composition engine (or you) calls viewLocator.locateViewForObject() it goes through a process of attempting to find the correct view for that object. Usually, this is accomplished through convention. But, there is a hook which your object can implement to manually return a view. To do so, add a function called getView() to your object. This function can either return a view id, used by the infrastructure to lookup the view, or it can return a DOMElement, allowing your object to manually construct it's view for absolute control.
View Model Binder Callbacks
Once a view is obtained, the composition engine will attempt to bind it to the associated object. To do this, it uses the view model binder, which looks for two possible hooks on your object. It calls beforeBind() just before the databinding happens. After databinding is complete, it calls afterBind(). In both cases it passes the view as an argument.
Composition Callbacks
After databinding is complete, the composition module then does its part to compose the bound view into the DOM. It may or may not use a transition as part of this process. Either way, once the view is attached to its parent's DOM node, it will check your object for a viewAttached() callback. This will be called with the view as its argument.
Activator Callbacks
The hooks described above are checked and run as part of every call to compose whether through the API or the binding handler. There are another set of hooks cenetered less around the view composition aspects of Durandal and more around screen and component lifecycles. These hooks are only checked/run when an activator is present. When is an activator present?
- The Router has an internal activator called "activeItem" which manages the current page.
- You can create an activator yourself at any time by requiring the view model module and calling it's activator function. This returns a computed observable that serves as the activator for your objects.
- When you call
app.setRootan activator is used on your root module. - If you set
activate:trueon a compose binding, an activator will be used during composition.
Cases 3 and 4 are a bit different as they only enforce canActivate and activate callbacks; not the deactivation lifecycle. To enable that, you must use a full activator yourself (cases 1 or 2). :::
Activator Lifecycle
- canDeactivate - Before a new screen (or component) is activated, the activator checks its current value.
If this value has a
canDeactivate()hook, then it is called. If this returns false, activation stops. - canActivate - Assuming canDeactivate returned true (or isn't present), the new value will be checked for a
canActivate()hook. If present, it will be called. If it returns false, activation stops here. - deactivate - If the previous value can deactivate and the new value can activate, then will call the previous value's
deactivate()function, if present. - activate - Assuming everything has gone well up to this point: if the new value has an
activate()function, we call that and the process finishes until a new activation begins.
You can read much more about this in the view model module's docs. Remember that all these hooks can return promises and all of them are optional
Full Lifecycle
Below is a table which shows the order of callbacks and their sources, assuming all necessary components are involved.
| Executes on Compose | Callback Name | Durandal Source Module | Purpose |
|---|---|---|---|
| Always | getView() | Enables the new object to return a custom view. | |
| When presence of activator | canDeactivate() | Allows the previous object to cancel deactivation. | |
| When presence of activator | canActivate() | Allows the new object to cancel activation. | |
| When presence of activator | deactivate() | Allows the previous object to execute custom deactivation logic. | |
| When presence of activator | activate() | Allows the new object to execute custom activation logic. | |
| Always | beforeBind() | Notifies the new object immediately before databinding occurs. | |
| Always | afterBind() | Notifies the new object immediately after databinding occurs. | |
| Always | viewAttached() | Notifies the new object when its view is attached to its parent DOM node. |