Breaking Down a YUI3 Widget
YUI3 has these great things called widgets. For you jQuery guys, a widget is sorta like a plugin. Widget driven development is nice because it allows you to modularize your code, based on certain element of your site. You might for instance have a search results widget or an advanced search widget. Today I’m going to break down a YUI3 widget into it’s basic components and hopefully show you that they aren’t really that scary and actually make developing more fun. Why, because they allow you to build organized complex applications in JavaScript and I shouldn’t have to tell you why that’s awesome!
Lets start out with the the absolute minimum code you need to create a widget.
YUI.add("mywidget", function(Y) {
/* Any frequently used shortcuts, strings and constants */
var Lang = Y.Lang;
/* MyWidget class constructor */
function MyWidget(config) {
MyWidget.superclass.constructor.apply(this, arguments);
}
/*
* Required NAME static field, to identify the Widget class and
* used as an event prefix, to generate class names etc. (set to the
* class name in camel case).
*/
MyWidget.NAME = "myWidget";
/*
* The attribute configuration for the widget. This defines the core user facing state of the widget
*/
MyWidget.ATTRS = {
};
/* MyWidget extends the base Widget class */
Y.extend(MyWidget, Y.Widget, {
initializer: function() {
/*
* initializer is part of the lifecycle introduced by
* the Base class. It is invoked during construction,
* and can be used to setup instance specific state or publish events which
* require special configuration (if they don't need custom configuration,
* events are published lazily only if there are subscribers).
*
* It does not need to invoke the superclass initializer.
* init() will call initializer() for all classes in the hierarchy.
*/
},
destructor : function() {
/*
* destructor is part of the lifecycle introduced by
* the Widget class. It is invoked during destruction,
* and can be used to cleanup instance specific state.
*
* Anything under the boundingBox will be cleaned up by the Widget base class
* We only need to clean up nodes/events attached outside of the bounding Box
*
* It does not need to invoke the superclass destructor.
* destroy() will call initializer() for all classes in the hierarchy.
*/
},
renderUI : function() {
/*
* renderUI is part of the lifecycle introduced by the
* Widget class. Widget's renderer method invokes:
*
* renderUI()
* bindUI()
* syncUI()
*
* renderUI is intended to be used by the Widget subclass
* to create or insert new elements into the DOM.
*/
},
bindUI : function() {
/*
* bindUI is intended to be used by the Widget subclass
* to bind any event listeners which will drive the Widget UI.
*
* It will generally bind event listeners for attribute change
* events, to update the state of the rendered UI in response
* to attribute value changes, and also attach any DOM events,
* to activate the UI.
*/
},
syncUI : function() {
/*
* syncUI is intended to be used by the Widget subclass to
* update the UI to reflect the initial state of the widget,
* after renderUI. From there, the event listeners we bound above
* will take over.
*/
}
});
Y.namespace("MyApp").MyWidget = MyWidget;
}, "3.1.0", {requires:["widget", "substitute"]});
Alright, lets dive in …
One thing that’s confusing when you are first starting out with widgets is what name refers to what. So, we have `MyWidget`, `myWidget`, and `mywidget` in the code above. `mywidget` is the name that you will use when loading the widget with the YUI3 loader. `MyWidget` is the class object. `myWidget` is a camelCased version of your class name, which can be used a prefix for events, ie: `Y.on(‘myWidget:doSomething’, this._doSomething)`.
Now that we have the naming conventions out of the way lets break our widget down by section or blocks of code.
First we call the super class constructure with `MyWidget.superclass.constructor.apply(this, arguments)`.
Next we need to give our widget a name with `MyWidget.NAME`. As I said before, this is used to prefix custom events, which is another topic in itself.
If you want your widgets to have any attribute, which are generally used to set an initial state when your widget is rendered, you define them in ‘MyWidget.ATTRS’. For you jQuery people, this is like your plugin’s options.
Now we get to the good stuff. Our `MyWidget` class extends Widget and Widget extends Base. With this line `Y.extend(MyWidget, Y.Widget, {` we are inheriting from Widget, which inherits from Base.
Our class has initialize and destructor methods, which it inherits from Base. Initialize is called when you create your widget with the new keyword. Our class also has renderUI, bindUI and syncUI methods. These methods get called when you render your widget with `.render();`. It’s these three methods that make a YUI3 widget so great. They force you to organize your code in a thought out manner. `renderUi` is where you put any code that needs to interact with the dom, `bindUi` is where you put all of your event listeners, and in ‘syncUi` you put and code that allows your to update the state of your application. Also, it should be noted that `syncUi` is the only one of these three methods you will possibly ever be called more than once.
At the bottom we add our widget to the Y namespace and list our what modules are required for widget to function properly.
Now that we’ve talked about the basics lets add some very simple functionality to our widget, just so you can get started and then you’ll be able to add more to it on your own.
YUI.add("mywidget", function(Y) {
/* MyWidget class constructor */
function MyWidget(config) {
MyWidget.superclass.constructor.apply(this, arguments);
}
MyWidget.NAME = "myWidget";
/*
* The attribute configuration for the widget. This defines the core user facing state of the widget
*/
MyWidget.ATTRS = {
color : {
value: "#FF0000"
}
};
/* MyWidget extends the base Widget class */
Y.extend(MyWidget, Y.Widget, {
initializer: function() {
//set our attribute color to this.color for easier access
this.color = this.get('color');
},
destructor : function() { },
renderUI : function() {
//set the color of a nodes text to the attribute 'color'
Y.one('#a_node').setStyle('color', this.color);
},
bindUI : function() {
//add some event listeners
Y.one('#my_link1').on('click', this._myMethod1);
Y.one('#my_link2').on('click', this._myMethod1, this);
},
syncUI : function() { },
// Beyond this point is the MyWidget specific application and rendering logic
_myMethod1(e) {
e.preventDefault();
//this refers to the node that was clicked
Y.log( this.get('href') );
},
_myMethod2(e) {
e.preventDefault();
//this refers to your MyWidget class
Y.log(this);
this._myMethod3();
},
_myMethod3() {
Y.log('made it to method 3!');
}
});
Y.namespace("MyApp").MyWidget = MyWidget;
}, "3.1.0", {requires:["widget", "substitute"]});
I stripped out a lot of the comments to save some space. First things first, we define an attribute `color` and give it a default hexadecimal value of bright red. Any time you want access to an attribute you use `this.get(‘my_attribute’)`, which I think is a lot of code, so in the initializer method with set our color attribute to `this.color`. The next thing we do is use that attribute to set the CSS color of a node in `renderUI`. Remember, `renderUI` is where we put any code that interacts with the dom.
Next we add a couple of event listeners in `bindUI`. We set our listeners up to listen for a click even and call a method upon that click happening. Notice that we are passing `this` with the second listener. By default, `this` is going to refer to the click event and not our class, so if we plan on calling any other methods then we need to explicitly pass `this` with our event.
We are not using `syncUi` in this example, so we can skip that method. After `syncUi` we define any custom methods we need for our widget. All private methods should be prefixed with an underscore, like `_myMethod`. Public methods don’t need the underscore. So, we define three custom methods, two of which get called when the user clicks on the nodes we defined with our event listeners in `bindUi`, and the third gets explicitly called.
That’s it for our simple example, but I encourage you to add onto what we’ve covered here and build something neat / useful that you can share with the community.
For more information about YUI3 widget, check out the official docs. To get started on your own widget, take advantage of this widget skeleton that will save you a lot of time with any boilerplate code.



Create A Simple PHP Contact Form
When form is submitted I get a blank page with character...
Create A Simple PHP Contact Form
I am trying to CAPTCHA to the validation page but am...
Create A Simple PHP Contact Form
I use a simpler form of this until now that looks...