|
ApplicationComponents
Application Components describe externalized content and modules, ideal for encapsulating reusable code as abstract extensions to content.
IntroductionApplication Components describe externalized content and modules, ideal for encapsulating reusable code and creating dynamic user interface widgets. Components can be created with no binding, or be bound to HTML nodes or XHTML Components. Application Components are similar to Modules in that they provide a collection point for customized code. Unlike custom script written for the Module Service, Application Component script is structured and automatically instruments several Hemi services. APIHistoryApplication Components debuted many years and versions ago in Demonstration #7 for Engine for Web Applications version 0.8. In the original Engine for Web Applications architecture, engine configurations were used to load external content through declarative constructors. Over time, those features were separated between Application Spaces and Templates through Application Components. While Application Spaces continue to support external content, the Application Component Template feature is the recommended method for mashing-up content fragments. Templates debuted in Demonstration #16 (note: regression in the mousemove handler) for Engine for Web Applications version 1.1 FeaturesApplication Components features include:
External Component DefinitionApplication Components may import component definitions from an external XML format. Component SyntaxThe following syntax includes the default descriptors and callbacks of an external component definition.
<application-components>
<application-component id = "componentId" participant-id = "participantId">
<![CDATA[
component_init : function(){
},
component_post_init : function(){
},
component_destroy : function(){
}
]]>
</application-component>
</application-components>Component APIThe Application Component API includes a number of helpful methods:
Components are also automatically configured with other Framework-provided APIs, including:
Container EventsWhen a component is bound to an HTML Node or XHTML Component, declaring an event handler causes a listener to be created for that handler. <![CDATA[
_handle_click : function(e){
var oContainer = this.getContainer();
var evt = Hemi.event.getEvent(e);
var oSrc = Hemi.event.getEventSource(evt);
}
]]>TransactionsApplication Components receive the injected Transaction API from the Transaction Service addServiceAPI method. The injected API includes special handling for serveTransaction and doTransaction. Therefore, instead of developers having to write against the Transaction API from components, they only need to know one method: this.serveTransaction. <![CDATA[
component_init : function(e){
/// Serve packet to like instances
this.serveTransaction("available");
/// Serve packet to unlike instances
this.serveTransaction("alsoavailable",this,1,"otherComponents");
},
_handle_available : function(oService, oPacket){
/// Notification from other components serving the "available" statement for this particular transaction participant list.
/// oPacket.data.src is defined by the injected serveTransaction API
/// BUT - this object doesn't receive it's own callback
}
]]>In the previous example, if the component id is myComponent, then every instance of myComponent except the invoker would be served the packet for the myComponent transaction. In the second call, the packet for "otherComponents" would be served to all participants. If those components define doTransaction, or handle_alsoavailable, those components would receive notification. Using ComponentsApplication Components can be loaded several ways. Headless ComponentsComponents that have no UI and need not be bound to an HTML node, such as the component.manager.xml component, may be loaded via script. Depending on how the component is to be referenced, it may be desirable to include the Application Space binding. Using the convenience method provided by the createApplicationComponent method, or the bindComponent from the Application Component API: /// Preferred/Easiest
var oComponent1 = Hemi.app.createApplicationComponent("manager", 0, Hemi.app.space.service.getPrimarySpace(), "manager");
/// OR
var oComponent2 = Hemi.app.comp.bindComponent(0, "manager", "Templates/component.manager.xml",0,1);The primary drawback of using the createApplicationComponent convenience method is it directs the component loading to be synchronous so that the returned object is completely loaded. Conversely, the bindComponent method may or may not be synchronous. Another difference in the previous example is that without including an XHTML component that had been bound to an Application Space, this component is outside the context of a Space. Without using the createApplicationComponent method, the other option is a direct implementation where the Application Space is configured: var sId = "manager"; var sPath = Hemi.hemi_base + "Components/component." + sId + ".xml"; var oSpace = Hemi.app.space.service.getPrimarySpace(); var oComponent = Hemi.app.comp.newInstance(sId, 0, oSpace.getObjectId()); oComponent.setAsync(false); oComponent.loadComponent(sPath, sId); Bound ComponentsBound components have the immediate benefit of being able to quickly define event handlers and having easy access to the container (ie: the HTML Node). Given some component, my-component, saved in Hemi/Components/component.my-component.xml: <application-components>
<application-component id = "my-component">
<![CDATA[
_handle_click : function(){
Hemi.xml.setInnerXHTML(this.getContainer(), "Clicked!");
}
]]>
</application-component>
</application-components>The easiest way to bind a component to a node is to use a Quick Fix via the XHTML Component and Application Spaces. <p component = "my-component"></p> If the component definition resides in a directory other than Components/, the acid and appcomp_path attributes may be used: <p acid = "my-component" appcomp_path = "/SomeDir/my-component.xml"></p> Otherwise, components may be bound via script, such as: <p id = "oPara">Para</p>
<script type = "text/javascript">
var oComponent = Hemi.app.comp.bindComponent(document.getElementById("oPara"), "my-component", "Templates/component.my-component.xml",0,1);
</script>Or, if using the createApplicationComponent method, an XHTML Component is automatically created for the DOM node. <p rid = "oPara">Para</p>
<script type = "text/javascript">
var oComponent = Hemi.app.createApplicationComponent("my-component", document.getElementById("oPara"));
</script>To load a component via reference id: <p rid = "oPara">Para</p> <script type = "text/javascript"> var oSpace = Hemi.app.space.service.getPrimarySpace(); var oSpaceObject = oSpace.getSpaceObjectByName(n) var oXhtmlObject = oSpaceObject.object.getContainer(); var oComponent = Hemi.app.comp.bindComponent(oXhtmlObject, "my-component", "Templates/component.my-component.xml", 0, 1); </script> Application Component Object ModelApplication Components and SpacesIn the following example, a DIV element is assigned an application component (using the XHTMLComponent's Quick Fix feature). (Note: If the component does not exist in the hemi_base/Components/ directory with the explicit format of component.name.xml, the acid/appcomp_path configuration must be used instead. <div rid = "some_div" component = "example">Some Div</div> <application-components>
<application-component id = "example"><![CDATA[
_handle_click : function(){
Hemi.xml.setInnerXHTML(this.getContainer(), "Clicked!");
}
]]></application-component>
</<application-components>Therefore, the topology includes the Application Component. <script type = "text/javascript">
Hemi.message.service.subscribe("onspaceconfigload", function (sName, oSpace) {
if (!oSpace.is_primary) return;
// Get the SpaceObject which indexes "some_div" to the Framework object.
var oObjectRef = oSpace.getSpaceObjectByName("some_div");
// Get the Framework object representing the DIV
var oXHTMLComponent = oObjectRef.object;
// Get the Application Component
var oApplicationComponent = oXHTMLComponent.getApplicationComponent();
// Retrieve the DIV node.
var oDiv = oXHTMLComponent.getContainer();
});
</script>Provided ComponentsThe Hemi JavaScript Framework includes several components, most notably:
Templates and FragmentsRefer to the Templates Introduction. |