扩展为输入标签助手的部分

时间:2020-09-30 17:43:55

标签: c# asp.net-core asp.net-core-mvc

本书 Pro ASP.NET Core 3 的第27章示例中带有the following code

<div class="m-2">
    <h5 class="bg-primary text-white text-center p-2">HTML Form</h5>
    <form asp-page="FormHandler" method="post" id="htmlform">
        <div class="form-group">
            <label>Name</label>
            <input class="form-control" asp-for="Product.Name" />
        </div>
        <div class="form-group">
            <label>Price</label>
            <input class="form-control" asp-for="Product.Price" />
        </div>
        <div class="form-group">
            <label>Category</label>
            <input class="form-control" asp-for="Product.Category.Name" />
        </div>
        <div class="form-group">
            <label>Supplier</label>
            <input class="form-control" asp-for="Product.Supplier.Name" />
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
    <button form="htmlform" asp-page="FormHandler" class="btn btn-primary mt-2">
        Sumit (Outside Form)
    </button>
</div>

如您所见,<div class="form-group>...</div>模式重复了四次。为了测试局部,我添加了文件Pages\_FormGroupPartial.cshtml

@model FormGroupParams

<div class="form-group">
    <label>@Model.LabelContent</label>
    <input class="form-control" asp-for="@Model.ForString" />
</div>

Pages\FormHandler.cshtml.cs中,我添加了以下课程:

public class FormGroupParams
{        
    public string LabelContent;
    public string ForString;

    public FormGroupParams(string labelContent, string forString)
    {
        LabelContent = labelContent;
        ForString = forString;
    }
}

为了对此进行测试,我编辑了Pages\FormHandler.cshtml以在原始方法之后立即使用新的部分:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" asp-for="Product.Supplier.Name" />
</div>

<partial name="_FormGroupPartial" model='new FormGroupParams("Supplier", "Product.Supplier.Name")' />

在结果页面中,我们看到partial并没有完全生成相同的代码。请注意,该值现在是Product.Supplier.Name,而不是预期的Splash Dudes

enter image description here

查看源代码,我们看到原始代码:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" asp-for="Product.Supplier.Name" />
</div>

扩展为:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" type="text" id="Product_Supplier_Name" name="Product.Supplier.Name" value="Splash Dudes" />
</div>

而我们的部分:

<partial name="_FormGroupPartial" model='new FormGroupParams("Supplier", "Product.Supplier.Name")' />

扩展为:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" type="text" id="ForString" name="ForString" value="Product.Supplier.Name" />
</div>

是否有一种很好的方法来实现此部分代码,以便获得与原始代码相同的输出?


更新2020-09-30

PeterG在下面的回答中提出以下建议:

<partial name="_FormGroupPartial" model='new FormGroupParams("Supplier", @Model.Product.Supplier.Name)' />

这扩展为以下内容:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" type="text" id="ForString" name="ForString" value="Splash Dudes" />
</div>

目标是:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" type="text" id="Product_Supplier_Name" name="Product.Supplier.Name" value="Splash Dudes" />
</div>

因此value现在正确。但是idname仍然关闭。

4 个答案:

答案 0 :(得分:1)

将变量绑定到输入标签帮助程序并使其被识别为相应的模型字段将非常复杂。

这将涉及输入标签帮助器的源代码,并考虑不同类型的输入。

我建议是在部分视图中的as-for之后直接添加名称和id属性,以覆盖原始生成的

调用局部视图时只需要传递一个额外的value参数:

代码如下:

Pages \ FormHandler.cshtml:

  <div class="form-group">
    <label>Supplier</label>
    <input class="form-control" asp-for="Product.Supplier.Name" />
</div>

          <partial name="_FormGroupPartial" 
    model='new FormGroupParams("Supplier","Product.Supplier.Name", @Model.Product.Supplier.Name)' />

Pages \ FormHandler.cshtml.cs:

 public class FormGroupParams
    {
        public string LabelContent;
        public string ForString;
        public string Value;
        public FormGroupParams(string labelContent, string forString, string value)
        {
            LabelContent = labelContent;
            ForString = forString;
            Value = value;
        }
    }

