Your first graphical component

  1. Create a new file ${root}/src/main/webapp/Sample/component/graphicalFoobar.js
  2. Copy and paste this in the file:
    Archetype.Component.Extend(["Archetype.component.graphicalComponent"], {
    	name:"Sample.component.graphicalFoobar",
    	/**
    	 * Set up the Component dependencies
    	 */
    	setup:{
    		dependencies: {
    			components:{foobar: "Sample.components.foobar"},
    			lib:[],
    			css:[],
    			html:{main: "Sample.templates.foobarComponent"}
    		}
    	},
    	/**
    	 * Start the Component itself
    	 * @constructor
    	 */
    	initialize: function() {
    		this.options = {
    			max: 5,
    			date: new Date(0),
    			table: ["a","b","c","d","e"]
    		}
    		this.anchor = $("bodyContent");
    		
    		Logger.debug("foobarGraphical has been instanciated!");
    		
                    new this.components.foobar();
    		Logger.debug("foobar launched from foobarComponent!");
    		
    		this.render(this.anchor);
                    Logger.debug("foobarGraphical rendered!");		
    	},
    	/**
    	 * Listen to "DateUpdate" event
    	 */
    	onDateUpdate: function(eventName, date) {
    		this.options.date = date;
    		this.render(this.anchor);
                    Logger.debug("foobarGraphical received a date: " + date);
    	},
    	/**
    	 * Render the Component view and return it
    	 */
    	renderViewAsString: function() {
    		return this.templates.main.evaluate(this.options);
    	}
    });
                        
  3. Now let's explain what it does:
    • "Archetype.Component.Extend" (it's aliased as "$C.Extend" if you're lazy) builds your component by extension of another. The graphicalComponent is an abstract component wich is delivered with Archetype. It add some dedicated functionnalities for a component which is associated to a view. There is two parameters : the list of "super component" (they can be more than one) and the HashMap containing the component's definition. The definition of the parent(s) component(s) will be added to the new component, and the extension will be applied one after the other in the component order in the Array (first will be the original array, second will extend and override the first, etc. and the hashmap definition will extend and override all of thos parent components).
    • "name" no changes here: property must be defined in order to reference your component. It's usually the same as the file path in a java manner.
    • "setup" provides the configuration of the component. This time, dependencies are not empty. We have two dependencies, one on the first component we have previously created. It allows this component to have a reference to it's constructor and allows him to be sure to have this component loaded. The second is the template for rendering our "graphical" component. Both of the dependencies are defined with HashMaps. The key of each entry will be useful in order to refer to these dependencies, which "name" (think of it as the name of the component, not the name of the file, even if it's usually the same) is defined as an HashMap string value.
    • "initialize": as with Prototype's classes, this method is launched as the object constructor. This time, the method contains two very typical operations :
      • new this.component.foobar(): In the dependencies setup, we have configured a component with the entry: "foobar: 'Sample.components.foobar'". With this configuration, Archetype will automaticaly set this.component.foobar with the constructor of the foobar component. So, this line is the simplest way to create an instance of component in dependency.
      • this.render(this.anchor): render is an inherited method from the graphicalComponent. It will follow several steps in order to add the component view in the page. The function parameter is the DOM element where we want to insert our view. Behind the render method, renderViewAsString method will be called as we will see next.
    • "onDateUpdate":
      • All methods with a name starting with "on" are event listeners (another methodBuilder magic). They will be called automatically when an event with the corresponding name is fired.
      • It takes as parameters the eventName and the eventData (which is any kind of object). Here, we use the eventData to transport the date we want to show.
      • We see in this example that the event is not sent by this component but another, the mechanism to listen it is the same. In the same way, not only the a single component (here foobar) can send a same event.
    • "renderViewAsString":
      • After calling the graphicalComponent's method render, this method will be called.
      • The method has to return the string of the rendered view.
      • Like in the example of the foobar component in dependency, the template in dependency is set in "this.templates".
      • To evaluate a template, you have to use the method evaluate with a HashMap in parameter wich list parameters used in the templates.
  4. Now, let's create our template: create a directory ${root}/src/main/webapp/Sample/templates
  5. Create a new file ${root}/src/main/webapp/Sample/templates/foobarGraphical.html
  6. Copy and paste this in the file:
    {for i=0; i< max; i++}
    	<hr>
    	{if (i%2)==0}
    		<p>i=${i}, date time:${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}, table[${i}]={table[i]}!</p>
    	{/if}
    {/for}
    <p>Click on the page to update the date</p>
                        
  7. How this templates works:
    • Archetype use an abstraction in order to manage different kind of templates. Any of them can be used by calling the "evaluate" method with a HashMap of parameters. Note that this Hashmap can be the component itself.
    • Template engines are for the moment: regexpTemplate, trimpathTemplate , talTemplate. regexpTemplate was the first implementation but it is quite deprecated now for questions of bugs and performances
    • You can choose the default template engine by setting "Archetype.template = 'template.trimpathTemplate';"
    • In this example, it used trimpathTemplate wich has a syntax very close of the Smarty syntax. Just refer to the documentation of the template engine in order to understand precisly the syntax.
  8. Now let's update the starting of our application by instanciating our new component:
    //Static namespace for your application
    Sample = {
    	/**
    	 * Sample.main is launched when Archetype is available for page Sample.html
    	 */
    	main: function()
    	{
    	//--Do your application specific configuration here, e.g.:
    	//Archetype.useLogger("log.firebugLogger");
    	// or
    	//Sample.conf = {foo:"bar",bar:"foo"};
    	//--
    
    	// you will put your application BootStrap here
    	/**
    	 * This will require the component asynchronously then instanciate one by default
    	 */
    	Archetype.requireComponent("Sample.component.foobarGraphical");
    	Logger.log("hello, world !");
    	}
    };
                        
  9. Simply refresh your test page in your browser to see this in action!

    And don't forget to open your Logger to see the debug informations to see that every components listen to the brodcasted events and that all listeners are called right after the event firing.

    To see the date being updated, don't forget to click on the page text!