Skip to content

Latest commit

 

History

History
426 lines (286 loc) · 14.9 KB

helper-html.md

File metadata and controls

426 lines (286 loc) · 14.9 KB

Html helper

Every web application generates lots of HTML markup. If markup is static, it could be done efficiently by mixing PHP and HTML in a single file but when it is generated dynamically it is starting to get tricky to handle it without extra help. Yii provides such help in a form of Html helper which provides a set of static methods for handling commonly used HTML tags, their options and content.

Note: If your markup is nearly static it's better to use HTML directly. There's no need to wrap absolutely everything with Html helper calls.

Basics

Since building dynamic HTML by string concatenation is getting messy very fast, Yii provides a set of methods to manipulate tag options and build tags based on these options.

Generating Tags

The code generating a tag looks like the following:

<?= Html::tag('p', Html::encode($user->name), ['class' => 'username']) ?>

The first argument is tag name. Second one is content to be enclosed between the start and end tags. Note that we are using Html::encode. That's because content isn't encoded automatically to allow using HTML when needed. Third one is an array of HTML options or, in other words, tag attributes. In this array key is the name of the attribute such as class, href or target and a value is its value.

The code above will generate the following HTML:

<p class="username">samdark</p>

In case you need just start tag or just closing tag you can use Html::beginTag() and Html::endTag() methods.

