|
|
|
Widgets
|
|
|
|
=======
|
|
|
|
|
|
|
|
Widgets are reusable building blocks used in [views](structure-views.md) to create complex and configurable user
|
|
|
|
interface elements in an object-oriented fashion. For example, a date picker widget may generate a fancy date picker
|
|
|
|
that allows users to pick a date as their input. All you need to do is just to insert the code in a view
|
|
|
|
like the following:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use yii\jui\DatePicker;
|
|
|
|
?>
|
|
|
|
<?= DatePicker::widget(['name' => 'date']) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
There are a good number of widgets bundled with Yii, such as [[yii\widgets\ActiveForm|active form]],
|
|
|
|
[[yii\widgets\Menu|menu]], [jQuery UI widgets](widget-jui.md), [Twitter Bootstrap widgets](widget-bootstrap.md).
|
|
|
|
In the following, we will introduce the basic knowledge about widgets. Please refer to the class API documentation
|
|
|
|
if you want to learn about the usage of a particular widget.
|
|
|
|
|
|
|
|
|
|
|
|
## Using Widgets <span id="using-widgets"></span>
|
|
|
|
|
|
|
|
Widgets are primarily used in [views](structure-views.md). You can call the [[yii\base\Widget::widget()]] method
|
|
|
|
to use a widget in a view. The method takes a [configuration](concept-configurations.md) array for initializing
|
|
|
|
the widget and returns the rendering result of the widget. For example, the following code inserts a date picker
|
|
|
|
widget which is configured to use the Russian language and keep the input in the `from_date` attribute of `$model`.
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use yii\jui\DatePicker;
|
|
|
|
?>
|
|
|
|
<?= DatePicker::widget([
|
|
|
|
'model' => $model,
|
|
|
|
'attribute' => 'from_date',
|
|
|
|
'language' => 'ru',
|
|
|
|
'clientOptions' => [
|
|
|
|
'dateFormat' => 'yy-mm-dd',
|
|
|
|
],
|
|
|
|
]) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Some widgets can take a block of content which should be enclosed between the invocation of
|
|
|
|
[[yii\base\Widget::begin()]] and [[yii\base\Widget::end()]]. For example, the following code uses the
|
|
|
|
[[yii\widgets\ActiveForm]] widget to generate a login form. The widget will generate the opening and closing
|
|
|
|
`<form>` tags at the place where `begin()` and `end()` are called, respectively. Anything in between will be
|
|
|
|
rendered as is.
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use yii\widgets\ActiveForm;
|
|
|
|
use yii\helpers\Html;
|
|
|
|
?>
|
|
|
|
|
|
|
|
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
|
|
|
|
|
|
|
|
<?= $form->field($model, 'username') ?>
|
|
|
|
|
|
|
|
<?= $form->field($model, 'password')->passwordInput() ?>
|
|
|
|
|
|
|
|
<div class="form-group">
|
|
|
|
<?= Html::submitButton('Login') ?>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<?php ActiveForm::end(); ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that unlike [[yii\base\Widget::widget()]] which returns the rendering result of a widget, the method
|
|
|
|
[[yii\base\Widget::begin()]] returns an instance of the widget which you can use to build the widget content.
|
|
|
|
|
|
|
|
|
|
|
|
### Configuring global defaults
|
|
|
|
|
|
|
|
Global defaults for a widget type could be configured via DI container:
|
|
|
|
|
|
|
|
```php
|
|
|
|
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
|
|
|
|
```
|
|
|
|
|
|
|
|
See ["Practical Usage" section in Dependency Injection Container guide](concept-di-container.md#practical-usage) for
|
|
|
|
details.
|
|
|
|
|
|
|
|
|
|
|
|
## Creating Widgets <span id="creating-widgets"></span>
|
|
|
|
|
|
|
|
To create a widget, extend from [[yii\base\Widget]] and override the [[yii\base\Widget::init()]] and/or
|
|
|
|
[[yii\base\Widget::run()]] methods. Usually, the `init()` method should contain the code that normalizes the widget
|
|
|
|
properties, while the `run()` method should contain the code that generates the rendering result of the widget.
|
|
|
|
The rendering result may be directly "echoed" or returned as a string by `run()`.
|
|
|
|
|
|
|
|
In the following example, `HelloWidget` HTML-encodes and displays the content assigned to its `message` property.
|
|
|
|
If the property is not set, it will display "Hello World" by default.
|
|
|
|
|
|
|
|
```php
|
|
|
|
namespace app\components;
|
|
|
|
|
|
|
|
use yii\base\Widget;
|
|
|
|
use yii\helpers\Html;
|
|
|
|
|
|
|
|
class HelloWidget extends Widget
|
|
|
|
{
|
|
|
|
public $message;
|
|
|
|
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
parent::init();
|
|
|
|
if ($this->message === null) {
|
|
|
|
$this->message = 'Hello World';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
return Html::encode($this->message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
To use this widget, simply insert the following code in a view:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use app\components\HelloWidget;
|
|
|
|
?>
|
|
|
|
<?= HelloWidget::widget(['message' => 'Good morning']) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Below is a variant of `HelloWidget` which takes the content enclosed within the `begin()` and `end()` calls,
|
|
|
|
HTML-encodes it and then displays it.
|
|
|
|
|
|
|
|
```php
|
|
|
|
namespace app\components;
|
|
|
|
|
|
|
|
use yii\base\Widget;
|
|
|
|
use yii\helpers\Html;
|
|
|
|
|
|
|
|
class HelloWidget extends Widget
|
|
|
|
{
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
parent::init();
|
|
|
|
ob_start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
$content = ob_get_clean();
|
|
|
|
return Html::encode($content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
As you can see, PHP's output buffer is started in `init()` so that any output between the calls of `init()` and `run()`
|
|
|
|
can be captured, processed and returned in `run()`.
|
|
|
|
|
|
|
|
> Info: When you call [[yii\base\Widget::begin()]], a new instance of the widget will be created and the `init()` method
|
|
|
|
will be called at the end of the widget constructor. When you call [[yii\base\Widget::end()]], the `run()` method
|
|
|
|
will be called whose return result will be echoed by `end()`.
|
|
|
|
|
|
|
|
The following code shows how to use this new variant of `HelloWidget`:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use app\components\HelloWidget;
|
|
|
|
?>
|
|
|
|
<?php HelloWidget::begin(); ?>
|
|
|
|
|
|
|
|
content that may contain <tag>'s
|
|
|
|
|
|
|
|
<?php HelloWidget::end(); ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Sometimes, a widget may need to render a big chunk of content. While you can embed the content within the `run()`
|
|
|
|
method, a better approach is to put it in a [view](structure-views.md) and call [[yii\base\Widget::render()]] to
|
|
|
|
render it. For example,
|
|
|
|
|
|
|
|
```php
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
return $this->render('hello');
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
By default, views for a widget should be stored in files in the `WidgetPath/views` directory, where `WidgetPath`
|
|
|
|
stands for the directory containing the widget class file. Therefore, the above example will render the view file
|
|
|
|
`@app/components/views/hello.php`, assuming the widget class is located under `@app/components`. You may override
|
|
|
|
the [[yii\base\Widget::getViewPath()]] method to customize the directory containing the widget view files.
|
|
|
|
|
|
|
|
|
|
|
|
## Best Practices <span id="best-practices"></span>
|
|
|
|
|
|
|
|
Widgets are an object-oriented way of reusing view code.
|
|
|
|
|
|
|
|
When creating widgets, you should still follow the MVC pattern. In general, you should keep logic in widget
|
|
|
|
classes and keep presentation in [views](structure-views.md).
|
|
|
|
|
|
|
|
Widgets should be designed to be self-contained. That is, when using a widget, you should be able to just drop
|
|
|
|
it in a view without doing anything else. This could be tricky if a widget requires external resources, such as
|
|
|
|
CSS, JavaScript, images, etc. Fortunately, Yii provides the support for [asset bundles](structure-assets.md),
|
|
|
|
which can be utilized to solve the problem.
|
|
|
|
|
|
|
|
When a widget contains view code only, it is very similar to a [view](structure-views.md). In fact, in this case,
|
|
|
|
their only difference is that a widget is a redistributable class, while a view is just a plain PHP script
|
|
|
|
that you would prefer to keep within your application.
|