web-dev-qa-db-ja.com

MVC 3:HtmlHelpersを使用した無効な属性の条件付き追加

ASP.Net MVC 3 Webアプリケーションがあり、次のようにHtmlHelperクラスを使用してビューページにチェックボックスを追加しています...

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

私がやりたいのは、ビューステートプロパティに基づいて条件付きでdisabled属性を追加することです。基本的には次のことが理想的です...

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

残念ながら、disabled属性の性質により、これは機能しませんany無効属性に割り当てられた値(偶数「false」)はtrueとして翻訳されます。

私はすでにこの問題を回避するためのいくつかの解決策を考えていたので、問題はどうすればできるのかではありません。むしろ、上記の望ましい方法のような簡単な方法はありますか?または、次のいずれかに頼らなければなりませんか?..

私ができると知っていること...

  1. If/elseステートメントを作成し、別のHtml.CheckBox行に書き込みます(読みやすさには向いていません-マークアップ警告がスローされる可能性があります-不明)

  2. HtmlHelperクラスをスキップし、条件付き属性を改善できるタグを手書きで記述します(コードは短くなりますが、一貫性が失われます)。

  3. 「disabled」パラメーターを使用するカスタムヘルパーを作成します(最もクリーンなソリューションですが、望ましくない追加のメソッドが必要です-これまでのところ最良のオプションです)

69
musefan

これをビュー/ヘルパーのどこかで定義します

@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"))
50
BigMike

この同様の質問からの私の答えは次のとおりです。 https://stackoverflow.com/a/13922813/4950


次のヘルパーを作成しました-ブール値と匿名オブジェクトを取ります。 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"))

私にとってこのアプローチの大きな利点の1つは、匿名オブジェクトではなくRouteValueDictionaryを受け入れるオーバーロードがあるため、ほぼすべてのMVC HtmlHelperで動作することです。

警告
HtmlHelper.AnonymousObjectToHtmlAttributes()は、巧妙なコード忍者の仕事を使って物事を成し遂げます。私はそれがどれほどパフォーマンスが良いのか完全にはわかりません...しかしそれは私がそれを使用するために十分です。あなたのマイレージは異なる場合があります。

私は特にその名前が好きではありません-しかし、私はより良いものを思い付くことができませんでした。名前の変更は簡単です。

使用法の構文も好きではありませんが、これ以上良いものは思いつきませんでした。変更するのは難しくないはずです。オブジェクトの拡張メソッドは1つのアイデアです... new { @class = "someClass" }.ConditionalDisable(true)になってしまいますが、disable属性のみが必要で、追加するものがない場合は、new {}.ConditionalDisable(true);を使用すると、すべてのobject...に対して表示される拡張メソッドになりますが、これはおそらく望ましくありません。

31
Mir

ヘルパー関数を必要とせずに、より簡潔な構文が必要な場合は、@ HTML.Checkboxヘルパーのhtml属性に使用される辞書を定義するときに、三項ステートメントを使用できます...

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

この場合、Model.ReadOnlyはfalseであり、html属性の辞書としてnullが渡されます。

10
Andy Brudtkuhl

無効化された属性のクライアント側の追加を実行すると、私にとってはうまくいきます。サーバー側で編集できるフィールドを確認する必要がありますが、無効な属性が装飾的に宣言されている場合も同様です。

この例では、jQueryを使用してフォームのすべての子を無効にしました。

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

            $(document).ready(function() {

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

        </script>
    }
1
gb2d
@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;
    }
}
1
Alan Singfield

私のsimpleソリューションについてどう思いますか?可能な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;
    }
}

表示中:

例1HtmlAttributes typeとしてAnonymous Object

@{
  var hasDisabled=true; 
}

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

例2HtmlAttributes type as Dictionary<string, object>

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

hasDisabled値をtrueまたはfalseに変更するだけです!


(複数の条件付きプロパティ)

@{
  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
RAM