MVC 3:有条件地使用HtmlHelpers添加Disabled属性


73

我有一个ASP.Net MVC 3 Web应用程序,并且正在使用HtmlHelper类向视图页面添加一个复选框,如下所示:

@Html.CheckBox("CheckBox1", true, new { @class = "Class1" })

我想做的是有条件地基于视图状态属性添加禁用的属性。基本上,以下将是理想的...

@Html.CheckBox("CheckBox1", true, new { @class = "Class1", @disabled = Model.ReadOnly })

不幸的是,由于禁用属性的性质,这将不起作用,因为分配给禁用属性的任何值(甚至是“ false”)都将转换为true。

我已经想到了一些解决此问题的方法,所以问题不在于我该怎么做。但是,有没有像上面所需的方法这样的简单方法?还是我必须采取以下措施之一?

我知道我能做的...

  1. 创建一个if / else语句并写入不同的Html.CheckBox行(对于可读性不是很好-可能会抛出标记警告-不确定)

  2. 跳过HtmlHelper类,然后手写标记以提供更好的条件属性(使代码保持较短,但会增加不一致性)

  3. 创建一个带有“ disabled”参数的自定义帮助程序(最干净的解决方案,但需要不需要的额外方法-到目前为止可能是最好的选择)


在这里看看我的答案(使用您列出的第三种方法):stackoverflow.com/a/43131930/6680521
Extragorey,2017年

Answers:


53

在您的视图/助手中的某个地方定义

@functions {
 object getHtmlAttributes (bool ReadOnly, string CssClass) 
 {
     if (ReadOnly) {
         return new { @class = CssClass, @readonly = "readonly" };
     }
     return new { @class = CssClass };
 }
}

然后使用:

@Html.TextBox("name", "value", @getHtmlAttributes(Model.ReadOnly, "test"))

好答案。我最终做了相同的逻辑,只是在Html.CheckBox调用中使用了一行(三进制)条件。您的解决方案要好得多,谢谢;)
musefan

谢谢,作为参考,我怀疑更好的方法是为模型定义一个EditorTemplate,在内部定义函数,并提供某种客户端jQuery魔术来完成所有工作。例如,在包含DIV的Load事件上。
BigMike 2011年

1
mmm ..当我将其与.TextBoxFor()(而不是.TextBox())一起使用时,上述示例不起作用-匿名类型投影初始化应为简单名称或成员访问表达式...
2014年

如何为添加disable可选做同样的事情?
Juan Carlos Oropeza

只需在函数中添加一个布尔参数,并相应地设置@readonly的值即可。我已经失去了与.NET MVC的联系,所以真的不知道此答案是否仍适用于最新版本(我希望他们添加了一些更好的方法来执行此操作)。
BigMike

33

这是我对类似问题的回答:https : //stackoverflow.com/a/13922813/495000


我创建了以下帮助器-它需要一个布尔值和一个匿名对象。如果disabled为true,则将其disabled属性添加到值为“ disabled”的匿名对象(实际上是一个Dictionary),否则根本不添加该属性。

public static RouteValueDictionary ConditionalDisable(
   bool disabled, 
   object htmlAttributes = null)
{
   var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

   if (disabled)
      dictionary.Add("disabled", "disabled");

   return dictionary;
}

一个实际的例子:

