Html.TextBoxForの条件に基づいて無効化属性を設定します


81

以下のようにasp.netMVCのHtml.TextBoxForの条件に基づいて無効化属性を設定したい

@Html.TextBoxFor(model => model.ExpireDate, new { style = "width: 70px;", maxlength = "10", id = "expire-date" disabled = (Model.ExpireDate == null ? "disable" : "") })

このヘルパーには、disabled = "disabled"またはdisabled = ""の2つの出力があります。両方のテーマでテキストボックスが無効になります。

Model.ExpireDate == nullの場合はテキストボックスを無効にしたい、それ以外の場合は有効にしたい


ここで私の答えを見てください:stackoverflow.com/a/43131930/6680521
Extragorey 2017年

回答:


85

有効な方法は次のとおりです。

disabled="disabled"

ブラウザも受け入れる かもしれませんdisabled=""が、最初のアプローチをお勧めします。

そうは言っても、この無効化機能を再利用可能なコードにカプセル化するために、カスタムHTMLヘルパーを作成することをお勧めします。

using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;

public static class HtmlExtensions
{
    public static IHtmlString MyTextBoxFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TProperty>> expression, 
        object htmlAttributes, 
        bool disabled
    )
    {
        var attributes = new RouteValueDictionary(htmlAttributes);
        if (disabled)
        {
            attributes["disabled"] = "disabled";
        }
        return htmlHelper.TextBoxFor(expression, attributes);
    }
}

あなたはこのように使うことができます:

@Html.MyTextBoxFor(
    model => model.ExpireDate, 
    new { 
        style = "width: 70px;", 
        maxlength = "10", 
        id = "expire-date" 
    }, 
    Model.ExpireDate == null
)

そして、このヘルパーにさらに多くのインテリジェンスをもたらすことができます。

public static class HtmlExtensions
{
    public static IHtmlString MyTextBoxFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        object htmlAttributes
    )
    {
        var attributes = new RouteValueDictionary(htmlAttributes);
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        if (metaData.Model == null)
        {
            attributes["disabled"] = "disabled";
        }
        return htmlHelper.TextBoxFor(expression, attributes);
    }
}

これで、無効な状態を指定する必要がなくなりました。

@Html.MyTextBoxFor(
    model => model.ExpireDate, 
    new { 
        style = "width: 70px;", 
        maxlength = "10", 
        id = "expire-date" 
    }
)

Model.ExpireDate == nullの場合はテキストボックスを無効にしたい、それ以外の場合は有効にしたい
Ghooti Farangi 2011

4
このソリューションは素晴らしいです-それが行く限り...しかし、無効な属性(TextBoxFor、TextAreaFor、CheckBoxForなど)を持つ可能性のあるすべてのHtmlHelperの周りにラッパーを配置する必要がないクリーンなソリューションを見つけるのは素晴らしいことです。)理想的には、既存のものとインラインで機能するもの。基本的に匿名オブジェクトをラップしてRouteValueDictionaryを返すだけのソリューションを構築しましたが、特にクリーンな感じはしません。
ミール

3
「disabled」、「disabled =」、「disabled = 'disabled'」はすべてhtmlで等しく有効であり、短いものは異なるブラウザでのみ受け入れられる可能性があると言うのは誤解を招きます(そして誤りです)。Cf. dev.w3.org/html5/markup/syntax.html#syntax-attr-empty
Shautieh

53

実際、内部動作は匿名オブジェクトを辞書に変換しています。したがって、これらのシナリオで私が行うことは、辞書を探すことです。

@{
  var htmlAttributes = new Dictionary<string, object>
  {
    { "class" , "form-control"},
    { "placeholder", "Why?" }        
  };
  if (Model.IsDisabled)
  {
    htmlAttributes.Add("disabled", "disabled");
  }
}
@Html.EditorFor(m => m.Description, new { htmlAttributes = htmlAttributes })

または、スティーブンがここでコメントしたように

@Html.EditorFor(m => m.Description,
    Model.IsDisabled ? (object)new { disabled = "disabled" } : (object)new { })

@ Html.EditorFor(m => m.Description、Model.IsDisabled?(object)new {disabled = "disabled"} :( object)new {})=>これが最善の方法のようです。ありがとう
カーマインチェッカー

23

ダリン方式が好きです。しかし、これを解決する簡単な方法は、

Html.TextBox("Expiry", null, new { style = "width: 70px;", maxlength = "10", id = "expire-date", disabled = "disabled" }).ToString().Replace("disabled=\"disabled\"", (1 == 2 ? "" : "disabled=\"disabled\""))

1
これを@ Html.Raw()で囲む必要があると思います
ShadiNamrouti18年

14

私が使用した簡単なアプローチの1つは、条件付きレンダリングです。

@(Model.ExpireDate == null ? 
  @Html.TextBoxFor(m => m.ExpireDate, new { @disabled = "disabled" }) : 
  @Html.TextBoxFor(m => m.ExpireDate)
)

13

htmlヘルパーを使用しない場合は、次のような単純な3項式を使用できます。

<input name="Field"
       value="@Model.Field" tabindex="0"
       @(Model.IsDisabledField ? "disabled=\"disabled\"" : "")>

13

私はいくつかの拡張メソッドを使用してそれを達成しました

private const string endFieldPattern = "^(.*?)>";

    public static MvcHtmlString IsDisabled(this MvcHtmlString htmlString, bool disabled)
    {
        string rawString = htmlString.ToString();
        if (disabled)
        {
            rawString = Regex.Replace(rawString, endFieldPattern, "$1 disabled=\"disabled\">");
        }

        return new MvcHtmlString(rawString);
    }

    public static MvcHtmlString IsReadonly(this MvcHtmlString htmlString, bool @readonly)
    {
        string rawString = htmlString.ToString();
        if (@readonly)
        {
            rawString = Regex.Replace(rawString, endFieldPattern, "$1 readonly=\"readonly\">");
        }

        return new MvcHtmlString(rawString);
    }

