Components

Components are UI modules that enable re-use within your application.

Components are the method used by the Framework to provide modular re-usable sections of UI. They make use of RequireJS to allow blocks of UI to either be lazily loaded when first needed, or be packaged into the initial JavaScript downloaded when the User-Agent starts the application.

Components act as singletons - the framework only allows one instance of a component to be onscreen at any one time, this means a component’s init(…) method will only be called once per session. If you wish to have multiple, but similar components on-screen simultaneously, you can subclass Components in the same manner as any other widget.

ComponentContainers are most often found at the top-level of an application, however they may be placed anywhere in the UI graph, including within other Components.

Note: You should NEVER load a component via the dependency list of a RequireJS module (other than when subclassing a Component), doing so will prevent the component from loading correctly. You should instead use the methods provided on the ComponentContainer widget (see Showing a Component).

Defining a Component

/**
* @fileOverview <DESCRIPTION>
*/require.def("<APPNAME>/appui/components/<COMPONENT>",["antie/widgets/component"],function(Component){/**
* <DESCRIPTION>
* @name <APPNAME>.appui.components.<COMPONENT>
* @class
* @extends antie.widgets.Component
* @requires ...
*/returnComponent.extend(/** @lends <APPNAME>.appui.components.<COMPONENT>.prototype */{init:functioninit(){varself=this;init.base.call(self,"<COMPONENTID>");// Add component lifecycle event listenersthis.addEventListener("load",function(ev){self._onLoad(ev);});this.addEventListener("beforerender",function(ev){self._onBeforeRender(ev);});this.addEventListener("beforeshow",function(ev){self._onBeforeShow(ev);});this.addEventListener("aftershow",function(ev){self._onAfterShow(ev);});this.addEventListener("beforehide",function(ev){self._onBeforeHide(ev);});this.addEventListener("afterhide",function(ev){self._onAfterHide(ev);});},_onLoad:function(ev){// Called when component is first loaded.},_onBeforeRender:function(ev){// Called before a component is rendered.// This is the best place to set data-specific content.},_onBeforeShow:function(ev){// Called after the component is rendered but before it is visible.},_onAfterShow:function(ev){// Called after the component is visible.},_onBeforeHide:function(ev){// Called before the component is hidden.},_onAfterHide:function(ev){// Called after the component is hidden.}});});

via the Application’s addComponentContainer shortcut, which adds a ComponentContainer to the root of the application:

varcontainer=application.addComponentContainer("topLeftContainer");

You then tell your ComponentContainer to load and show the hellocomponent:

container.show("helloworld/appui/components/hellocomponent");

The show method takes an optional second argument. This argument can be any arbitrary object and is passed as the “args” property of the beforerender, beforeshow and aftershow events on the loaded Container. This allows you to reuse your component, initialising the UI with different data depending on different arguments (see Using ComponentEvents).

An example would be to have a dialog component that has a different title and text:

container.show("helloworld/appui/components/dialogcomponent",{title:"Do you want to continue?",text:"Yes/OK"});container.show("helloworld/appui/components/dialogcomponent",{title:"Warning: Hull breach in progress",text:"Sound the alarm"});

The same can be achieved by using the object and using the show component shortcut:

Hiding a Component

To hide a Component you can call the hide() method on either the Component or the ComponentContainer which holds it, e.g.

container.hide();

Or within a Component’s code:

this.hide();

Note: After calling hide() the ComponentContainer will be empty. If you wish to return to the previous loaded Component, use the ComponentContainer history functionality.

Using ComponentContainer History

ComponentContainers have the ability to maintain a history stack of loaded Components along with the arguments passed to them when they were shown. To maintain history, instead of calling show(), call pushComponent() (with the same arguments), e.g.

Due to the singleton design of Components there is very little overhead in maintaining the history.

When you wish to return to the previous Component, call the back() method on the ComponentContainer:

container.back();

Maintaining State Within the History

You may find that you need to persist state information alongside the Component within the history, for example the currently focused Button, so that when you return to the Component, you can restore the Component to the same state as it was before it was pushed on to the history stack.

The framework calls a getCurrentState() method on the Component before pushing in on to the history stack. You should implement this method in your Component and return any data you wish to persist.

Using ComponentEvents

As mentioned above, using events (namely ComponentEvent) are critical for successful use of Components. As Components are singletons, events are the only way your component can be informed that it must update its content with new data, etc. each time it is shown.

The important events are:

load

This event is fired once, the first time a Component is loaded. At this point the Component will have been initialised but not placed into the UI graph, i.e. this event will not bubble.

beforerender

This event is fired each time a Component is shown. The Component will be in the UI graph (its parent being a ComponentContainer), but it will not yet have been rendered (via the render(…) method).

Note: If you wish to bind data to any widgets within a Component, beforerender is the correct place to do it. You should also update any Labels, Images, etc. with any content that varies based on the args property of this event.

beforeshow

This event is fired each time a Component is shown. The Component will be in the UI graph and will have been rendered (outputElement will not be null). However it will not be visible (e.g. DOM element will have visibility: hidden)

aftershow

This event is fired each time a Component is shown. This Component will be in the UI graph, will have been rendered, and will be visible to the user.

Note: Either beforeshow or aftershow are the recommended places for overlays/modal Components to capture focus.

beforehide

This event is fired each time a Component is hidden. The Component will be in the UI graph, will have been rendered, and will currently be visible to the user.

Note: You may call preventDefault() on this event to prevent the rendered output from being removed from the DOM. This is particularly useful if you wish to cross-fade, etc., however you MUST ensure the Component’s DOM element is removed before the Component is shown again.

afterhide

This event is fired each time a Component is hidden. The Component will be in the UI graph, but will have been remove from the output (unless preventDefault() was called in a beforehide listener).

Component Lifecycle

The following sequence diagram illustrates loading Component A (defined in Module A) into a ComponentContainer using the Application.showComponent(...) shortcut. The application then uses showComponent(...) again to show Component B within the same ComponentContainer. Later the application shows Component A again.

Note how ComponentContainer.showComponent(...) is asynchronous. If the module has not yet been loaded, it calls RequireJS which loads the module asynchronously. If the module has already been loaded, showComponent(...) begins the process of showing the component asynchronously and returns instantly.