MVC 3: условное добавление отключенного атрибута с помощью HtmlHelpers - PullRequest
67 голосов
/ 02 ноября 2011

У меня есть веб-приложение ASP.Net MVC 3, и я добавляю флажок на страницу просмотра с помощью класса HtmlHelper, например так:

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

Что я хочу сделать, это условнодобавить отключенный атрибут на основе свойства состояния представления.По существу, следующее было бы идеально ...

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

К сожалению, из-за природы атрибута disabled это не будет работать, поскольку любое значение , назначенное дляатрибут disabled (даже «false») будет переведен как true.

Я уже думал о нескольких решениях, чтобы обойти эту проблему, поэтому вопрос не в том, как я могу это сделать.Но есть ли такой простой способ, как желаемый метод выше?или я должен прибегнуть к одному из следующих? ..

Что я знаю, я мог бы сделать ...

  1. Создать оператор if / else и написать вразличные Html.CheckBox строки (не очень удобны для чтения - и возможно с выдачей предупреждения о разметке - не уверен)

  2. Пропустите класс HtmlHelper и вручную напишите тег, позволяющий улучшить условные атрибуты(сокращает код, но добавляет несоответствия)

  3. Создайте пользовательский помощник, который принимает параметр «отключен» (самое чистое решение, но требует нежелательных дополнительных методов - вероятно, лучший вариант на данный момент)хотя)

Ответы [ 6 ]

48 голосов
/ 02 ноября 2011

Определите это где-то на ваш взгляд / помощники

@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"))
31 голосов
/ 18 декабря 2012

Вот мой ответ на этот похожий вопрос: https://stackoverflow.com/a/13922813/495000


Я создал следующий Помощник - он принимает логический и анонимный объект.Если значение disabled равно true, он добавляет атрибут disabled в анонимный объект (который на самом деле является словарем) со значением «disabled», в противном случае он вообще не добавляет свойство.

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 HtmlHelpers, поскольку все они имеют перегрузки, которые принимают RouteValueDictionary вместо анонимного объекта.

Предостережения :
HtmlHelper.AnonymousObjectToHtmlAttributes() использует некоторую причудливую работу над ниндзя для достижения цели.Я не совсем уверен, насколько он эффективен ... но этого было достаточно для того, для чего я его использую.Ваш пробег может варьироваться.

Мне не особенно нравится его название, но я не мог придумать ничего лучшего.Переименовать легко.

Мне также не нравится синтаксис использования - но опять же я не мог придумать ничего лучшего.Это не должно быть сложно изменить.Один из методов расширения объекта - одна идея ... вы получите new { @class = "someClass" }.ConditionalDisable(true), но тогда, если вам нужен только атрибут disable и у вас нет ничего дополнительного, вы получите что-то грубое, например new {}.ConditionalDisable(true);, и вытакже в конечном итоге метод расширения, который отображается для всех object ... что, вероятно, не желательно.

10 голосов
/ 25 июня 2013

Если вам нужен более краткий синтаксис без использования вспомогательной функции, вы можете использовать троичный оператор при определении словаря, используемого для атрибутов html вспомогательного средства @ HTML.Checkbox ...

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

Inв этом случае Model.ReadOnly имеет значение false, значение NULL передается как словарь атрибутов HTML.

1 голос
/ 08 сентября 2016

Что вы думаете о моем простом решении?Он легко работает с обоими возможными 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 на true или false!


Example3 (несколько условных свойств)

@{
  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 голос
/ 09 сентября 2015
@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 /4304755/sravnenie-tipov-v-shtuchnoi-upakovke
            return !val.Equals(defaultValue);
        }

        return true;
    }
}
1 голос
/ 05 июля 2013

Выполнение добавления отключенного атрибута на стороне клиента работает для меня. Обратите внимание, что вы должны проверить, какие поля разрешено редактировать на стороне сервера, но это верно для случаев, когда атрибут disabled также объявлен декоративно.

В этом примере я отключил всех детей формы с помощью jQuery.

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

            $(document).ready(function() {

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

        </script>
    }
...