这是我的情况:在ASP.NET Core应用程序中,我需要从模型实例的Razor视图中生成以下HTML代码:
<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>
模型的CultureName
属性的值为“ en-GB”。该模型还具有所有可用选项的列表。我使用的Web前端框架支持单独的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>
然后,预定义的选择标签助手将为我填写选项。但是再次,我不能使用它,因为在这里我需要其他标准属性。所以我也想自己做。
这是代码,但是我真的不知道我在做什么,因为关于它的文档并不多:
[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>");
}
}
}
}
我将其用作:
<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>");
}
}
}
下一步,我还有另一个要求:在某些地方,我需要向所有<option>
元素添加另一个页面特定的属性,这些属性将用于表单的其他部分:
<select asp-for="CultureName">
@foreach (var culture in Model.Cultures)
{
<option item="@culture" data-separator="@culture.ValueObject.TextInfo.ListSeparator"></option>
}
</select>
这将通过TextInfo.ListSeparator
属性将每个CultureInfo的data-separator
值提供给页面脚本。显然,默认情况下无法再解决此问题,因此我仍然需要自己在循环中创建<option>
元素。幸运的是,我的第一个标签助手已经覆盖了它,因此所有其他属性都已经存在。但是,再次缺少 selected
属性。
虽然我可以尝试修改模型中的选项列表,以使其中的一个具有Selected
属性集,但这是许多愚蠢的工作,应该已经被{{1} }。
在这里,我还需要从每个选项标签助手中找出是否应选择特定选项。
或者,或者,选择标签帮助器(父级)可以在处理完内容之后找到要选择的选项元素。因此,如果可能的话,我将必须触发结束asp-for
标记并迭代所有</select>
子元素以匹配其<option>
属性,并向其中一个添加value
属性。
标记助手可以帮助我吗?还是对于这项任务来说太有限了?这些助手真的有多少帮助?
答案 0 :(得分:1)
您没有对asp-for
做任何事情。这不是魔术。如果您查看其中一个内置标记帮助器的代码,您将看到它们具有捕获该属性的属性,类似于:
[HtmlAttributeName("asp-for")]
public ModelExpression For { get; set; }
然后,您必须使用此属性通过读取值来实际设置所选选项。就是说,不过,最好是从SelectTagHelper
继承标签帮助程序,而重写Process
来执行自己的逻辑,则可能会更好。不过,请记住也要拨打base.Process
。