Options are used in many methods of Html helper and various widgets. In all these cases there is some extra handling to know about:

  • If a value is null, the corresponding attribute will not be rendered.

  • Attributes whose values are of boolean type will be treated as boolean attributes.

  • The values of attributes will be HTML-encoded using [[yii\helpers\Html::encode()|Html::encode()]].

  • If the value of an attribute is an array, it will be handled as follows:

    • If the attribute is a data attribute as listed in [[yii\helpers\Html::$dataAttributes]], such as data or ng, a list of attributes will be rendered, one for each element in the value array. For example, 'data' => ['id' => 1, 'name' => 'yii'] generates data-id="1" data-name="yii"; and 'data' => ['params' => ['id' => 1, 'name' => 'yii'], 'status' => 'ok'] generates data-params='{"id":1,"name":"yii"}' data-status="ok". Note that in the latter example, JSON format is used to render a sub-array.
    • If the attribute is NOT a data attribute, the value will be JSON-encoded. For example, ['params' => ['id' => 1, 'name' => 'yii'] generates params='{"id":1,"name":"yii"}'.

Forming CSS Classes and Styles

When building options for HTML tag we're often starting with defaults which we need to modify. In order to add or remove CSS class you can use the following:

$options = ['class' => 'btn btn-default'];

if ($type === 'success') {
    Html::removeCssClass($options, 'btn-default');
    Html::addCssClass($options, 'btn-success');
}

echo Html::tag('div', 'Pwede na', $options);

// in case of $type of 'success' it will render
// <div class="btn btn-success">Pwede na</div>

You may specify multiple CSS classes using the array style as well:

$options = ['class' => ['btn', 'btn-default']];

echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'

While adding or removing classes you may use the array format as well:

$options = ['class' => 'btn'];

if ($type === 'success') {
    Html::addCssClass($options, ['btn-success', 'btn-lg']);
}

echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-success btn-lg">Save</div>'

Html::addCssClass() prevents duplicating classes, so you don't need to worry that the same class may appear twice:

$options = ['class' => 'btn btn-default'];

Html::addCssClass($options, 'btn-default'); // class 'btn-default' is already present

echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'

If the CSS class option is specified via the array format, you may use a named key to mark the logical purpose of the class. In this case, a class with the same key in the array format will be ignored in Html::addCssClass():

$options = [
    'class' => [
        'btn',
        'theme' => 'btn-default',
    ]
];

Html::addCssClass($options, ['theme' => 'btn-success']); // 'theme' key is already taken

echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'

CSS styles can be setup in similar way using style attribute:

$options = ['style' => ['width' => '100px', 'height' => '100px']];

// gives style="width: 100px; height: 200px; position: absolute;"
Html::addCssStyle($options, 'height: 200px; position: absolute;');

// gives style="position: absolute;"
Html::removeCssStyle($options, ['width', 'height']);

When using [[yii\helpers\Html::addCssStyle()|addCssStyle()]] you can specify either an array of key-value pairs corresponding to CSS property names and values or a string such as width: 100px; height: 200px;. These formats could be converted there and forth by using [[yii\helpers\Html::cssStyleFromArray()|cssStyleFromArray()]] and [[yii\helpers\Html::cssStyleToArray()|cssStyleToArray()]]. The [[yii\helpers\Html::removeCssStyle()|removeCssStyle()]] method accepts an array of properties to remove. If it's going to be a single property it could be specified as string.

Encoding and Decoding Content

In order for content to be displayed properly and securely in HTML special characters in the content should be encoded. In PHP it's done with htmlspecialchars and htmlspecialchars_decode. The issue with using these methods directly is that you have to specify encoding and extra flags all the time. Since flags are the same all the time and encoding should match the one of the application in order to prevent security issues, Yii provides two compact and simple to use methods:

$userName = Html::encode($user->name);
echo $userName;

$decodedUserName = Html::decode($userName);

Forms

Dealing with forms markup is quite repetitive and error prone. Because of that there is a group of methods to help dealing with them.

Note: consider using [[yii\widgets\ActiveForm|ActiveForm]] in case you deal with models and need validation.

Creating Forms

Form could be opened with [[yii\helpers\Html::beginForm()|beginForm()]] method like the following:

<?= Html::beginForm(['order/update', 'id' => $id], 'post', ['enctype' => 'multipart/form-data']) ?>

First argument is the URL form will be submitted to. It could be specified in form of Yii route and parameters accepted by [[yii\helpers\Url::to()|Url::to()]]. Second one is method to use. post is default. Third one is array of options for the form tag. In this case we're changing the way of encoding form data in POST request to multipart/form-data. It is required in order to upload files.

Closing form tag is simple:

<?= Html::endForm() ?>

Buttons

In order to generate buttons you can use the following code:

<?= Html::button('Press me!', ['class' => 'teaser']) ?>
<?= Html::submitButton('Submit', ['class' => 'submit']) ?>
<?= Html::resetButton('Reset', ['class' => 'reset']) ?>

First argument for all three methods is button title and the second one is options. Title isn't encoded so if you're getting data from end user, encode it with [[yii\helpers\Html::encode()|Html::encode()]].

Input Fields

There are two groups on input methods. The ones starting with active and called active inputs and the ones not starting with it. Active inputs are taking data from model and attribute specified while in case of regular input data is specified directly.

The most generic methods are:

type, input name, input value, options
<?= Html::input('text', 'username', $user->name, ['class' => $username]) ?>

type, model, model attribute name, options
<?= Html::activeInput('text', $user, 'name', ['class' => $username]) ?>

If you know input type in advance it's more convenient to use shortcut methods:

  • [[yii\helpers\Html::buttonInput()]]
  • [[yii\helpers\Html::submitInput()]]
  • [[yii\helpers\Html::resetInput()]]
  • [[yii\helpers\Html::textInput()]], [[yii\helpers\Html::activeTextInput()]]
  • [[yii\helpers\Html::hiddenInput()]], [[yii\helpers\Html::activeHiddenInput()]]
  • [[yii\helpers\Html::passwordInput()]] / [[yii\helpers\Html::activePasswordInput()]]
  • [[yii\helpers\Html::fileInput()]], [[yii\helpers\Html::activeFileInput()]]
  • [[yii\helpers\Html::textarea()]], [[yii\helpers\Html::activeTextarea()]]

Radios and checkboxes are a bit different in terms of method signature:

<?= Html::radio('agree', true, ['label' => 'I agree']);
<?= Html::activeRadio($model, 'agree', ['class' => 'agreement'])

<?= Html::checkbox('agree', true, ['label' => 'I agree']);
<?= Html::activeCheckbox($model, 'agree', ['class' => 'agreement'])

Dropdown list and list box could be rendered like the following:

<?= Html::dropDownList('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeDropDownList($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>

<?= Html::listBox('list', $currentUserId, ArrayHelper::map($userModels, 'id', 'name')) ?>
<?= Html::activeListBox($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>

First argument is the name of the input, second is the value that's currently selected and third is key-value pairs where array key is list value and array value is list label.

If you want multiple choices to be selectable, checkbox list is a good match:

<?= Html::checkboxList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeCheckboxList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>

If not, use radio list:

<?= Html::radioList('roles', [16, 42], ArrayHelper::map($roleModels, 'id', 'name')) ?>
<?= Html::activeRadioList($user, 'role', ArrayHelper::map($roleModels, 'id', 'name')) ?>

Labels and Errors

Same as inputs there are two methods for generating form labels. Active that's taking data from the model and non-active that accepts data directly:

<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
<?= Html::activeLabel($user, 'username', ['class' => 'label username'])

In order to display form errors from a model or models as a summary you could use:

<?= Html::errorSummary($posts, ['class' => 'errors']) ?>

To display individual error:

<?= Html::error($post, 'title', ['class' => 'error']) ?>

Input Names and Values

There are methods to get names, ids and values for input fields based on the model. These are mainly used internally but could be handy sometimes:

// Post[title]
echo Html::getInputName($post, 'title');

// post-title
echo Html::getInputId($post, 'title');

// my first post
echo Html::getAttributeValue($post, 'title');

// $post->authors[0]
echo Html::getAttributeValue($post, '[0]authors[0]');

In the above first argument is the model while the second one is attribute expression. In its simplest form it's attribute name but it could be an attribute name prefixed and/or suffixed with array indexes which are mainly used for tabular input:

  • [0]content is used in tabular data input to represent the "content" attribute for the first model in tabular input;
  • dates[0] represents the first array element of the "dates" attribute;
  • [0]dates[0] represents the first array element of the "dates" attribute for the first model in tabular input.

In order to get attribute name without suffixes or prefixes one can use the following:

// dates
echo Html::getAttributeName('dates[0]');

Styles and Scripts

There two methods to generate tags wrapping embedded styles and scripts:

<?= Html::style('.danger { color: #f00; }') ?>

Gives you

<style>.danger { color: #f00; }</style>


<?= Html::script('alert("Hello!");', ['defer' => true]);

Gives you

<script defer>alert("Hello!");</script>

If you want to link external style from CSS file:

<?= Html::cssFile('@web/css/ie5.css', ['condition' => 'IE 5']) ?>

generates

<!--[if IE 5]>
    <link href="http://example.com/css/ie5.css" />
<![endif]-->

First argument is the URL. Second is an array of options. Additionally to regular options you could specify:

  • condition to wrap <link with conditional comments with condition specified. Hope you won't need conditional comments ever ;)
  • noscript could be set to true to wrap <link with <noscript> tag so it will be included only when there's either no JavaScript support in the browser or it was disabled by the user.

To link JavaScript file:

<?= Html::jsFile('@web/js/main.js') ?>

Same as with CSS first argument specifies link to the file to be included. Options could be passed as the second argument. In options you can specify condition in the same way as in options for cssFile.

Hyperlinks

There's a method to generate hyperlink conveniently:

<?= Html::a('Profile', ['user/view', 'id' => $id], ['class' => 'profile-link']) ?>

The first argument is the title. It's not encoded so if you're using data got from user you need to encode it with Html::encode(). Second argument is what will be in href of <a tag. See Url::to() for details on what values it accepts. Third argument is array of tag properties.

In you need to generate mailto link you can use the following code:

<?= Html::mailto('Contact us', '[email protected]') ?>

Images

In order to generate image tag use the following:

<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>

generates

<img src="http://example.com/images/logo.png" alt="My logo" />

Aside aliases the first argument can accept routes, parameters and URLs. Same way as Url::to() does.

Lists

Unordered list could be generated like the following:

<?= Html::ul($posts, ['item' => function($item, $index) {
    return Html::tag(
        'li',
        $this->render('post', ['item' => $item]),
        ['class' => 'post']
    );
}]) ?>

In order to get ordered list use Html::ol() instead.