Let's build a widget, that increases a DIV's font size everytime it is clicked:
namespace MySamples
{
public class MyCoolWidget : Widget
{
private int fontSize = 10;
public MyCoolWidget(jQueryObject div)
: base(div)
{
div.Click(e => {
fontSize++;
this.Element.Css("font-size", fontSize + "pt");
});
}
}
}
<div id="SomeDiv">Sample Text</div>
We can create this widget on an HTML element, like:
var div = jQuery.Select("#SomeDiv");
new MyCoolWidget(div);
public abstract class Widget : ScriptContext
{
private static int NextWidgetNumber = 0;
protected Widget(jQueryObject element);
public virtual void Destroy();
protected virtual void OnInit();
protected virtual void AddCssClass();
public jQueryObject Element { get; }
public string WidgetName { get; }
public string UniqueName { get; }
}
Classes derived from Widget can get the element, on which they are created, by the Element
property.
public jQueryObject Element { get; }
This property has type of jQueryObject and returns the element, which is used when the widget is created. In our sample, container DIV element is referenced as this.Element
in the click handler.
When a widget is created on an HTML element, it does some modifications to the element.
First, the HTML element gets a CSS class, based on the type of the widget.
In our sample, .s-MyCoolWidget
class is added to the DIV
with ID #SomeDiv
.
Thus, after widget creation, the DIV looks similar to this:
<div id="SomeDiv" class="s-MyCoolWidget">Sample Text</div>
This CSS class is generated by putting a s-
prefix in front of the widget class name (it can be changed by overriding Widget.AddCssClass method).
Widget CSS class can be used to style the HTML element that the widget is created on.
.s-MyCoolWidget {
background-color: red;
}
Along with adding a CSS class, another information about the widget is added to the HTML element, though it is not obvious on markup. This information can be seen by typing following in Chrome console:
> $('#SomeDiv').data()
> Object { MySamples_MyCoolWidget: $MySamples_MyCoolWidget }
Thus, it is possible to get a reference to a widget that is attached to an HTML element, using $.data
function. In C# this can be written as:
var myWidget = (MyCoolWidget)(J("#SomeDiv").GetDataValue('MySamples_MyCoolWidget'));
Instead of the prior line that looks a bit long and complex, a Serenity shortcut can be used:
var myWidget = J("#SomeDiv").GetWidget<MyCoolWidget>();
This piece of code returns the widget if it exists on HTML element, otherwise throws an exception:
Element has no widget of type 'MySamples_MyCoolWidget'!
TryGetWidget can be used to check if the widget exists, simply returning null
if it doesn't:
var myWidget = $('#SomeDiv').TryGetWidget<MyCoolWidget>();
Only one widget of the same class can be attached to an HTML element.
An attempt to create a secondary widget of the same class on a element throws the following error:
The element already has widget 'MySamples_MyCoolWidget'.
Any number of widgets from different classes can be attached to a single element as long as their behaviour doesn't affect each other.
Every widget instance gets a unique name like MySamples_MyCoolWidget3
automatically, which can be accessed by this.UniqueName
property.
This unique name is useful as a ID prefix for the HTML element and its descendant elements which may be generated by the widget itself.
It can also be used as an event class for $.bind
and `$.unbind' methods to attach / detach event handlers without affecting other handlers, which might be attached to the element:
jQuery("body").Bind("click." + this.UniqueName, delegate { ... });
...
jQUery("body").Unbind("click." + this.UniqueName);
Sometimes releasing an attached widget might be required without removing the HTML element itself.
Widget class provides Destroy
method for the purpose.
In default implementation of the Destroy method, event handlers which are assigned by the widget itself are cleaned (by using UniqueName event class) and its CSS class (.s-WidgetClass
) is removed from the HTML element.
Custom widget classes might need to override Destroy method to undo changes on HTML element and release resources (though, no need to detach handlers that are attached previously with UniqueName class)
Destroy method is called automatically when the HTML element is detached from the DOM. It can also be called manually.
If destory operation is not performed correctly, memory leaks may occur in some browsers.