- Create a new file ${root}/Sample/component/graphicalFoobar.js
- Copy and paste this in the file:
Archetype.Component.Extend(["Archetype.component.graphicalComponent"], {
name:"Sample.components.graphicalFoobar",
/**
* Set up the Component dependencies
*/
setup:{
dependencies: {
components:{foobar: "Sample.components.foobar"},
lib:[],
css:[],
html:{main: "Sample.templates.graphicalFoobar"}
}
/*,template: "Archetype.template.ejsTemplate"*/
},
/**
* Start the Component itself
* @constructor
*/
initialize: function() {
this.date= new Date(0);
this.table= ["a","b","c","d","e"];
this.anchor = $(document.body);
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.date = date;
this.render(this.anchor);
Logger.debug("foobarGraphical received a date: " + date);
},
});
-
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 definition,
second will extend and override the first one, etc. and the hashmap definition will extend and override all of those 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.
his 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 automatically 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":
- Any method that has a name starting with "on" is an 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, and the mechanism to listen it is the same.
In the same way, multiple components can send a same event.
- The not shown but inherited from the graphicalComponent useful "renderViewAsString":
- After calling the graphicalComponent's method render, this method will be called. The method has to return the string of the rendered view.
- The inherited code is equivalent to "return this.templates.main.evaluate(this);". Like in the example of the foobar component in dependency, the template in dependency is set in "this.templates", and by default, renderViewAsString uses the "main" template.
- To evaluate a template, you have to use the method evaluate with a hashmap or object in parameter which list parameters used in the templates. The object can be simply "this", which is the case by default in renderViewAsString.
- Now, let's create our template: create a directory ${root}/Sample/templates
- Create a new file ${root}/Sample/templates/foobarGraphical.html
- Copy and paste this in the file:
<ul>
<% for(var i=0; i<table.length; i++) {%>
<% if((i%2)==0) {%>
<li><%=i%>, date time:<%= date.getHours() %>:<%= date.getMinutes() %>:<%= date.getSeconds() %>, table[<%= i%>] <%= table[i] %></li>
<% } %>
<% } %>
</ul>
<p>Click on the page to update the date</p>
- How this templates works:
- Archetype uses an abstraction in order to manage different kind of templates.
Any of them can be used by calling the "evaluate" method with a HashMap or an object of parameters. Note that this can be the component itself (this).
- Current bundled Template engines are:
- trimpathTemplate : has as Smarty like syntax, good performances,
you cannot do whatever you want in the view, but to keep in mind that the view is not the controller, this is quite a quality !
- TAL Template
(Archetype.template.talTemplate): The cleaner html template system ever! however performances aren't very fast in this implementation.
Please note that domtal implementation is using the original code,
not the one provided by the site we directly link, which has an incompatible licence, available only for education purpose.
However, the documentation is ok on the template format. Original code was not bundled with documentation, but you may find a lot
of documentation of TAL on some other implementation website, like
phptal
, or Zope
.
- EmbeddedJS
(Archetype.template.ejsTemplate) : Quite an efficient but not very clean
template system, used too by some other frameworks, it's a bit like coding a page in PHP or using JSP scriptlets. You can do almost whatever you want
in the view using this one, but it's dangerous as most of the code should be in the controller (the component itself)
- You can choose the default template engine by setting "Archetype.template = 'template.template.trimpathTemplate';" in archetype.conf.js or
in your Page controller ($(root)/Pages/Start.js))
- You can locally override the default system for a component by just uncommenting "/*,template: "Archetype.template.ejsTemplate"*/"
in the component setup, and setting the good template system.
- In this example, it used trimpathTemplate wich has a syntax very close tp the Smarty one.
Just refer to the documentation of the template engine in order to understand precisly the syntax.
-
Now let's update the starting of our application by instanciating our new component in our Page Controller :
//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 !");
}
};
- Simply refresh (you may need to use hard refresh by using Ctrl+F5) 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 broadcasted 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!