Google Closure Components
29 April 2014 by StefanIn google closure, understanding the goog.ui.Component
lifecycle
is a important part of understanding the library. The component provides a
interface to manage all the aspects of a given element.
Components are disposable
This means that it can and must be disposed of when you are done using it.
// create component;
var component = new my.Component();
// do things with component
component.render();
// when done with component:
component.dispose(); // destroys the component, all event listeners and other
// disposable objects attached to the component
The render and decorate methods
A component can be created in two ways.
- The element already exists and we just decorate the component’s behaviour onto it.
- The element does not exist and we tell the component to create it.
// the element exists in the document.
var buttonElement = goog.dom.getElementByClass(goog.getCssName('my-button-element'));
var button = new goog.ui.Button();
if(goog.dom.isElement(buttonElement)){
buttonElement.decorate();
}
// we ask the button to render its own element into the dom.
var button = new goog.ui.Button();
button.render();
The createDom and decorateInternal methods
/**
* @constructor
* @extends {goog.ui.Component}
*/
my.Component = function () {
goog.base(this);
};
goog.inherits(my.Component, goog.ui.Component);
/**
* Creates a element like this
* <div>
* <span>Title</span>
* </div>
* @override
*/
my.Component.prototype.createDom = function () {
var domHelper = this.getDomHelper();
var element = domHelper.createDom('div');
var titleElement = domHelper.createDom('span');
titleElement.innerHTML = "Title";
element.appendChild(titleElement);
this.setElementInternal(element);
};
/**
* @Override
*/
my.Component.prototype.decorateInternal = function (element) {
this.setElementInternal(element);
};
The enterDocument and exitDocument methods.
When a component enters the document, enterDocument is called and when it leaves exitDocument is called, this is where enable/disable any behaviour code.
Let us consider a example where you have a component with composes a button which it needs to decorate and listen to.
Warning: Don't forget the goog.base calls when overriding enter and exitDocument
/**
* @constructor
* @extends {goog.ui.Component}
*/
my.Component = function () {
goog.base(this);
/** @type {goog.ui.Button} */
this.button = new goog.ui.Button();
this.registerDisposable(this.button);
};
goog.inherits(my.Component, goog.ui.Component);
/**
* @override
*/
my.Component.prototype.enterDocument = function () {
goog.base(this, 'enterDocument');
/** @type {goog.events.EventHandler} */
this.lifecycle = new goog.events.EventHandler(this);
this.registerDisposable(this.lifecycle);
this.lifecycle.listen(this.button, goog.ui.Components.EventType.ACTION, this.onButtonAction);
/** @type {Element} */
var buttonElement = this.getElementByClass(goog.getCssName("my-button"));
if(goog.dom.isElement(buttonElement)){
this.button.decorate(buttonElement);
}
};
/**
* @override
*/
my.Component.prototype.exitDocument = function () {
this.button.exitDocument();
if(goog.isDefAndNotNull(this.lifecycle)) {
this.lifecycle.dispose();
}
goog.base(this, 'exitDocument');
};
/**
* @param {goog.events.Event} event
*/
my.Component.prototype.onButtonAction = function (event) {
alert("Button Clicked");
};
A complete example component.
/**
* @constructor
* @extends {goog.ui.Component}
*/
my.Component = function () {
goog.base(this);
/** @type {goog.ui.Button} */
this.button = new goog.ui.Button();
this.registerDisposable(this.button);
};
goog.inherits(my.Component, goog.ui.Component);
/**
* Creates a element like this
* <div>
* <span>Title</span>
* </div>
* @override
*/
my.Component.prototype.createDom = function () {
var domHelper = this.getDomHelper();
var element = domHelper.createDom('div');
var titleElement = domHelper.createDom('span');
titleElement.innerHTML = "Title";
element.appendChild(titleElement);
this.setElementInternal(element);
};
/**
* @Override
*/
my.Component.prototype.decorateInternal = function (element) {
this.setElementInternal(element);
};
/**
* @override
*/
my.Component.prototype.enterDocument = function () {
goog.base(this, 'enterDocument');
/** @type {goog.events.EventHandler} */
this.lifecycle = new goog.events.EventHandler(this);
this.registerDisposable(this.lifecycle);
this.lifecycle.listen(this.button, goog.ui.Components.EventType.ACTION, this.onButtonAction);
/** @type {Element} */
var buttonElement = this.getElementByClass(goog.getCssName("my-button"));
if(goog.dom.isElement(buttonElement)){
this.button.decorate(buttonElement);
}
};
/**
* @override
*/
my.Component.prototype.exitDocument = function () {
this.button.exitDocument();
if(goog.isDefAndNotNull(this.lifecycle)) {
this.lifecycle.dispose();
}
goog.base(this, 'exitDocument');
};
/**
* @param {goog.events.Event} event
*/
my.Component.prototype.onButtonAction = function (event) {
alert("Button Clicked");
};