Создание HTML-элементов

59

Итак, в предыдущей статье мы рассмотрели создание и настройку HTML-дескрипторов веб-форм. HTML-форма не имеет особого смысла до тех пор, пока не будут созданы некоторые элементы управления вводом (например, <input>). В таблице ниже описаны базовые вспомогательные методы, которые доступны для создания элементов <input>, и приведены примеры генерируемой ими HTML-разметки. Во всех этих вспомогательных методах первый аргумент используется для установки значений атрибутов id и name элемента <input>, а второй аргумент служит для установки значения атрибута value.

Базовые вспомогательные методы HTML для создания элементов управления вводом
Метод Пример Генерируемый HTML-элемент
Html.CheckBox() Html.CheckBox("myCheckbox", false) <input id="myCheckbox" name="myCheckbox" type="checkbox" value="true">
<input name="myCheckbox" type="hidden" value="false">
Html.Hidden() Html.Hidden("myHidden", "val") <input id= "myHidden" name="myHidden" type="hidden" value="val">
Html.RadioButton() Html.RadioButton("myRadiobutton", "val", true) <input checked="checked" id="myRadiobutton" name="myRadiobutton" type="radio" value="val">
Html.Password() Html.Password("myPassword", "val") <input id="myPassword" name="myPassword" type="password" value="val">
Html.TextArea() Html.TextArea("myTextarea", "val", 5, 20, null) <textarea cols="20" id="myTextarea" name="myTextarea" rows="5">val</textarea>
Html.TextBox() Html.TextBox("myTextbox", "val") <input id="myTextbox" name="myTextbox" type="text" value="val">

Каждый из перечисленных вспомогательных методов имеет перегруженную версию. В этой таблице показаны простейшие версии, но можно также предоставить дополнительный аргумент object для указания HTML-атрибутов, как это делалось с элементом <form> в предыдущей статье.

Обратите внимание, что вспомогательный метод для флажка (Html.CheckBox()) генерирует два элемента <input>: собственно флажок и скрытый элемент <input> с тем же самым именем. Причина в том, что браузеры не отправляют значения для флажков, если те не отмечены. Наличие скрытого элемента управления гарантирует, что ASP.NET MVC Framework получит значение из скрытого поля, когда такое произойдет.

Использование этих базовых вспомогательных методов для создания элементов управления вводом демонстрируется в примере ниже:

@model HelperMethods.Models.User

@{
    ViewBag.Title = "CreateUser";
}

<h2>Создать пользователя</h2>
@using (Html.BeginRouteForm("FormRoute", null, FormMethod.Post,
    new { @class = "userCssClass", data_formType="user" }))
{ 
    <div class="item">
        <label>UserId</label>
        @Html.TextBox("userId", @Model.UserId)
    </div>
    <div class="item">
        <label>Имя</label>
        @Html.TextBox("firstName", @Model.FirstName)
    </div>
    <div class="item">
        <label>Фамилия</label>
        @Html.TextBox("lastName", @Model.LastName)
    </div>
    <input type="submit" value="Отправить" />
}

В примере ниже показаны HTML-элементы <input>, сгенерированные этим представлением. Вывод очень похож на первоначальный элемент <form>, но в нем присутствует ряд подсказок инфраструктуры ASP.NET MVC Framework в виде атрибутов данных, добавленных с целью поддержки проверки достоверности формы, которая будет подробно рассматриваться позже:

...
<form action="/app/forms/Home/CreateUser" class="userCssClass" 
    data-formType="user" method="post">
    <div class="item">
        <label>UserId</label>
        <input data-val="true" data-val-number="The field UserId must be a number." 
            data-val-required="Требуется поле UserId." 
            id="userId" name="userId" type="text" value="0" />
    </div>
    <div class="item">
        <label>Имя</label>
        <input id="firstName" name="firstName" type="text" value="" />
    </div>
    <div class="item">
        <label>Фамилия</label>
        <input id="lastName" name="lastName" type="text" value="" />
    </div>
    <input type="submit" value="Отправить" />
</form>
....

Генерация элемента управления вводом из свойства модели

