TemplatedWidget Class
Such problems can be avoided by using HTML templates. For example, lets add the following template into the HTML page:
<div id="~_MyToolbar">
</div>
<table id="~_MyTable">
<thead><tr><th>Name</th><th>Surname</th>...</tr></thead>
<tbody>...</tbody>
</table>
</script>
Here, a SCRIPT
tag is used, but by specifying its type as "text/html"
, browser won’t recognize it as a real scriptto execute.
By making use of TemplatedWidget, lets rewrite previous spaghetti code block:
public class MyComplexWidget : TemplatedWidget
{
public MyComplexWidget(jQueryObject div)
: base(div)
{
}
When this widget is created on an HTML element like following:
<div id="SampleElement">
</div>
You’ll end up with such an HTML markup:
TemplatedWidget automatically locates the template for your class and applies it to the HTML element.
If you watch carefully, in our template we specified ID for descendant elements as ~_MyToolbar
and ~_MyTable
.
But when this template is applied to the HTML element, resulting markup contained ID’s of MySamples_MyComplexWidget1_MyToolbar and MySamples_MyComplexWidget1_MyTable
instead.
Using this strategy, even if the same widget template is used in a page for more than one HTML element, their ID’s won’t conflict with each other as they will have unique ID’s.
As TemplateWidget appends a unique name to them, the ID attributes in a widget template can’t be used to access elements after widget creation.
Widget’s unique name and an underscore should be prepended to the original ID attribute in the template to find an element:
public class MyComplexWidget : TemplatedWidget
public MyComplexWidget(jQueryObject div)
: base(div)
{
J(this.uniqueName + "_" + "Toolbar").AddClass("some-class");
}
}
TemplatedWidget’s ByID method can be used instead:
public class MyComplexWidget
{
public MyComplexWidget(jQueryObject div)
: base(div)
{
ByID("Toolbar").AddClass("some-class");
}
}
In the last sample MyComplexWidget
located its template automatically.
TemplatedWidget makes use of a convention to find its template (convention based programming). It inserts Template_
prefix before the class name and searches for a SCRIPT
element with this ID attribute (Template_MyComplexWidget
) and uses its HTML content as a template.
If we wanted to use another ID like following:
<script id="TheMyComplexWidgetTemplate" type="text/html">
</script>
An error like this would be seen in the browser console:
public class MyComplexWidget
{
protected override string GetTemplateName()
{
}
}
GetTemplate
method might be overriden to provide a template from another source or specify it manually:
public class MyCompleWidget
{
protected override string GetTemplate()
{
return $('#TheMyComplexWidgetTemplate').GetHtml();
}
}
Default implementation for TemplatedWidget.GetTemplate
method calls GetTemplateName
and searches for a SCRIPT
element with that ID.
If no such SCRIPT element is found, Q.GetTemplate
is called with the same ID.
An error is thrown if neither returns a result.
Q.GetTemplate
method provides access to templates defined on the server side. These templates are compiled from files with .template.cshtml
extension in ~/Views/Template
or ~/Modules
folders or their subfolders.
For example, we could create a template for MyComplexWidget in a server side file like ~/Views/Template/SomeFolder/MyComplexWidget.template.cshtml
with the following content:
<div id="~_MyToolbar">
</div>
<table id="~_MyTable">
<thead><tr><th>Name</th><th>Surname</th>...</tr></thead>
</table>
Template file name and extension is important while its folder is simply ignored.
By using this strategy there would be no need to insert widget templates into the page markup.