-
Notifications
You must be signed in to change notification settings - Fork 3
Page Manager
Page Manager is an essential part of IMA.js. It's something like a puppeteer that manipulates with pages and views. Once a router matches URL to one of route's path the page manager takes care of the rest.
If the new matched route has onlyUpdate
option set to true
and the controller and view hasn't changed the route transition is dispatched only through update
method of the controller.
In every other case the manager goes through it's full process:
To make room for the new, manager has to get rid of the old controller and extensions. First calls deactivate
method on every extension registered in the old controller and then the same method on the controller itself.
Same process follows with destroy
method.
After unloading controller and extensions the page state is cleared and view (starting from ManagedRootView) is unmounted. However if the DocumentView, ViewAdapter and ManagedRootView are the same for the new route the view is cleared rather then unmounted. This way you can achieve component persistency.
After the manager is done with clearing previous resource it initialises the new ones. First the init
method is called on controller then on every extension (Extensions may be initialised during the controllers init
method call).
When the initialisation is complete manager starts loading resources via load
method of the controller and extensions. For detailed explanation see the load
method documentation.
After the load
method has been called a view for the controller is rendered. It doesn't matter if all promises returned by the load
method have been resolved. The process of handling promises is described in the load
method documentation. Following rendering process is described on a page Rendering process and View & Components.
It's possible for you to intervene into the process before it starts and after it finished. One way is to listen to BEFORE_HANDLE_ROUTE
and AFTER_HANDLE_ROUTE
dispatcher events. However from inside event listeners you cannot intercept or modify the process. For this purpose we've introduced PageManagerHandlers in v16
PageManagerHandler is a simple class that extends ima/page/handler/PageHandler
. It can obtain dependencies through dependency injection. Each handler should contain 4 methods:
For purpose of initialising.
This method is called before the page manager start taking any action. It receives 3 arguments managedPage
, nextManagedPage
and action
. managedPage
holds information about current page, nextManagedPage
about following page. Each of the "managed page" arguments has following shape:
{{
controller: ?(string|function(new: Controller)), // controller class
controllerInstance: ?Controller, // instantiated controller
decoratedController: ?Controller, // controller decorator created from controller instance
view: ?React.Component, // view class/component
viewInstance: ?React.Element, // instantiated view
route: ?Route, // matched route that leads to the controller
options: ?RouteOptions, // route options
params: ?Object<string, string>, // route parameters and their values
state: {
activated: boolean // if the page has been activated
}
}}
and finally the action
is an object describing what triggered the routing. If a PopStateEvent
triggered the routing the action object will look like this: { type: 'popstate', event: PopStateEvent }
otherwise the event
property will contain MouseEvent
(e.g. clicked on a link) and type
property will have value 'redirect'
, 'click'
or 'error'
.
This method is a counterpart to handlePreManagedState()
method. It's called after page transition is finished. It receives similar arguments (managedPage
, previousManagedPage
and action
). previousManagedPage
holds information about previous page.
Note:
handlePreManagedState()
andhandlePostManagedState()
methods can interrupt transition process by throwing an error. The thrown error should be instance ofGenericError
with a status code specified. That way the router can handle thrown error accordingly.
For purpose of destructing
PageManagerHandlers have their own registry PageHandlerRegistry. Every handler you create should be registered as a dependency of this registry.
// app/config/bind.js
import PageHandlerRegistry from 'ima/page/handler/PageHandlerRegistry';
import Window from 'ima/window/Window';
import MyOwnHandler from 'app/handler/MyOwnHandler';
export let init = (ns, oc, config) => {
// ...
if (oc.get(Window).isClient()) { // register different handlers for client and server
oc.inject(PageHandlerRegistry, [MyOwnHandler]);
} else {
oc.inject(PageHandlerRegistry, []);
}
};
Note: Handlers are executed in series and each one waits for the previous one to complete its task.
With introduction of PageManagerHandlers in v16 we've moved some functionality to predefined handler PageNavigationHandler. This handler takes care of saving scroll position, restoring scroll position and settings browser's address bar URL. You're free to extend it, override it or whatever else you want.
PageNavigationHandler is registered by default, but when you register your own handlers you need to specify PageNavigationHandler as well.
import PageHandlerRegistry from 'ima/page/handler/PageHandlerRegistry';
import PageNavigationHandler from 'ima/page/handler/PageNavigationHandler';
import MyOwnHandler from 'app/handler/MyOwnHandler';
export let init = (ns, oc, config) => {
// ...
oc.inject(PageHandlerRegistry, [PageNavigationHandler, MyOwnHandler]);
};
- Introduction
- Static view
- Adding some state
- Fetching the data from the server
- Writing posts
- Final polish