Write my own decorator

This tutorial will take you through the process of creating a new decorator to add to a grid, in order to extend its basic functionality.  Just as an example, what we’re going to do is create a decorator that will add or remove a CSS class to a row when it is clicked, prompting a background colour change. 

Contents:

Step 1: Adding the Decorator to the Grid Definition

We’ll start off by defining an alias for our new decorator. We will do this inside the resources folder at the bladeset level as we are defining an alias that didn't exist before. The decorator won’t work at this point, because it doesn’t exist yet, but it at least lets us know what we are aiming at:

<aliasDefinitions xmlns="http://schema.caplin.com/CaplinTrader/aliasDefinitions">

<alias  name="novox.myDecorator"
   defaultClass="novox.fxtrader.grid.decorator.MyDecorator">
</alias>

</aliasDefinitions>

Once we’ve got our newly defined alias, we need to add it to a grid.  Note that the alias is used as an XML element, and we’ve given it an attribute of its own: clickedClass.  That will contain the name of the CSS class that we will be adding or removing from the grid row.

<grid id="myGrid">
  <decorators>
	<novox.myDecorator clickedClass="<name of the class>" />
  </decorators>
</grid>

Having done that, we need to create our new decorator.

Step 2: Creating a Decorator Class

First of all, we need to create a decorator class, which will implement the caplin.grid.decorator.GridDecorator interface.  You can do this as follows:

caplin.implement(novox.fxtrader.grid.decorator.MyDecorator, caplin.grid.decorator.GridDecorator);

Note that the first argument in caplin.implement() matches the className attribute from the <decoratorMapping> tag in our grid definition.

Our class’s constructor will receive the decorator’s configuration as a parameter. We can use this to get any parameters from the XML configuration file; in this case, we need our decorator to get hold of the CSS class that we specified in the XML.

novox.fxtrader.grid.decorator.MyDecorator = function(mDecoratorConfig)
{
	this.clickedClass = mDecoratorConfig.clickedClass;
};

So now we have a new grid decorator, with the highly original name of "MyDecorator", and it has the name of the CSS class it will be using.  Now all we need is for it to actually do something.

Step 3: Registering the Decorator as a Listener

As the "something" that we want it to do, should happen when we click on a grid row, our next task is to make sure that the decorator knows when that has occurred. Caplin provides various "listeners" to do that job for us, all we have to do is subscribe to them; first by registering for events that occur on the grid container, and then to specifically listen for click events.

To register ourselves as listeners to the grid elements we are interested in, we use the implemented method setGridView(). Bear in mind that the grid would not have yet been rendered at this point. For full details of all the elements that you can register on, have a look at caplin.grid.decorator.GridDecorator in our Grid API reference section.  We want to listen to events on the grid container, so we’ll implement the caplin.grid.GridViewListener interface, as shown below:

caplin.implement(novox.fxtrader.grid.decorator.MyDecorator, caplin.grid.GridViewListener);
// GridDecorator Interface Methods

novox.fxtrader.grid.decorator.MyDecorator.prototype.setGridView = function(oGridView)
{
   // register the decorator as a listener	
   this.m_oGridView = oGridView;
   oGridView.addGridViewListener(this);
};

Step 4: Subscribing to Events

Having registered as a listener to grid view events (and you can see a complete list of what grid events you can listen for, at caplin.grid.GridViewListener in the Grid API reference section) we want to subscribe specifically to click events that occur on the grid container. Once the grid is rendered, we’ll register one of our methods as a handler for click events happening on the grid container:

// GridViewListener Interface Methods
novox.fxtrader.grid.decorator.MyDecorator.prototype.onContainerHtmlRendered = function()
{
   this.m_eRowContainer = this.m_oGridView.getRowContainerElement();
	
   // Subscribe to the click event happening on the row container
   // and handle it with our _onClick method

   this.m_nClickListenerId = caplin.dom.Utility.addEventListener(this.m_eRowContainer, "click", this._onClick.bind(this));
};

Refer to caplin.dom.Utility in the API reference, for further details.

Step 5: Handling Events

Now we’re subscribed to the grid container’s click events, we need to define how we’re going to handle them when they occur. We’ll implement our _onClick() handler, determine the row in which the click has taken place and check if it has the CSS class we defined. If it already does, we’ll remove it; otherwise we'll add it.

novox.fxtrader.grid.decorator.MyDecorator.prototype._onClick = function(oEvent)
{
   oEvent = caplin.dom.event.Event.getNormalizedEvent(oEvent);
   var eRow = caplin.dom.Utility.getAncestorElementWithClass(oEvent.target, "row");

   if(caplin.dom.Utility.hasClassName(eRow, this.clickClass)) {   
      caplin.dom.Utility.removeClassName(eRow, this.clickClass);
   } else {
      caplin.dom.Utility.addClassName(eRow, this.clickClass);
   }
};

Refer to caplin.dom.event.Event and caplin.dom.Utility in the API Reference for full details of the events and utilities used here.

Step 6: Housekeeping

That more or less completes the basic functionality, but before we put our feet up and have a well-earned cup of tea, there is one last thing to do: remove ourselves as event-listeners on the grid view after it’s been closed. There’s a specific method from the caplin.grid.GridViewListener interface that enables us to do so: the onClose() method, which is triggered when the view is closed.

novox.fxtrader.grid.decorator.MyDecorator.prototype.onClose = function()
{
   // Clean up
   caplin.dom.Utility.removeEventListenerById(this.m_nClickListenerId);
   this.m_eRowContainer = null;
};

And here is the result: The clicked rows now have a red background colour.