Widgets are self-contained blocks of functionality that solve different tasks. Widgets always have a user interface and a back-end controller (the widget class) that prepares the widget data and handles AJAX requests generated by the widget user interface.
Widgets are the back-end equivalent of front-end Components. They are similar because they are modular bundles of functionality, supply partials and are named using aliases. The key difference is that back-end widgets use YAML markup for their configuration and bind themselves to Backend pages.
Widget classes reside inside the widgets directory of the plugin directory. The directory name matches the name of the widget class written in lowercase. Widgets can supply assets and partials. An example widget directory structure looks like this:
widgets/
/form
/partials
form.htm <== Widget view file
/assets
/js
form.js <== Widget JavaScript file
/css
form.css <== Widget StyleSheet file
Form.php <== Widget class
The generic widget classes must extend the Backend\Classes\WidgetBase
class. As any other plugin class, generic widget controllers should belong to the plugin namespace. Example widget controller class definition:
namespace Backend\Widgets;
use Backend\Classes\WidgetBase;
class Lists extends WidgetBase
{
public $defaultAlias = 'list';
public function widgetDetails()
{
return [
'name' => 'List Widget',
'description' => 'Used for building back end lists.'
];
}
...
The widget class must contain a render() method for producing the widget markup by rendering a widget partial. Example:
public function render()
{
return $this->makePartial('list');
}
To pass variables to partials you can either add them to the $vars
class variable
public function render()
{
$this->vars['var'] = 'value';
return $this->makePartial('list');
}
Alternatively you pass the variables to the second parameter of the makePartial() method:
public function render()
{
$this->vars['var'] = $value;
return $this->makePartial('list', ['var'=>'value']);
}
Widgets implement the same AJAX approach as the back-end controllers. The AJAX handlers are public methods of the widget class with names starting with the on prefix. The only difference between the widget AJAX handlers and backend controller's AJAX handlers is that you should use the widget's getEventHandler()
in order to get the widget's handler name when you refer to it in the widget partials. Example:
<a
href="javascript:;"
data-request="<?= $this->getEventHandler('onPaginate') ?>"
title="Next page">Next</a>
A widget should be bound to a back-end controller before you can start using it in a back-end page or partial. Use the widget's bindToController()
method for binding it to a controller. The best place to initialize a widget is the controller's constructor. Example:
public function __construct()
{
parent::__construct();
$myWidget = new MyWidgetClass($this);
$myWidget->alias = 'myWidget';
$myWidget->bindToController();
}
After binding the widget you can access it in the controller's view or partial by its alias:
<?= $this->widget->myWidget->render() ?>
With form widgets you can add new control types to the back-end forms. They provide features that are common to supplying data for models. Form widgets must be registered in the Plugin registration file.
The form widget classes must extend the Backend\Classes\FormWidgetBase
class. As any other plugin class, generic widget controllers should belong to the plugin namespace. A registered widget can be used in the back-end form field definition file. Example form widget class definition:
namespace Backend\Widgets;
use Backend\Classes\FormWidgetBase;
class CodeEditor extends FormWidgetBase
{
public function widgetDetails()
{
return [
'name' => 'Code Editor',
'description' => 'Renders a code editor field.'
];
}
public function render() {}
}
Report widgets can be used on the back-end dashboard and in other back-end report containers. Report widgets must be registered in the Plugin registration file.
The report widget classes should extend the Backend\Classes\ReportWidgetBase
class. As any other plugin class, generic widget controllers should belong to the plugin namespace. The class should override the render()
method in order to render the widget itself. Similarly to all backend widgets, report widgets use partials and a special directory layout. Example directory layout:
plugins/
rainlab/ <=== Author name
googleanalytics/ <=== Plugin name
reportwidgets/ <=== Report widgets directory
trafficsources <=== Widget files directory
partials
_widget.htm
TrafficSources.php <=== Widget class file
Example report widget class definition:
namespace RainLab\GoogleAnalytics\ReportWidgets;
use Backend\Classes\ReportWidgetBase;
class TrafficSources extends ReportWidgetBase
{
public function render()
{
return $this->makePartial('widget');
}
}
The widget partial could contain any HTML markup you want to display in the widget. The markup should be wrapped into the DIV element with the report-widget class. Using H3 element to output the widget header is preferable. Example widget partial:
<div class="report-widget">
<h3>Traffic sources</h3>
<div
class="control-chart"
data-control="chart-pie"
data-size="200"
data-center-text="180">
<ul>
<li>Direct <span>1000</span></li>
<li>Social networks <span>800</span></li>
</ul>
</div>
</div>
Inside report widgets you can use any charts or indicators, lists or any other markup you wish. Remember that the report widgets extend the generic back-end widgets and you can use any widget functionality in your report widgets. The next example shows a list report widget markup.
<div class="report-widget">
<h3>Top pages</h3>
<div class="table-container">
<table class="table data" data-provides="rowlink">
<thead>
<tr>
<th><span>Page URL</span></th>
<th><span>Pageviews</span></th>
<th><span>% Pageviews</span></th>
</tr>
</thead>
<tbody>
<tr>
<td>/</td>
<td>90</td>
<td>
<div class="progress">
<div class="bar" style="90%"></div>
<a href="/">90%</a>
</div>
</td>
</tr>
<tr>
<td>/docs</td>
<td>10</td>
<td>
<div class="progress">
<div class="bar" style="10%"></div>
<a href="/docs">10%</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
Report widgets could have properties that users can manage with the Inspector:
The properties should be defined in the defineProperties()
method of the widget class. The properties are described in the components article. Example:
public function defineProperties()
{
return [
'title' => [
'title' => 'Widget title',
'default' => 'Top Pages',
'type' => 'string',
'validationPattern' => '^.+$',
'validationMessage' => 'The Widget Title is required.'
],
'days' => [
'title' => 'Number of days to display data for',
'default' => '7',
'type' => 'string',
'validationPattern' => '^[0-9]+$'
]
];
}