Pages_FormGroupPartial.cshtml:

@model FormGroupParams

<div class="form-group">
    <label>@Model.LabelContent</label>
    <input class="form-control" asp-for="@Model.Value" id="@Model.ForString.Replace(".","_")" name="@Model.ForString"  />
</div>

这是呈现的html:

enter image description here

答案 1 :(得分:0)

我认为问题是由于将“ Product.Supplier.Name”作为字符串值传递到局部模型的FormGroupParams对象中引起的。相反,您需要从模型传递Product.Supplier.Name属性的实际值。

类似这样的东西:

<partial name="_FormGroupPartial" model='new FormGroupParams("Supplier", @Model.Product.Supplier.Name)' />

答案 2 :(得分:0)

这本书的作者亚当·弗里曼(Adam Freeman)通过电子邮件向我提供了一个示例,演示了如何使用标签帮助程序解决此问题。

添加文件TagHelpers/FormGroupTagHelper.cs

using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

namespace WebApp.TagHelpers
{
    [HtmlTargetElement("form-group")]
    public class FormGroupTagHelper : TagHelper
    {
        public string Label { get; set; }
        public ModelExpression For { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            output.TagMode = TagMode.StartTagAndEndTag;
            output.Attributes.SetAttribute("class", "form-group");

            var label = new TagBuilder("label");
            label.InnerHtml.Append(Label ?? For.Name);
                        
            var input = new TagBuilder("input");
            input.AddCssClass("form-control");
            input.Attributes["type"] = "text";
            input.Attributes["id"] = For.Name.Replace(".", "_");
            input.Attributes["name"] = For.Name;
            input.Attributes["value"] = For.Model.ToString();
            
            output.Content.AppendHtml(label);
            output.Content.AppendHtml(input);
        }
    }
}

现在,用Pages/FormHandler.cshtml代替:

<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" asp-for="Product.Supplier.Name" />
</div>

您可以使用以下内容:

<form-group label="Supplier" for="Product.Supplier.Name"/>

感谢亚当!

答案 3 :(得分:0)

这是一种使用模板函数而不是部分函数的方法。

以下代码:


<div class="form-group">
    <label>Name</label>
    <input class="form-control" asp-for="Product.Name" />
</div>
<div class="form-group">
    <label>Price</label>
    <input class="form-control" asp-for="Product.Price" />
</div>
<div class="form-group">
    <label>Category</label>
    <input class="form-control" asp-for="Product.Category.Name" />
</div>
<div class="form-group">
    <label>Supplier</label>
    <input class="form-control" asp-for="Product.Supplier.Name" />
</div>

可以替换为:

@{ 
    await Template("Name",     "Product.Name");
    await Template("Price",    "Product.Price");
    await Template("Category", "Product.Category.Name");
    await Template("Supplier", "Product.Supplier.Name");
}

在 Razor 页面的开头给出以下模板函数:

@{ 
    async Task Template(string label, string str)
    {
        var expr = Model.CreateModelExpression(str);

        <div class="form-group">

            <label>@label</label>

            <input class="form-control" asp-for="@expr.Model" />

        </div>
    }
}

此处引用的 CreateModelExpression 方法在页面模型中定义:

public class FormHandlerModel : PageModel
{
    private ModelExpressionProvider _modelExpressionProvider { get; set; }

    private DataContext context;

    public FormHandlerModel(DataContext dbContext, ModelExpressionProvider modelExpressionProvider)
    {
        context = dbContext;
        _modelExpressionProvider = modelExpressionProvider;
    }

    public ModelExpression CreateModelExpression(string expr)
    {
        var dict = new ViewDataDictionary<FormHandlerModel>(ViewData);
        
        return _modelExpressionProvider.CreateModelExpression(dict, expr);
    }
    
    ...
}

请注意,ModelExpressionProvider 是通过依赖注入引入的。

github 上的上述 Razor 页面:link

上面github上的页面模型:link

欢迎就如何改进这一点提出建议!