[英]Pass sub object to partial view from views with different models, have it bind when form is posted
I have an ASP.net MVC Core 2 (can upgrade to 3 if required) web app.我有一个 ASP.net MVC Core 2(如果需要可以升级到 3)web 应用程序。
There are several different classes, landlord, tenant, contractor - they each have an address object, and other different properties.有几个不同的类别,房东、租户、承包商——他们每个都有一个地址 object 和其他不同的属性。
I have a partial view that is passed the address object from each view.我有一个部分视图,每个视图都传递了地址 object。
<partial name="_AddressPartial" , model="@Model" />
This works fine.这工作正常。 But when the form is posted, each address field is posted flat, as the names of the address are things like "Street", not "Address.Street" - because the address model is passed to the partial.
但是当表单发布时,每个地址字段都是平铺的,因为地址的名称是“Street”,而不是“Address.Street” - 因为地址 model 被传递给部分。 So the model binder is looking for "Street" etc, not as part of an Address object.
所以 model 活页夹正在寻找“街道”等,而不是作为地址 object 的一部分。
I could pass the object from each page the partial is on, and prefix "Address."我可以从部分所在的每个页面传递 object,并添加前缀“地址”。 to each field name, but Landlord, Contractor, Tenant etc are all different classes so I'd need a different partial per page which defeats the point.
到每个字段名称,但房东、承包商、租户等都是不同的类,所以我需要每页有不同的部分,这违背了这一点。
I might be able to use a base class with Address, then derive all the other classes from that, and bind the base class to the partial?我也许可以使用带有地址的基础 class,然后从中派生所有其他类,并将基础 class 绑定到部分? But that seems like overkill just to get a partial working.
但这似乎只是为了部分工作而过大。
I could flatten the Address object into each ViewModel - this would create significantly more work when writing to the database though (you can't just pass Dapper an Address model, you'll have to manually write some SQL for the update), and create lots of repetition.我可以将地址 object 展平到每个 ViewModel 中——尽管这样在写入数据库时会产生更多的工作(你不能只将地址 model 传递给 Dapper,你必须手动编写一些 Z9778840A01010CB30C982Z876 更新)很多重复。
How can I re-use a partial between all the pages, keep it DRY, and avoid the listed problems.如何在所有页面之间重复使用部分,保持干燥,并避免列出的问题。
I've googled it and the above is all I could find.我已经用谷歌搜索过了,以上就是我能找到的所有内容。 Am I missing something?
我错过了什么吗?
when the form is posted, each address field is posted flat, as the names of the address are things like "Street", not "Address.Street" - because the address model is passed to the partial.
当表单发布时,每个地址字段都是平铺的,因为地址的名称是“Street”,而不是“Address.Street” - 因为地址 model 被传递给部分。 So the model binder is looking for "Street" etc, not as part of an Address object.
所以 model 活页夹正在寻找“街道”等,而不是作为地址 object 的一部分。
To fix it, you can try following approaches.要修复它,您可以尝试以下方法。
Approach 1 : set HtmlFieldPrefix with "Address"
in _AddressPartial.cshtml
as below.方法 1 :在_AddressPartial.cshtml中使用
"Address"
设置_AddressPartial.cshtml
,如下所示。
@model Address
@{
Html.ViewData.TemplateInfo.HtmlFieldPrefix = "Address";
}
<div class="form-group">
<label asp-for="City" class="control-label"></label>
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Street" class="control-label"></label>
<input asp-for="Street" class="form-control" />
<span asp-validation-for="Street" class="text-danger"></span>
</div>
@*other input fields*@
Approach 2 : implement a custom model binder to bind data to Street
etc properties.方法 2 :实现自定义 model绑定器将数据绑定到
Street
等属性。
Address class地址 class
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}
Custom model binder AddressBinder
自定义 model 绑定器
AddressBinder
// code logic here
// ...
var model = new Address();
if (bindingContext.ValueProvider.GetValue("City").FirstOrDefault() != null&& bindingContext.ValueProvider.GetValue("Street").FirstOrDefault() != null)
{
var city = bindingContext.ValueProvider.GetValue("City").FirstOrDefault();
var street = bindingContext.ValueProvider.GetValue("Street").FirstOrDefault();
model.City = city;
model.Street = street;
}
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
Apply it to Address
property将其应用于
Address
属性
[ModelBinder(BinderType = typeof(AddressBinder))]
public Address Address { get; set; }
Test and Result测试和结果
For approach 1:对于方法 1:
<div class="row">
<div class="col-md-4">
<form asp-action="NewContractor">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Cname" class="control-label"></label>
<input asp-for="Cname" class="form-control" />
<span asp-validation-for="Cname" class="text-danger"></span>
</div>
<partial name="_AddressPartial" model="@Model" />
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
For approach 2:对于方法 2:
public class Landlord
{
public string Name { get; set; }
[ModelBinder(BinderType = typeof(AddressBinder))]
public Address Address { get; set; }
}
I'm a bit late to the party, but I think you should use the attribute for
instead of model
in the partial
element, similarly to:我参加聚会有点晚了,但我认为您应该在
partial
元素中使用属性for
而不是model
,类似于:
<partial name="_AddressPartial" for="@Model.Address" />
Assuming Model.Address
is a property that stores an instance of your shared Address
class.假设
Model.Address
是一个存储共享Address
class 实例的属性。 Thus, ASP.NET Core will properly map the fields' name with the prefix Address
.因此, ASP.NET 核心将正确地 map 带有前缀
Address
的字段名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.