Вспомогательные методы, используемые в предыдущем разделе, работают хорошо, но нам по-прежнему необходимо гарантировать, что значение, передаваемое в первом аргументе, соответствует значению модели, которое передается во втором аргументе. Если эти значения не согласованы, инфраструктура ASP.NET MVC Framework не сможет воссоздать объект модели из данных формы, поскольку атрибуты name и значения элементов <input> формы не соответствуют друг другу.

Для каждого метода, перечисленного в таблице выше, доступна перегруженная версия, которая принимает единственный аргумент типа string:

@model HelperMethods.Models.User

@{
    ViewBag.Title = "CreateUser";
}

<h2>Создать пользователя</h2>
@using (Html.BeginRouteForm("FormRoute", null, FormMethod.Post,
    new { @class = "userCssClass", data_formType="user" }))
{ 
    <div class="item">
        <label>UserId</label>
        @Html.TextBox("userId")
    </div>
    <div class="item">
        <label>Имя</label>
        @Html.TextBox("firstName")
    </div>
    <div class="item">
        <label>Фамилия</label>
        @Html.TextBox("lastName")
    </div>
    <input type="submit" value="Отправить" />
}

Аргумент string применяется для поиска в данных представления, в объекте ViewBag и в модели представления соответствующего элемента данных, который может использоваться в качестве основы для элемента input. Таким образом, например, если вызвать @Html.TextBox("DataValue"), то инфраструктура ASP.NET MVC Framework попытается найти элемент данных, который соответствует ключу DataValue. Будут проверяться следующие местоположения:

Первое найденное значение используется для установки атрибута value генерируемой HTML-разметки. (Последняя проверка, в @Model.DataValue, предпринимается, только если модель представления содержит свойство или поле по имени DataValue.)

Если указать строку вроде DataValue.First.Name, поиск становится более сложным. Инфраструктура ASP.NET MVC Framework опробует различные комбинации элементов, разделяемых точками, такие как перечисленные ниже:

Проверяются многие перестановки. И снова будет использоваться первое найденное значение, завершая поиск. С этим приемом связана очевидная проблема производительности, однако помните, что внутри объекта ViewBag обычно содержится совсем немного элементов, так что поиск среди них не должен отнимать значительное время.

Использование строго типизированных вспомогательных методов для создания элементов управления вводом

Каждому базовому вспомогательному методу для создания элементов управления вводом, описанному в таблице выше, соответствует строго типизированный вспомогательный метод. Эти вспомогательные методы перечислены в таблице ниже вместе с примерами HTML-разметки, которую они генерируют. Такие вспомогательные методы могут применяться только со строго типизированными представлениями. (Часть вспомогательных методов генерируют атрибуты, которые помогают обеспечивать проверку достоверности данных форм на стороне клиента, но для краткости в таблице они не приведены.)

Строго типизированные вспомогательные методы для создания элементов управления вводом
Метод Пример Генерируемый HTML-элемент
Html.CheckBoxFor() Html.CheckBoxFor(х => х.IsApproved) <input id="IsApproved" name="IsApproved" type="checkbox" value="true">
<input name="IsApproved" type="hidden" value="false">
Html.HiddenFor() Html.HiddenFor(x => x.FirstName) <input id="FirstName" name="FirstName" type="hidden" value="value">
Html.RadioButtonFor() Html.RadioButtonFor(x => x.IsApproved, "val") <input id="IsApproved" name="IsApproved" type="radio" value="val">
Html.PasswordFor() Html.PasswordFor(x => x.Password) <input id="Password" name="Password" type="password" value="val">
Html.TextAreaFor() Html.TextAreaFor(x => x.Bio, 5, 20, new{}) <textarea cols="20" id="Bio" name="Bio" rows="5">
Bio value
</textarea>
Html.TextBoxFor() Html.TextBoxFor(x => x.FirstName) <input id="FirstName" name="FirstName" type="text" value="">

Строго типизированные вспомогательные методы для создания элементов управления вводом работают с лямбда-выражениями. В такое выражение передается объект модели представления, в котором можно выбрать поле или свойство, используемое для установки атрибута value. В примере ниже показано, как этот вид вспомогательного метода применяется в представлении CreateUser.cshtml из примера приложения:

@model HelperMethods.Models.User

@{
    ViewBag.Title = "CreateUser";
}

<h2>Создать пользователя</h2>
@using (Html.BeginRouteForm("FormRoute", null, FormMethod.Post,
    new { @class = "userCssClass", data_formType="user" }))
{ 
    <div class="item">
        <label>UserId</label>
        @Html.TextBoxFor(user => user.UserId)
    </div>
    <div class="item">
        <label>Имя</label>
        @Html.TextBoxFor(user => user.FirstName)
    </div>
    <div class="item">
        <label>Фамилия</label>
        @Html.TextBoxFor(user => user.LastName)
    </div>
    <input type="submit" value="Отправить" />
}

Генерируемая этими вспомогательными методами HTML-разметка ничем не отличается от приведенной ранее. Тем не менее, использовать в проектах именно строго типизированные вспомогательные методы предпочтительнее, т.к. это уменьшает вероятность внесения ошибок за счет некорректного написания имен свойств.

Создание элементов выбора

В таблице ниже описаны вспомогательные методы HTML, предназначенные для создания элементов выбора (select). Они могут применяться для выбора одиночного элемента из раскрывающегося списка или для обеспечения одновременного выбора множества элементов. Как и в случае других элементов формы, доступны слабо и строго типизированные версии этих вспомогательных методов:

Вспомогательные методы HTML, генерирующие элементы выбора
Метод Описание Пример Генерируемый HTML-элемент
Html.DropDownList() Раскрывающийся список Html.DropDownList("myList",
    new SelectList(new [] {"A", "B"}), "Выбрать")
<select id="myList" name="myList">
    <option value="">Выбрать</option>
    <option>A</option>
    <option>B</option>
</select>
Html.DropDownListFor() Раскрывающийся список Html.DropDownListFor(x => x.Gender,
    new SelectList(new [] {"M", "F"}))
<select id="Gender" name="Gender">
    <option>M</option>
    <option>F</option>
</select>
Html.ListBox() Список с множественным выбором Html.ListBox("myList",
    new MultiSelectList(new [] {"A", "B"}))
<select id="myList" name="myList" multiple="multiple">
    <option>A</option>
    <option>B</option>
</select>
Html.ListBoxFor() Список с множественным выбором Html.ListBoxFor(x => x.Vals,
    new MultiSelectList(new [] {"A", "B"}))
<select id="Vals" name="Vals" multiple="multiple">
    <option>A</option>
    <option>B</option>
</select>

Вспомогательные методы, генерирующие элементы выбора, принимают параметры типа SelectList или MultiSelectList. Разница между этими классами заключается в том, что MultiSelectList имеет опции конструктора, которые позволяют указывать возможность выбора более одного элемента при начальной визуализации страницы.

Оба эти класса оперируют с последовательностями IEnumerable объектов. В таблице выше создавались встраиваемые массивы, содержащие списковые элементы, которые необходимо отображать, но классы SelectList и MultiSelectList способны также извлекать для элементов списка значения из объектов, включая объект модели. В примере ниже показано, как создать элемент <select> для свойства Role объекта модели User:

...
@using (Html.BeginRouteForm("FormRoute", null, FormMethod.Post,
    new { @class = "userCssClass", data_formType="user" }))
{ 
    ...
    <div class="item">
        <label>Роль</label>
        @Html.DropDownListFor(user => user.Role,
            new SelectList(Enum.GetNames(typeof(HelperMethods.Models.Role))))
    </div>
    <input type="submit" value="Отправить" />
}

Свойство Role объявлено так, что оно принимает значение перечисления Role, определенного в том же файла класса. Поскольку классы SelectList и MultiSelect имеют дело с экземплярами реализаций IEnumerable, мы должны использовать метод Enum.GetNames() для того, чтобы можно было указывать перечисление Role в качестве источника для элемента <select>.

Ниже приведена HTML-разметка, которая создается последней версией представления:

<div class="item">
    <label>Роль</label>
    <select data-val="true" data-val-required="Требуется поле Role." 
        id="Role" name="Role">
        <option selected="selected">Admin</option>
        <option>User</option>
        <option>Guest</option>
    </select>
</div>
Лучший чат для C# программистов