Это моя ситуация: в базовом приложении ASP. NET мне нужно сгенерировать следующий код HTML в представлении Razor из экземпляра модели:
<select name="CultureName">
<option value="de-DE" data-summary="Deutsch (Deutschland)">* Deutsch (Deutschland)</option>
<option value="de-AT" data-summary="Deutsch (Österreich)">* Deutsch (Österreich)</option>
<option value="de-CH" data-summary="Deutsch (Schweiz)">* Deutsch (Schweiz)</option>
<option value="en-GB" data-summary="Englisch (Großbritannien)" selected>Englisch (Großbritannien)</option>
^^^^^^^^- important!
<option value="en-US" data-summary="Englisch (USA)">Englisch (USA)</option>
</select>
The CultureName
свойство модели имеет значение «en-GB». Модель также имеет список всех доступных опций. Отдельный атрибут data-summary
поддерживается структурой веб-интерфейса, которую я использую, и должен быть установлен для каждого элемента <option>
, наряду с другими атрибутами, оставленными здесь для краткости. Один из параметров предварительно выбирается атрибутом selected
.
Я не могу использовать предопределенный класс SelectListItem
, поскольку он не поддерживает дополнительные атрибуты. Поэтому я создал свой собственный класс SelectListOption
, который выглядит аналогично, но имеет дополнительные свойства. У меня есть помощник по тегам, который позволяет мне написать это:
<select asp-for="CultureName">
@foreach (var culture in Model.Cultures)
{
<option item="@culture"></option>
}
</select>
Вот код:
[HtmlTargetElement("option", ParentTag = "select", Attributes = "item")]
public class OptionTagHelper : TagHelper
{
public SelectListOption Item { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (Item != null)
{
output.Content.SetContent(Item.Text);
output.Attributes.SetAttribute("value", Item.Value);
if (Item.Summary != null)
output.Attributes.SetAttribute("data-summary", Item.Summary);
if (Item.HtmlText != null)
output.Attributes.SetAttribute("data-html", Item.HtmlText);
if (Item.HtmlSummary != null)
output.Attributes.SetAttribute("data-summary-html", Item.HtmlSummary);
if (Item.Selected)
output.Attributes.SetAttribute("selected", true);
if (Item.Disabled)
output.Attributes.SetAttribute("disabled", true);
output.Attributes.RemoveAll("item");
}
}
}
Он заполняет другие атрибуты элемента <option>
из модели. Это хорошо работает, но выбор игнорируется при визуализации страницы. Таким образом, пользователь увидит список со всеми параметрами, но текущий выбор отсутствует .
Я обнаружил, что то, что я делаю, не обязательно правильно, и я должен сделать это вместо этого:
<select asp-for="CultureName" asp-items="@Model.Cultures">
</select>
Предопределенный помощник тега select затем заполнит параметры для меня. Но опять же, я не могу использовать это, потому что мне нужны дополнительные стандартные атрибуты здесь. Поэтому я тоже попытался сделать это сам.
Вот код, но я понятия не имею, что я там делаю, потому что документации об этом немного:
[HtmlTargetElement("select", Attributes = "options")]
public class SelectTagHelper : TagHelper
{
public IEnumerable<SelectListOption> Options { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (Options != null)
{
foreach (var option in Options)
{
// TODO: Use HtmlEncoder.HtmlEncode() on values?
output.Content.AppendHtml($"<option value=\"{option.Value}\"");
if (option.Summary != null)
output.Content.AppendHtml($" data-summary=\"{option.Summary}\"");
if (option.HtmlText != null)
output.Content.AppendHtml($" data-html=\"{option.HtmlText}\"");
if (option.HtmlSummary != null)
output.Content.AppendHtml($" data-summary-html=\"{option.HtmlSummary}\"");
if (option.Selected)
output.Content.AppendHtml(" selected");
if (option.Disabled)
output.Content.AppendHtml(" disabled");
output.Content.AppendHtml($">{option.Text}</option>");
}
}
}
}
I ' используя это как:
<select asp-for="CultureName" options="@Model.Cultures">
</select>
Кажется, это работает, я получаю все опции в моем окне выбора. Но, конечно, теперь все еще без первоначального выбора .
Теперь я застрял. Как я могу получить атрибут selected
для правильного элемента <option>
? Как узнать текущее значение модели элемента <select>
? У него есть атрибут asp-for
, но это только имя, а не значение, которое мне нужно сопоставить.
Я ищу что-то вроде этого:
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (Options != null)
{
foreach (var option in Options)
{
output.Content.AppendHtml($"<option value=\"{option.Value}\"");
if (option.Value == CURRENT_SELECT_VALUE_FROM_MODEL)
output.Content.AppendHtml(" selected");
// (Other attributes)
output.Content.AppendHtml($">{option.Text}</option>");
}
}
}
Далее у меня есть другое требование : В некоторых местах мне нужно добавить еще один атрибут c, определяющий страницу, ко всем <option>
элементам, которые будут использоваться для других частей формы:
<select asp-for="CultureName">
@foreach (var culture in Model.Cultures)
{
<option item="@culture" data-separator="@culture.ValueObject.TextInfo.ListSeparator"></option>
}
</select>
Это делает доступным каждый элемент CultureInfo TextInfo.ListSeparator
значение для скриптов страницы через атрибут data-separator
. Это, очевидно, больше не может быть обработано регистром по умолчанию, поэтому мне все еще нужно создать элементы <option>
в al oop самостоятельно. К счастью, это уже описано моим первым помощником по тегам, поэтому все дополнительные атрибуты уже есть. Но опять же, атрибут selected
отсутствует .
Хотя я мог попытаться изменить список параметров в модели, чтобы у одного из них было установлено свойство Selected
, чтобы Это большая глупая работа, которая уже должна быть покрыта чем-то вроде asp-for
.
Здесь я также должен выяснить у каждого помощника тега option, должна ли быть выбрана конкретная опция c.
Или, в качестве альтернативы, помощник по тегу select (родительский) может найти элемент option для выбора после обработки его содержимого. Поэтому, если это возможно, мне нужно будет вызвать закрывающий тег </select>
и выполнить итерацию всех дочерних элементов <option>
, чтобы они соответствовали их атрибуту value
, и добавить атрибут selected
к одному из них.
Может тегировать помощники даже помогают мне с этим или они слишком ограничены для этой задачи? Насколько помогают эти помощники?