その後....

@Html.TextBoxFor(model => model.Name, new { @class= "someclass"}).IsDisabled(Model.ExpireDate == null)

rawstring.Length -2 for 7を変更し、最後の後に「」を追加すると機能します。
JozefKrchňavý 2017年

TextAreaForでは機能しません。すべての種類の入力タイプのソリューションが必要です
erhan3 5519年

10

これは遅いですが、一部の人には役立つかもしれません。

@DarinDimitrovの回答を拡張して、次のようなブールhtml属性をいくつでも取る2番目のオブジェクトを渡すことができるようにしました。 disabled="disabled" checked="checked", selected="selected" etcなどの。

プロパティ値がtrueの場合にのみ属性がレンダリングされ、それ以外の場合は属性がまったくレンダリングされません。

カスタムの再利用可能なHtmlHelper:

public static class HtmlExtensions
{
    public static IHtmlString MyTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
                                                                Expression<Func<TModel, TProperty>> expression,
                                                                object htmlAttributes,
                                                                object booleanHtmlAttributes)
    {
        var attributes = new RouteValueDictionary(htmlAttributes);

        //Reflect over the properties of the newly added booleanHtmlAttributes object
        foreach (var prop in booleanHtmlAttributes.GetType().GetProperties())
        {
            //Find only the properties that are true and inject into the main attributes.
            //and discard the rest.
            if (ValueIsTrue(prop.GetValue(booleanHtmlAttributes, null)))
            {
                attributes[prop.Name] = prop.Name;
            }                
        }                                

        return htmlHelper.TextBoxFor(expression, attributes);
    }

    private static bool ValueIsTrue(object obj)
    {
        bool res = false;
        try
        {
            res = Convert.ToBoolean(obj);
        }
        catch (FormatException)
        {
            res = false;
        }
        catch(InvalidCastException)
        {
            res = false;
        }
        return res;
    }

}

あなたはそのように使うことができます:

@Html.MyTextBoxFor(m => Model.Employee.Name
                   , new { @class = "x-large" , placeholder = "Type something…" }
                   , new { disabled = true})

10

RouteValueDictionary(IDictionaryに基づいているためhtmlAttributesとして正常に機能します)と拡張メソッドを使用してこれを解決します:

public static RouteValueDictionary AddIf(this RouteValueDictionary dict, bool condition, string name, object value)
{
    if (condition) dict.Add(name, value);
    return dict;
}

使用法:

@Html.TextBoxFor(m => m.GovId, new RouteValueDictionary(new { @class = "form-control" })
.AddIf(Model.IsEntityFieldsLocked, "disabled", "disabled"))

クレジットはhttps://stackoverflow.com/a/3481969/40939に移動します


IMHO、これが最良の答えです
JenonD

6

Html Helpersを使用したくない場合は、私のソリューションを見てください

disabled="@(your Expression that returns true or false")"

そのこと

@{
    bool isManager = (Session["User"] as User).IsManager;
}
<textarea rows="4" name="LetterManagerNotes" disabled="@(!isManager)"></textarea>

それを行うためのより良い方法は、コントローラーでそのチェックを行い、ビュー(Razorエンジン)内でアクセス可能な変数内に保存して作成することだと思います the view free from business logic


7
コントロールでdisabled属性を使用すると、属性の値に関係なく、コントロールは無効になります。値のない属性が存在する場合でも、コントロールは無効になります。
オタクガイ2016

2
この解決策は非常にうまく機能し、反対派は表現がブール値であることを見逃しているのではないかと思います。式がブール値の場合、disabled属性は、式がtrueの場合はdisabled = "disabled"としてレンダリングされ、falseの場合は完全に省略されます。それはまさにあなたが望むものです。
カルステン

これにより、disabled = "false"またはdisabled = "true"がレンダリングされます。
アンデス2018年

4

さらに別の解決策は、Dictionary<string, object>呼び出す前に作成してTextBoxForその辞書を渡すことです。辞書で"disabled"、テキストボックスを無効にする場合にのみキーを追加します。最も良い解決策ではありませんが、シンプルで簡単です。


2

別のアプローチは、クライアント側のテキストボックスを無効にすることです。

無効にする必要のあるテキストボックスは1つだけですが、無効にする必要のない複数のinput、select、およびtextareaフィールドがある場合を考えてみてください。

jquery +を介して行う方がはるかに簡単です(クライアントからのデータに依存できないため)これらのフィールドが保存されないように、コントローラーにロジックを追加します。

次に例を示します。

<input id="document_Status" name="document.Status" type="hidden" value="2" />

$(document).ready(function () {

    disableAll();
}

function disableAll() {
  var status = $('#document_Status').val();

  if (status != 0) {
      $("input").attr('disabled', true);
      $("textarea").attr('disabled', true);
      $("select").attr('disabled', true);
  }
}

0

私は拡張メソッドのアプローチが好きなので、考えられるすべてのパラメーターを渡す必要はありません。
ただし、正規表現の使用は非常に難しい(そして多少遅くなる)可能性があるため、XDocument代わりに次を使用しました。

public static MvcHtmlString SetDisabled(this MvcHtmlString html, bool isDisabled)
{
    var xDocument = XDocument.Parse(html.ToHtmlString());
    if (!(xDocument.FirstNode is XElement element))
    {
        return html;
    }

    element.SetAttributeValue("disabled", isDisabled ? "disabled" : null);
    return MvcHtmlString.Create(element.ToString());
}

次のような拡張方法を使用します。
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.