以编程方式确定要在页面上输出的 html 元素类型 - 此逻辑应位于何处

本文关键字:类型 元素 于何处 html 方式确 编程 输出 | 更新日期: 2023-09-27 18:32:11

我有一个下拉列表,表示与文档相关的各种"属性"字段。例如,文档可以具有"标签"字段,该字段需要一个文本框才能在其中输入标签。或者它可能有一个位置字段,这将具有用户可以选择的各种位置类型的预填充下拉列表。或者它可能是一个截止日期字段,我们有一个自定义日期选择器的东西,我们用于选择日期。

我的问题:我想在我的控制器操作中声明一个 HtmlHelper,该操作在选择适当的属性字段时触发。我会针对 Attribute.Type 进行切换,并根据类型,我会在我的视图模型中返回要在视图中呈现的适当 html。如果我这样做,我可以对我的 switch 语句进行单元测试。

我读到了很多,在控制器中声明 HtmlHelper 是一个坏主意。我能理解这种情绪——有没有更好的方法可以做到这一点?我想尽可能避免逻辑,因为我根本无法对其进行单元测试。

我看到的另一种方法是在视图模型中传递 Attribute.Type,并在视图上执行切换逻辑以确定要调用哪个 HtmlHelper 方法。这是要走的路吗?提前谢谢。

编辑:我说的是想在代码隐藏中做这样的事情。我的单元测试会断言反对viewModel.FieldHtml。我听到的是,我应该把它放在另一个类中,让控制器调用它。但这是它在控制器中的样子。它只是伪代码,所以它并不完美,但它是为了给我所要求的内容提供上下文。

public ActionResult GetValueInput(Guid attributeFieldUid)
{
    //you have to pass some stuff into the constructor but essentially this
    HtmlHelper html = new HtmlHelper();
    AttributeField field = GetAttributeFieldFromDb(attributeFieldUid);
    AttributeViewModel viewModel = new AttributeViewModel();
    switch(field.type)
    {
        case Dropdown:
            viewModel.FieldHtml = html.DropDownList();
            break;
        case Text:
            viewModel.FieldHtml = html.TextBox();
            break;
        case Date:
            // our own extension method
            viewModel.FieldHtml = html.OurDatePicker();
            break;
    }
}

我最初看到的另一个选项基本上是在剃刀视图上执行此 switch 语句。但我想我喜欢在控制器调用最多的单独类中执行此操作的想法。

这实际上是一个设计问题 - 我问什么实现它的方法最有意义?

以编程方式确定要在页面上输出的 html 元素类型 - 此逻辑应位于何处

您可以为此编写一个自定义 HTML 帮助程序。因此,控制器操作将负责填充视图模型并将其传递给视图:

public ActionResult GetValueInput(Guid attributeFieldUid)
{
    AttributeField field = GetAttributeFieldFromDb(attributeFieldUid);
    AttributeViewModel viewModel = new AttributeViewModel();
    viewModel.FieldType = field.type;
    return View(viewModel);
}

然后编写一个帮助程序:

public static class HtmlExtensions
{
    public static IHtmlString Field(this HtmlHelper html, FieldType type)
    {
        switch(field.type)
        {
            case Dropdown:
                return html.DropDownList(... you will probably need some more info on your view model to be passed here to generate a dropdown)
            case Text:
                return html.TextBox(...);
            case Date:
                return html.OurDatePicker();
        }
        return MvcHtmlString.Empty;
    }
}

此帮助程序将用于以下视图:

@model AttributeViewModel
@Html.Field(Model.FieldType)

另一种可能性是使用编辑器模板。下面是一个示例。

嗯,

听起来像是AOP的工作。

这很简单,创建一个自定义属性,您可以在其中指定字段的类型以及所需的任何其他参数。

public class CustomAttribute : Attribute
{
    private readonly FieldType _fieldType;
    public CustomAttribute(FieldType fieldType)
    {
        _fieldType = fieldType;
    }
    public FieldType FieldType { get { return _fieldType; } }
}

并在视图模型上注释属性,例如。

[Custom(FieldType.CheckBox)]
public int SomeField { get; set; }

然后编写一个 html 帮助程序扩展方法,例如。

public static class CustomHtmlHelperExtensions
{
    public MvcHtmlString CustomControlFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel,TProperty>> memberExpression)
    {
        var member = ((MemberExpression)model.Body).Member;
        var customAttribute = member.GetAttributes().OfType<CustomAttribute>().Cast<CustomAttribute>().SingleOrDefault();
        if(customAttribute == null)
        //Perform certain logic if the property doesn't have the attribute specified
        //ex. return null;
        switch(customAttribute.FieldType)
        {
            case FieldType.TextBox: 
                {
                    //Do something
                    return htmlHelper.TextBoxFor(memberExpression);
                }
            default: break;
        }
        return null;
    }
}

这至少应该让你开始:)