ASP.NET 5 MVC 6中的单选按钮标记助手

34

我在ASP.NET 5 MVC 6中没有看到任何适用于单选按钮的标签助手。在需要使用单选按钮的表单元素处理方面,应该采取什么正确的方法?

4个回答

47

所有输入类型都有一个TagHelper,其中包括单选按钮类型。假设你有这样的视图模型:

public class CreateUserVm
{
    public string UserName { set; get; }
    public IEnumerable<RoleVm> Roles { set; get; } 
    public int SelectedRole { set; get; }
}
public class RoleVm
{
    public int Id { set; get; }
    public string RoleName { set; get; }        
}

而在您的 GET 操作中,

public IActionResult Index()
{
    var vm = new CreateUserVm
    {
        Roles = new List<RoleVm>
        {
            new RoleVm {Id = 1, RoleName = "Admin"},
            new RoleVm {Id = 2, RoleName = "Editor"},
            new RoleVm {Id = 3, RoleName = "Reader"}
        }
    };
    return View(vm);
}

在视图中,您可以简单地使用输入标记的标记。

@model YourNamespaceHere.CreateUserVm
<form asp-action="Index" asp-controller="Home">
    <label class="label">User name</label>
    <div class="col-md-10">
        <input type="text" asp-for="UserName" />
    </div>
    <label class="label">Select a Role</label>
    <div class="col-md-10">
    @foreach (var item in Model.Roles)
    {
       <input asp-for="SelectedRole" type="radio" value="@item.Id" /> @item.RoleName
    }
    </div>
    <input type="submit" />
</form>
当您提交表单时,所选角色的Rold Id将位于SelectedRole属性中。
请注意,上面的razor代码将为循环生成的每个输入元素生成具有相同Id属性值和name属性值的输入元素。在上面的示例中,它将生成3个元素,其Idname属性值均设置为SelectedRole。当name属性值与视图模型中的属性名(SelectedRole)匹配时,模型绑定将起作用,但重复的Id属性值可能会给客户端代码带来麻烦(文档中的重复Id无效)。

问题:我可以将值设置为true或false吗?value="true" - Kemal Tezer Dilsiz
如果您希望在选择单选按钮时传递该内容。 - Shyju
这会不会在浏览器控制台中产生错误?因为我认为ASP.Net Core为每个单选框输入生成相同的Id。 - Mohammed Noureldin
@MohammedNoureldin 是的。标签助手为循环生成的所有输入元素生成相同的ID,这是无效的HTML!目前,我不知道如何处理这个干净的解决方案。但是,模型绑定将使用上述方法,因为它只关心输入的“名称”属性值。 - Shyju
4
目前的解决方法似乎是手动设置id HTML属性,以覆盖标签助手的行为。 - Mohammed Noureldin
显示剩余2条评论

8

虽然有使用asp-for="SomeField"的解决方案,但我发现最简单的解决方案是将视图模型字段与单选按钮的name字段匹配。

视图模型:

public class MyViewModel
{
   public string MyRadioField { get; set; }
}

表单(为了清晰起见没有标签):

@model MyViewModel
<form asp-action="SomeAction" asp-controller="SomeController">
   <input type="radio" name="MyRadioField" value="option1" checked />
   <input type="radio" name="MyRadioField" value="option2" />
   <input type="radio" name="MyRadioField" value="option3" />

   <input type="submit" />
</form>

提交表单后,MyRadioField 将被填充为所选单选按钮的值。

0
这是一个扩展方法,它可以根据SelectList渲染一个单选按钮列表。您可以像使用Html.DropDownListFor一样使用它。
public static HtmlString RadioButtonListFor<TModel, TResult>(this IHtmlHelper<TModel> helper, Expression<Func<TModel, TResult>> expression, SelectList selectList, string className = "radio-group")
{
  //render a list of radio buttons to bind to the specified value
  MemberExpression member = expression.Body as MemberExpression;
  string propertyName = member.Member.Name;

  Func<TModel, TResult> method = expression.Compile();
  TResult selectedValue = method(helper.ViewData.Model);

  var output = new StringBuilder();
  if (!string.IsNullOrEmpty(className))
    output.AppendLine($"<div class='{className}'>");
  else
    output.AppendLine("<div>");

  foreach (SelectListItem item in selectList)
  {
    bool selected = Convert.ToString(selectedValue) == item.Value;
    string html = $"<label> <input type='radio' name='{propertyName}' value='{item.Value}' {(selected ? "checked" : "")} /> {item.Text} </label>";
    output.AppendLine(html);
  }
  output.AppendLine("</div>");

  return new HtmlString(output.ToString());
}

在 Razor 文件中,您可以这样调用它:

 @Html.RadioButtonListFor(m => m.ModelProperty, selectList)

0

我编写了自己的标签助手来完成这个任务。它将input标签替换为每个枚举变量的标签和单选按钮:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using DigitScpi.Web.Helpers;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace TagHelpers
{
    /// Generates the radio buttons for an enum. Syntax: `<input radio asp-for="MyMappedEnumField"/>`.
    [HtmlTargetElement("input", Attributes = RadioAttributeName)]
    public class RadioButtonTagHelper : TagHelper
    {
        private const string RadioAttributeName = "radio";
        private const string ForAttributeName = "asp-for";

        [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; }
        private readonly IHtmlGenerator _generator;

        [HtmlAttributeName(ForAttributeName)] public ModelExpression For { get; set; }
        [HtmlAttributeName(RadioAttributeName)] public bool RadioMarker { get; set; }

        public RadioButtonTagHelper(IHtmlGenerator generator)
        {
            _generator = generator;
        }

        /// <inheritdoc />
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.SuppressOutput();

            foreach (var enumItem in For.Metadata.EnumNamesAndValues)
            {
                var id = VariantId(enumItem);
                var name = For.Metadata.EnumGroupedDisplayNamesAndValues.FirstOrDefault(v => v.Value == enumItem.Value).Key.Name;
                var radio = _generator.GenerateRadioButton(ViewContext, For.ModelExplorer, For.Name, enumItem.Key, false, new {id});
                var label = _generator.GenerateLabel(ViewContext, For.ModelExplorer, For.Name, name, new {@for = id});

                output.PreElement.AppendHtml(radio);
                output.PreElement.AppendHtml(label);
            }
        }

        /// Computes the variant to be unique for each radiobutton.
        private string VariantId(KeyValuePair<string, string> enumItem) =>
            new StringBuilder()
                .Append(ViewContext.CreateUniqueId(_generator.IdAttributeDotReplacement, For.Name))
                .Append(_generator.IdAttributeDotReplacement)
                .Append(enumItem.Key)
                .ToString();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接