Issue with Custom TagHelper (Autocomplete) when used inside a List of Items (being displayed with EditorFor)
我们编写了一个自定义的
自动完成功能
但是当使用
- 我们如何获得需要添加到所有字段名称前面的基于Z索引的名称前缀?
- 我们必须自己弥补吗?
-
还是我们以某种方式从
ModelExpression 中提取? -
标准输入
TagHelper 是否得到正确处理? -
EditorFor /EditorTemplate 是在ASP.NET Core 1中处理可编辑对象列表的正确方法吗?
自动完成TagHelper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | public class AutocompleteTagHelper : TagHelper { public ModelExpression AspFor { get; set; } public ModelExpression AspValue { get; set; } //public string AspFor { get; set; } public string Route { get; set; } public string RouteParameters { get; set; } public string TargetWrapper { get; set; } public string DisplayFormat { get; set; } public string ValueFormat { get; set; } public string ManageListCallback { get; set; } public string ListWrapper { get; set; } public string Placeholder { get; set; } private SkillDbContext _context; private readonly UserManager<ApplicationUser> _userManager; private IMemoryCache cache; public AutocompleteTagHelper(SkillDbContext Context, UserManager<ApplicationUser> userManager, IMemoryCache cache) { _context = Context; _userManager = userManager; this.cache = cache; } public override void Process(TagHelperContext context, TagHelperOutput output) { var hiddenVal =""; var displayVal =""; //asp-for="LandingPointId" //route="/Lookups/GetLandingPoint" //route-parameter="SomeOtherId" //target-wrapper="form" key="Id" //label="{Name} ({Code})" //output="{code}" //AspFor. //get parent model from AspFor object thisModel = null; //get value properties if (AspValue != null) { hiddenVal = ValueFormat; displayVal = DisplayFormat; thisModel = AspValue.Model; } else if (AspFor.Model != null && !AspFor.Model.Equals((object)0)) { Object Id = AspFor.Model; string routeMethod = Route.Split('/').Last<string>(); } if(thisModel != null) { PropertyInfo[] propertyInfo = thisModel.GetType().GetProperties(); foreach (var info in propertyInfo) { var val = info.GetValue(thisModel); if (val != null) { hiddenVal = hiddenVal.Replace(("{" + info.Name +"}"), val.ToString()); displayVal = displayVal.Replace(("{" + info.Name +"}"), val.ToString()); } } } var isAcList = ManageListCallback != null && ListWrapper != null; string aspForName = AspFor.Name.Replace(".","_"); output.TagName ="input"; // replaces with tag inputId = inputName = aspForName; output.Attributes["id"] = aspForName; output.Attributes["name"] = aspForName; output.Attributes["type"] ="text"; output.Attributes["route"] = Route; output.Attributes["route-parameters"] = RouteParameters; output.Attributes["target-wrapper"] = TargetWrapper; output.Attributes["placeholder"] = Placeholder; output.Attributes["value-format"] = ValueFormat; output.Attributes["display-format"] = DisplayFormat; output.Attributes["value"] = displayVal; output.Attributes["class"] ="autocomplete form-control" + (isAcList?" hasList":""); TagBuilder HiddenValue = new TagBuilder("input"); HiddenValue.Attributes["name"] = inputName; HiddenValue.Attributes["id"] = inputId +"_hidden"; HiddenValue.Attributes["type"] ="hidden"; HiddenValue.Attributes["value"] = hiddenVal; output.PreElement.SetContent(HiddenValue); if (isAcList) { TagBuilder AddBtn = new TagBuilder("a"); AddBtn.Attributes["id"] = AspFor.Name.Replace(".","_") +"_submit"; AddBtn.Attributes["class"] ="moana-autocomplete-list-manager disabled btn btn-primary"; AddBtn.Attributes["listwrapper"] = ListWrapper; AddBtn.Attributes["href"] = ManageListCallback; AddBtn.InnerHtml.AppendHtml("Add"); output.PostElement.SetContent(AddBtn); } } |
这是模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class AddressEditorModel { public int Id { get; set; } public string AddressLinkTo { get; set; } public int AddressLink { get; set; } public string AddressLine { get; set; } public int ContactTypeId { get; set; } public string Suburb { get; set; } public string City { get; set; } public string Postcode { get; set; } public int? CountryId { get; set; } public string ContactTypeName { get; set; } public string CountryCode { get; set; } public string CountryName { get; set; } } |
这是cshtml
1 2 3 4 | @model List<Skill.ViewModels.AddressEditorModel> @Html.EditorFor(m => m) |
这是控制器方法调用
1 | public async Task<IActionResult> UpdateAddressInfo(List<AddressEditorModel> addresses) |
最后是EditorTemplate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | @model Skill.ViewModels.AddressEditorModel <input type="hidden" asp-for="Id" /> <input type="hidden" asp-for="ContactTypeId" /> <input type="hidden" asp-for="AddressLink" /> <input type="hidden" asp-for="AddressLinkTo" /> <input type="hidden" asp-for="CountryId" /> <label class="col-md-12 control-label" style="padding-bottom:20px;">@Model.ContactTypeName</label> <label asp-for="AddressLine" class="col-md-2 control-label">Address</label> <input asp-for="AddressLine" class="form-control" style="resize:both" /> <span asp-validation-for="AddressLine" class="text-danger" /> <label asp-for="Suburb" class="col-md-2 control-label">Suburb</label> <input asp-for="Suburb" class="form-control" /> <span asp-validation-for="Suburb" class="text-danger" /> <label asp-for="City" class="col-md-2 control-label">City</label> <input asp-for="City" class="form-control" /> <span asp-validation-for="City" class="text-danger" /> <label class="col-md-2 control-label">Country</label> </autocomplete> <span asp-validation-for="CountryId" class="text-danger" /> <label asp-for="Postcode" class="col-md-2 control-label">Post Code</label> <input asp-for="Postcode" class="form-control" /> <span asp-validation-for="Postcode" class="text-danger" /> |
请注意,上面EditorTemplate中的autocomplete标记会生成自己的内部标记(作为标记帮助器的一部分)。
这是第一个地址信息的页面的一部分(如firefox中所示)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <input id="z0__Id" type="hidden" value="5" name="[0].Id" data-val-required="The Id field is required." data-val="true"> <input id="z0__ContactTypeId" type="hidden" value="1" name="[0].ContactTypeId" data-val-required="The ContactTypeId field is required." data-val="true"> <input id="z0__AddressLink" type="hidden" value="1" name="[0].AddressLink" data-val-required="The AddressLink field is required." data-val="true"> <input id="z0__AddressLinkTo" type="hidden" value="F" name="[0].AddressLinkTo"> <label class="col-md-12 control-label" style="padding-bottom:20px;">Work</label> <label class="col-md-2 control-label" for="z0__AddressLine">Address</label> <input id="z0__AddressLine" class="form-control" type="text" value="4a Lansdowne Street" name="[0].AddressLine" style="resize:both"> <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="[0].AddressLine"> </span> <label class="col-md-2 control-label" for="z0__Suburb">Suburb</label> <input id="z0__Suburb" class="form-control" type="text" value="Bayswater" name="[0].Suburb"> <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="[0].Suburb"> </span> <label class="col-md-2 control-label" for="z0__City">City</label> <input id="z0__City" class="form-control" type="text" value="Auckland" name="[0].City"> <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="[0].City"> </span> <label class="col-md-2 control-label">Country</label> <input id="CountryId_hidden" type="hidden" value="1" name="CountryId"> <input id="CountryId" class="moana-autocomplete form-control ui-autocomplete-input" type="text" value="New Zealand (NZ)" display-format="{Name} ({Code})" value-format="{Id}" placeholder="" target-wrapper="form" route-parameters="" route="/Lookups/GetCountry" name="CountryId" autocomplete="off"> <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="[0].CountryId"> </span> <label class="col-md-2 control-label" for="z0__Postcode">Post Code</label> <input id="z0__Postcode" class="form-control" type="text" value="0604" name="[0].Postcode"> <span class="text-danger field-validation-valid" data-valmsg-replace="true" data-valmsg-for="[0].Postcode"> </span> |
请注意,Html.EditorFor会为输入名称属性生成Zn__fieldname前缀,并为输入id属性生成[n] .fieldname名称。
问题是如何访问索引值,或从TagHelper内部获取此前缀以添加到我们生成的输入上,即Zn __ *或[n]值,它实际上是EditorFor的索引器,因为它生成重复的字段
感谢您的帮助
好吧,我一直在努力地工作。
我最终不得不从Asp.Net核心源项目中查看TagHelpers。
我发现我们需要访问ViewContext.ViewData.TemplateInfo;。
从TagHelper内部。
或者我们也可以使用IHtmlGenerator对象-调用GenerateTextBox,GenerateHidden等,以根据需要构建TageHelpers。