Commit 756308d2 by Qiang Xue

Finished widget tutorial [skip ci]

parent f1a815a8
...@@ -193,8 +193,8 @@ Widgets ...@@ -193,8 +193,8 @@ Widgets
* Menu: link to demo page * Menu: link to demo page
* LinkPager: link to demo page * LinkPager: link to demo page
* LinkSorter: link to demo page * LinkSorter: link to demo page
* [Bootstrap Widgets](bootstrap-widgets.md) * [Bootstrap Widgets](widget-bootstrap.md)
* [Jquery UI Widgets](jui-widgets.md) * [Jquery UI Widgets](widget-jui.md)
Helpers Helpers
......
Widgets Widgets
======= =======
> Note: This section is under development. 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:
Widgets are self-contained building blocks for your views, a way to combine complex logic, display, and functionality into a single component. A widget: ```php
<?php
use yii\bootstrap\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 <a name="using-widgets"></a>
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 Russian language and keep the input in the `from_date` attribute of `$model`.
```php
<?php
use yii\bootstrap\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']); ?>
* May contain advanced PHP programming <?= $form->field($model, 'username') ?>
* Is typically configurable
* Is often provided data to be displayed
* Returns HTML to be shown within the context of the view
There are a good number of widgets bundled with Yii, such as [active form](form.md), <?= $form->field($model, 'password')->passwordInput() ?>
breadcrumbs, menu, and [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are
extensions that provide more widgets, such as the official widget for [jQueryUI](http://www.jqueryui.com) components.
In order to use a widget, your view file would do the following: <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.
## Creating Widgets <a name="creating-widgets"></a>
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 ```php
// Note that you have to "echo" the result to display it namespace app\components;
echo \yii\widgets\Menu::widget(['items' => $items]);
// Passing an array to initialize the object properties use yii\base\Widget;
$form = \yii\widgets\ActiveForm::begin([ use yii\helpers\Html;
'options' => ['class' => 'form-horizontal'],
'fieldConfig' => ['inputOptions' => ['class' => 'input-xlarge']], class HelloWidget extends Widget
]); {
... form inputs here ... public $message;
\yii\widgets\ActiveForm::end();
public function init()
{
parent::init();
if ($this->message === null) {
$this->message = 'Hello World';
}
}
public function run()
{
return Html::encode($this->message);
}
}
``` ```
In the first example in the code above, the [[yii\base\Widget::widget()|widget()]] method is used to invoke a widget To use this widget, simply insert the following code in a view:
that just outputs content. In the second example, [[yii\base\Widget::begin()|begin()]] and [[yii\base\Widget::end()|end()]]
are used for a ```php
widget that wraps content between method calls with its own output. In case of the form this output is the `<form>` tag <?php
with some properties set. 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 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 <a name="best-practices"></a>
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-asset-bundles.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 it within your application.
...@@ -20,7 +20,7 @@ use yii\helpers\Json; ...@@ -20,7 +20,7 @@ use yii\helpers\Json;
* echo DatePicker::widget([ * echo DatePicker::widget([
* 'language' => 'ru', * 'language' => 'ru',
* 'model' => $model, * 'model' => $model,
* 'attribute' => 'country', * 'attribute' => 'from_date',
* 'clientOptions' => [ * 'clientOptions' => [
* 'dateFormat' => 'yy-mm-dd', * 'dateFormat' => 'yy-mm-dd',
* ], * ],
...@@ -32,7 +32,7 @@ use yii\helpers\Json; ...@@ -32,7 +32,7 @@ use yii\helpers\Json;
* ```php * ```php
* echo DatePicker::widget([ * echo DatePicker::widget([
* 'language' => 'ru', * 'language' => 'ru',
* 'name' => 'country', * 'name' => 'from_date',
* 'clientOptions' => [ * 'clientOptions' => [
* 'dateFormat' => 'yy-mm-dd', * 'dateFormat' => 'yy-mm-dd',
* ], * ],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment