The raptor-widgets module provides a simple and efficient mechanism for binding behavior to UI components rendered on either the server or in the browser. This module also supports inter-widget communication and provides a simple framework that encourages best practices and makes it easy to "wire up" complex applications. Out of the box, bindings are provided for Raptor Templates and Dust. There is no complex widget class hierarchy or complex API and you are free to use jQuery or any other library for working with the DOM.

Using the bindings for Raptor Templates, you can bind a widget to a rendered DOM element using the custom w-bind attribute as shown in the following sample template:

<divclass="my-component"w-bind="./widget">

<h1>Click Me</h1>

</div>

The widget bound to the <div> should then be implemented as a CommonJS module that exports a constructor function. During client-side initialization, a new instance of your widget will be created for each rendered DOM element that the widget is bound to. A sample widget implementation is shown in the following JavaScript code:

src/pages/index/widget.js:

functionWidget(config){

var rootEl =this.el;// this.el returns the root element that the widget is bound to

var self =this;

rootEl.addEventListener('click',function(){

self.addText('You clicked on the root element!');

});

}

Widget.prototype={

addText: function(text){

this.el.appendChild(document.createTextNode(text));

}

};

module.exports = Widget;

In order for everything to work on the client-side we need to include the code for the raptor-widgets module and the ./widget.js module as part of the client bundle and we also need to use the custom <w-init-widgets> tag to let the client know which widgets rendered on the server need to be initialized on the client. To include the client-side dependencies will be using the raptor-optimizer module and the taglib that it provides. Our final page template is shown below:

src/pages/index/template.rhtml:

<optimizer-pagename="index"package-path="./optimizer.json" />

<!doctype html>

<htmllang="en">

<head>

<metacharset="UTF-8">

<title>Widgets Demo</title>

<optimizer-head/>

</head>

<body>

<!-- Bind a widget to a div element using the "w-bind" attribute -->

<divclass="my-component"w-bind="./widget">

<h1>Click Me</h1>

</div>

<optimizer-body/>

<w-init-widgets/>

</body>

</html>

The optimizer.json that includes the required client-side code is shown below:

src/pages/index/optimizer.json:

{

"dependencies":[

"require raptor-widgets",

"require ./widget"

]

}

In the above example, the final HTML will be similar to the following:

The raptor-widgets taglib also provides support for allowing a widget to communicate directly with nested widgets. A nested widget can be assigned a widget ID (only needs to be unique within the scope of the containing widget) and the containing widget can then reference the nested widget by the assigned widget ID using the this.widgets collection.

The following HTML template fragment contains a widget that has three nested sample-button widgets. Each nested sample-button is assigned an ID (i.e. primaryButton, successButton and dangerButton).

<divclass="my-component"w-bind="./widget">

<divclass="btn-group">

<sample-buttonlabel="Click Me"variant="primary"w-id="primaryButton"/>

<sample-buttonlabel="Click Me"variant="success"w-id="successButton"/>

<sample-buttonlabel="Click Me"variant="danger"w-id="dangerButton"/>

</div>

...

</div>

The containing widget can then refer to a particular nested widget as shown in the following sample JavaScript code:

this.widgets.dangerButton.on('click',function(){

alert('You clicked on the danger button!');

});

:arrow_forward: To try out and experiment with this code please see the documentation and source code for the widgets-communication sample app.

DOM elements nested within a widget can be given unique IDs based on the containing widget's ID. These DOM elements can then be efficiently looked up by the containing widget using methods provided. The w-el-id custom attribute can be used to assign DOM element IDs to HTML elements that are prefixed with the widget's ID. For example, given the following HTML template fragment:

<formw-bind="./widget">

...

<buttontype="submit"w-el-id="submitButton">Submit</button>

<buttontype="button"w-el-id="cancelButton">Cancel</button>

</form>

Assuming the unique ID assigned to the widget is w123, the following would be the HTML output:

<formid="w123">

...

<buttontype="submit"id="w123-submitButton">Submit</button>

<buttontype="button"id="w123-cancelButton">Cancel</button>

</form>

Finally, to reference a widget's nested DOM element's the following code can be used in the containing widget:

This is a convenience method for accessing a widget's DOM elements when jQuery is available. This mixin method serves as a proxy to jQuery to ease building queries based on widget element IDs.

Internally, this jQuery proxy method will resolve widget element IDs to their actual DOM element ID by prefixing widget element IDs with the widget ID. For example, where this is a widget with an ID of w123:

this.$() ➡ $("#w123")

this.$("#myEl") ➡ $("#w123-myEl")

The usage of this mixin method is described below:

$()

Convenience usage to access the root widget DOM element wrapped as a jQuery object. All of the following are equivalent:

this.$()

$(this.el)

$("#"+this.id)

$('#<widget-el-id>')

Convenience usage to access a nested widget DOM element wrapped as a jQuery object. All of the following are equivalent:

this.$("#myEl)

$(this.getEl("myEl"))

$("#" + this.getElId("myEl"))

$('<selector>')

Convenience usage to query nested DOM elements scoped to the root widget DOM element. All of the following are equivalent:

this.$("ul > li")

$("ul > li",this.el)

$("#"+this.id+" ul > li")

$('<selector>', '<widget-el-id>')

Convenience usage to query nested DOM elements scoped to a nested widget DOM element. All of the following are equivalent:

this.$("li.color","colorsUL")

this.$("#colorsUL li.color")

$("li.color",this.getEl("colorsUL"))

$("#"+this.getElId("colorsUL")+" li.color")

$('#<widget-el-id> <selector>')

Convenience usage to query nested DOM elements scoped to a nested widget DOM element. All of the following are equivalent:

this.$("#colorsUL li.color")

this.$("li.color","colorsUL")

$("li.color",this.getEl("colorsUL"))

$("#"+this.getElId("colorsUL")+" li.color")

$(callbackFunction)

Convenience usage to add a listener for the "on DOM ready" event and have the this object for the provided callback function be the current widget instance. All of the following are equivalent:

Destroys the widget by unsubscribing from all listeners made using the subscribeTo method and then detaching the widget's root element from the DOM. All nested widgets (discovered by querying the DOM) are also destroyed.

Returns a nested DOM element by prefixing the provided widgetElId with the widget's ID. For Raptor Templates, nested DOM elements should be assigned an ID using the w-el-id custom attribute. Returns this.el if no widgetElId is provided.