代码之家  ›  专栏  ›  技术社区  ›  melkisadek

SelectTagHelper不显示所选项目

  •  0
  • melkisadek  · 技术社区  · 5 年前

    我想使用可枚举的SelectListItems作为我的数据源,而不向ViewModel添加额外的属性来保存当前选定的值,因为这些值已经存储在SelectListItems中。

    我使用的是定制的SelectTagHelper(删除了多属性),我认为这可能是问题所在,但我已经用标准的SelectTagHelper进行了测试,我找不到从SelectListItems中捕获所选项目的方法。

    有没有办法让默认的SelectTagHelper像这样工作,或者我需要扩展自定义的SelectTagHelper?

    我试过使用SelectList和SelectListItems的IEnumerable,但这两种方法的工作方式都不可能。

    在调试时,这些项将正确返回(在下面的示例中,其中一个项的选定值为true)。我假设在标准SelectTagHelper中有某种东西阻止从Items集合解析所选项。

    型号(带SelectListItems):

    public class TaskEditViewModel
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public IEnumerable<SelectListItem> ProjectId { get; set; }
        public string Week { get; set; }
    }
    

    [HttpGet]
    public IActionResult Edit(int Id)
    {
        var model = _repo.GetTaskEdit(Id);                       
    
        if (model != null)
        {
            return View(model);
        }
    
        return NotFound();            
    }
    

    存储库:

    public TaskEditViewModel GetTaskEdit(int Id)
    {
        var query = _context.Task.Where(t => t.Id == Id);
    
        var model = query
                    .ProjectTo<TaskEditViewModel>(_mapper.ConfigurationProvider)
                    .Single();
    
        if (model != null)
        {
            var selected = query.First().ProjectId; //gets currently selected value as int
            var list = _context.Project.Select(x => new SelectListItem(x.Name, x.Id.ToString(), true ? x.Id == selected : false));
    
            model.ProjectId = list;
    
            return model;
        }
    
        return null;
    }
    

    HTML格式:

        <div class="form-group">
            <label asp-for="ProjectId" class="control-label"></label>
            <selectOne asp-for="ProjectId" class="form-control" asp-items="Model.ProjectId"></selectOne>
            <span asp-validation-for="ProjectId" class="text-danger"></span>
        </div>
    

    Debugger

    生成的HTML:

    <div class="form-group">
       <label class="control-label" for="ProjectId">Project</label>
         <select class="form-control" data-val="true" data-val-required="Please select a project." id="ProjectId" multiple="multiple" name="ProjectId">
           <option value="1">7 Day SAT</option>
           <option value="2">UEC</option>
         </select>
       <span class="text-danger field-validation-valid" data-valmsg-for="ProjectId" data-valmsg-replace="true"></span>
    </div>
    
    0 回复  |  直到 5 年前
        1
  •  1
  •   poke    5 年前

    正如我已经在注释中所写的,select标记助手将使用 asp-for 元素绑定到视图模型。这意味着指定属性中的模型值将用于匹配标记辅助对象的可用项的值,以确定当前选择了哪些项。不管发生什么,这个过程都是有效的 SelectListItem 有它的 Selected 属性设置为 true .

    也就是说,如果你不使用 ,那么你完全可以随心所欲地完成这项工作:

    // in the controller action
    return View(new TaskEditViewModel
    {
        ProjectId = new List<SelectListItem>()
        {
            new SelectListItem { Text = "Item 1", Value = "value-1" },
            new SelectListItem { Text = "Item 2", Value = "value-2", Selected = false },
            new SelectListItem { Text = "Item 3", Value = "value-3" },
            new SelectListItem { Text = "Item 4", Value = "value-4" },
        },
    });
    
    // in the view
    <select class="form-control" asp-items="Model.ProjectId"></select>
    

    <select class="form-control">
        <option value="value-1">Item 1</option>
        <option value="value-2">Item 2</option>
        <option selected="selected" value="value-3">Item 3</option>
        <option value="value-4">Item 4</option>
    </select>
    

    只有当你加上 这会停止工作。

    <select class="form-control" id="ProjectId" multiple="multiple" name="ProjectId">
        <option value="value-1">Item 1</option>
        <option value="value-2">Item 2</option>
        <option value="value-3">Item 3</option>
        <option value="value-4">Item 4</option>
    </select>
    

    倍数 选择。此外,逻辑现在将尝试匹配 SelectListItem.Value 价值 Model.ProjectId 仅用于确定是否选择了某个对象。

    正如在注释中所指出的,这不是您通常在这里使用selecttaghelper的方式。相反,您将为所选的 价值

    public class TaskEditViewModel
    {
        // …
        public string ProjectId { get; set; }
        public IEnumerable<SelectListItem> AvailableProjects { get; set; }
    }
    
    // in the controller
    return View(new TaskEditViewModel
    {
        ProjectId = "value-3",
        AvailableProjects = new List<SelectListItem>()
        {
            new SelectListItem { Text = "Item 1", Value = "value-1" },
            new SelectListItem { Text = "Item 2", Value = "value-2" },
            new SelectListItem { Text = "Item 3", Value = "value-3" },
            new SelectListItem { Text = "Item 4", Value = "value-4" },
        },
    });
    
    // in the view
    <select asp-for="ProjectId" class="form-control" asp-items="Model.AvailableProjects"></select>
    

    现在,这是您将获得的HTML:

    <select class="form-control" id="ProjectId" name="ProjectId">
        <option value="value-1">Item 1</option>
        <option value="value-2">Item 2</option>
        <option selected="selected" value="value-3">Item 3</option>
        <option value="value-4">Item 4</option>
    </select>
    

    请注意,项3现在已隐式选中,即使其 选择列表项 没有 挑选出来的 ProjectId 在模型中恰好等于 Value 选择列表项 . 这正是它使用的逻辑。

    这种方法比使用 中的属性 选择列表项 option name select 标记是值所用于的键,提交表单将有效地发送 ProjectId=value-3

    当该模型作为控制器中POST操作的一部分绑定时,该值可以正确地反序列化到 模型的属性:

    [HttpPost]
    public IActionResult Edit(TaskEditViewModel model)
    {
        var selectedProject = model.ProjectId; // "value-3"
        // …
    }
    
        2
  •  0
  •   melkisadek    5 年前

    我决定扩展我正在使用的自定义TagHelper来覆盖这一点,因为我想提供一个TagHelper来覆盖Select输入的Create和Edit实例。

    标记帮助程序:

    [HtmlTargetElement("selectOne", Attributes = "asp-for")]
        public class SingleSelectTagHelper : SelectTagHelper
        {
            public SingleSelectTagHelper(IHtmlGenerator generator)
                : base (generator)
            {
    
            }       
    
            public override void Process(TagHelperContext context, TagHelperOutput output)
            {
                base.Process(context, output);
    
                output.TagName = "select";           
    
                var index = output.Attributes.IndexOfName("multiple");
                output.Attributes.RemoveAt(index);
    
                output.PreContent.AppendHtml("<option value=\"\">Please select an option</option>");          
    
                output.PostContent.Reinitialize();
    
                foreach(var item in Items)
                {
                    if(item.Selected)
                    {
                        output.PostContent.AppendHtml($"<option selected='selected' value=" + item.Value + ">" + item.Text + "</option>");
                    }
                    else
                    {
                        output.PostContent.AppendHtml($"<option value=" + item.Value + ">" + item.Text + "</option>");
                    }                
                }  
            }
        }
    

    用法:

        <div class="form-group">
            <label asp-for="ProjectId" class="control-label"></label>
            <selectOne asp-for="ProjectId" class="form-control" asp-items="Model.ProjectId"></selectOne>
            <span asp-validation-for="ProjectId" class="text-danger"></span>
        </div>
    

            <div class="form-group">
                <label class="control-label" for="ProjectId">Project</label>
                <select class="form-control" data-val="true" data-val-required="Please select a project." id="ProjectId" name="ProjectId">
                    <option value="">Please select an option</option>
                    <option value=1>Option 1</option>
                    <option selected='selected' value=2>Option 2</option>
                </select>
                <span class="text-danger field-validation-valid" data-valmsg-for="ProjectId" data-valmsg-replace="true"></span>
            </div>
    
    推荐文章