@Html.TextBoxFor(m => m.SomeProperty,    
   HtmlHelpers.ConditionalDisable(true, new { @class = "someClass"))

对我而言,此方法的一个巨大优势是,它几乎可以与所有MVC HtmlHelper一起使用,因为它们都具有接受RouteValueDictionary而不是匿名对象的重载。

警告
HtmlHelper.AnonymousObjectToHtmlAttributes()使用一些有趣的代码忍者工作来完成任务。我不完全确定它的性能如何……但是对于我的用途来说已经足够了。你的旅费可能会改变。

我不太喜欢它的名字-但我无法提出更好的选择。重命名很容易。

我也不喜欢用法语法-但我再也想不出更好的方法了。改变应该不难。在对象上使用扩展方法是一个主意……您最终会得到,new { @class = "someClass" }.ConditionalDisable(true)但是如果您只想要disable属性并且没有其他要添加的内容,则最终会得到类似的结果,new {}.ConditionalDisable(true);并且您最终还会得到扩展所有人都可以看到的方法object...这可能是不可取的。


一个最优雅的解决方案。这是我发现的最好的。我之前曾考虑过扩展方法,但它太笼统了。
Anon343224user 2014年

这是一个很好的解决方案,但我似乎无法将其与Html.ActionLink得到工作
夏兰加拉格尔

良好的解决方案,但它不与Html.EditorFor工作,以及
Dark_Knight

12

如果您想要更简洁的语法而不需要帮助程序功能,则可以在定义用于@ HTML.Checkbox帮助程序的html属性的字典时使用三元语句。

@Html.CheckBox("CheckBox1", true, Model.ReadOnly 
       ? new { @class = "Class1", @disabled = Model.ReadOnly } 
       : null)

在这种情况下,Model.ReadOnly为false,则将null作为html属性的字典传递。


7
如果要设置其他属性,这可能会变得很冗长。
ScottE 2014年

@ScottE不能然后在视图[模型]上设置一个为您完成所有繁重计算的属性吗?然后在cshtml中,就像上面的示例一样简单。
甘德斯

1
如果您仍想将@class属性设置为false,则此方法将无效。
Jaxidian

3

对我来说,执行禁用属性客户端的添加是可行的。请注意,您应该检查允许在服务器端编辑哪些字段,但是对于禁用属性也被装饰性声明的情况,这是正确的。

在此示例中,我使用jQuery禁用了表单的所有子项。

    if (Model.CanEdit)
    {
        <script type="text/javascript">

            $(document).ready(function() {

                $('#editForm *').attr('disabled', true);
            });

        </script>
    }

2

您如何看待我的简单解决方案?它可以很容易地与两种可能的HtmlAttributes类型一起使用:

  • Dictionary<string, object>
  • Anonymous Object

首先,将以下简单代码添加extension class到您的项目中:

public static class HtmlAttributesExtensions
{
    public static IDictionary<string, object> AddHtmlAttrItem(this object obj, string name, object value, bool condition)
    {
        var items= !condition ? new RouteValueDictionary(obj) : new RouteValueDictionary(obj) {{name, value}};
        return UnderlineToDashInDictionaryKeys(items);
    }
    public static IDictionary<string, object> AddHtmlAttrItem(this IDictionary<string, object> dictSource, string name, object value, bool condition)
    {
        if (!condition)
            return dictSource;

        dictSource.Add(name, value);
        return UnderlineToDashInDictionaryKeys(dictSource);
    }
    private static IDictionary<string, object> UnderlineToDashInDictionaryKeys(IDictionary<string,object> items)
    {
        var newItems = new RouteValueDictionary();
        foreach (var item in items)
        {
            newItems.Add(item.Key.Replace("_", "-"), item.Value);
        }
        return newItems;
    }
}

现在显示:

Example1 HtmlAttributes输入为Anonymous Object

@{
  var hasDisabled=true; 
}

@Html.CheckBox("CheckBox1"
              , true
              , new { @class = "Class1"}
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.

示例2 HtmlAttributes输入为Dictionary<string, object>

@Html.CheckBox("CheckBox1"
              , true
              , new Dictionary<string, object> { { "class", "Class1" }
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.

现在,只需将hasDisabled值更改为trueor即可false


示例3 (多个条件属性)

@{
  var hasDisabled=true;
  var hasMax=false ;
  var hasMin=true ;
}

@Html.CheckBox("CheckBox1"
              , true
              , new { @class = "Class1"}
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled)
               .AddHtmlAttrItem("data-max", "100", hasMax)
               .AddHtmlAttrItem("data-min", "50", hasMin))
.

1
太好了,谢谢!但有一条评论:我建议使用HtmlHelper.AnonymousObjectToHtmlAttributes而不是,UnderlineToDashInDictionaryKeys因为它已经内置。;)
Rami

1
@Html.TextBoxFor(m => m.FieldName, Html.FixBoolAttributes(new {
    @class = "myClass",
    @readonly = myFlag  
}))


public static class BooleanAttributeFix
{
    /// <summary>
    /// Normalises HTML boolean attributes so that readonly=true becomes readonly="readonly" and
    /// readonly=false removes the attribute completely.
    /// </summary>
    /// <param name="htmlHelper"></param>
    /// <param name="htmlAttributes"></param>
    /// <returns></returns>
    public static RouteValueDictionary FixBoolAttributes(this HtmlHelper htmlHelper, object htmlAttributes)
    {
        var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

        foreach(var attrName in new[] { "disabled", "readonly" })
        {
            object value;
            if(attrs.TryGetValue(attrName, out value))
            {
                if(isTruthy(value))
                {
                    // Change from readonly="true" to readonly="readonly"
                    attrs[attrName] = attrName; 
                }
                else
                {
                    // Remove attribute entirely
                    attrs.Remove(attrName); 
                }
            }
        }
        return attrs;
    }

    /// <summary>
    /// Apply similar loose rules like javascript does for whether a value is true or not.
    /// e.g. 1 = true, non-empty string = true and so on.
    /// </summary>
    /// <param name="val"></param>
    /// <returns></returns>
    private static bool isTruthy(object val)
    {   
        if(val == null)
            return false;

        if(val is string)
        {
            return !String.IsNullOrEmpty((string)val);
        }

        Type t = val.GetType();

        if(t.IsValueType && Nullable.GetUnderlyingType(t) == null)
        {
            // If a non-nullable value type such as int we want to check for the
            // default value e.g. 0.
            object defaultValue = Activator.CreateInstance(t);

            // Use .Equals to compare the values rather than == as we want to compare
            // the values rather than the boxing objects.
            // See http://stackoverflow.com/questions/6205029/comparing-boxed-value-types
            return !val.Equals(defaultValue);
        }

        return true;
    }
}

0

我喜欢@ gb2d答案,这是在JS中使用的getElementsByClassName从这里获取的 getElementByClass()。setAttribute不起作用

<script type="text/javascript">
    var list, index;
    list = document.getElementsByClassName("form-control");
    for (index = 0; index < list.length; ++index) {
        list[index].setAttribute('disabled', true);
    }
</script>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.