c# - SelectTagHelper 在模型中不显示没有显式 Id 属性的选定项目
问题描述
我正在尝试在 MVC Core (2.2) 中为 Edit 操作创建一个下拉列表。
我想使用 Enumerable 的 SelectListItems 作为我的数据源,而不向我的 ViewModel 添加额外的属性来保存当前选定的值,因为这些值已经存储在 SelectListItems 中。
我正在使用自定义的 SelectTagHelper(它删除了多个属性),我认为这可能是问题所在,但我已经使用标准 SelectTagHelper 进行了测试,但我找不到从 SelectListItems 中捕获所选项目的方法。
有没有办法让默认的 SelectTagHelper 像这样工作,还是我需要扩展自定义的 SelectTagHelper?
我已经尝试过使用 SelectList 和 IEnumerable 的 SelectListItems ,但都没有按照我认为可能的方式工作。
调试时,项目会正确返回(在下面的示例中,项目的选定值为 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>
调试器:
生成的 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>
解决方案
正如我在评论中已经写的那样,选择标签助手将使用该asp-for
元素绑定到视图模型。这意味着指定属性中模型的值用于匹配标签助手的可用项的值,以确定当前选择了哪些项。无论SelectListItem
其Selected
属性设置为什么,此过程都有效true
。
这意味着,如果您不使用asp-for
,那么您完全可以随心所欲地完成这项工作:
// 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>
仅当您添加时asp-for
,它才会停止工作。
<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
并且仅使用该值来确定是否选择了某些内容。
如评论中所述,这不是您通常在此处使用 select 标签助手的方式。相反,您将拥有一个用于选定值的单独属性和一个用于可用项的单独属性:
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 现在已隐式选择,即使它SelectListItem
没有Selected
设置属性。这是因为ProjectId
模型中 的当前值恰好等于Value
的SelectListItem
。这正是它使用的逻辑。
Selected
与在 中使用属性相比,这种方法有一个巨大的好处SelectListItem
: 现在,当您提交表单时发送的数据非常清楚。由于 selected 的值option
是正在发送的内容,并且name
标签select
的 是该值所用于的键,因此ProjectId=value-3
现在提交表单将有效地发送。
然后,当该模型被绑定为控制器中 POST 操作的一部分时,该值可以正确反序列化为ProjectId
模型的属性:
[HttpPost]
public IActionResult Edit(TaskEditViewModel model)
{
var selectedProject = model.ProjectId; // "value-3"
// …
}
推荐阅读
- javascript - 添加了第二个css动画但没有产生效果
- python - 使用 TensorFLow 进行多输出分类
- python - Numpy 数组行分为 2 行。这可以改变吗?
- ruby-on-rails - Gem Recaptcha 我应该在哪里指定站点密钥?
- r - 如何在 R 中创建没有“填充”的条形图?
- javascript - 动画 appendChild div 高度 javascript
- reactjs - 无法使用 setValues 在布尔属性上设置状态
- reactjs - Spotify WebPlayer API - 更改播放器请求
- angular - Angular: TypeError: Object(...)(...).functions 不是函数
- azure - Azure 函数存储容器 Blob 触发器