Legen Sie das Deaktivierungsattribut basierend auf einer Bedingung für Html.TextBoxFor fest

81

Ich möchte das Deaktivierungsattribut basierend auf einer Bedingung für Html.TextBoxFor in asp.net MVC wie unten festlegen

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

Dieser Helfer hat zwei Ausgänge deaktiviert = "deaktiviert" oder deaktiviert = "". Bei beiden Themen wird das Textfeld deaktiviert.

Ich möchte das Textfeld deaktivieren, wenn Model.ExpireDate == null ist. Andernfalls möchte ich es aktivieren

Ghooti Farangi
quelle
Schauen Sie sich meine Antwort hier an: stackoverflow.com/a/43131930/6680521
Extragorey

Antworten:

85

Der gültige Weg ist:

disabled="disabled"

Browser könnten auch akzeptieren, disabled="" aber ich würde Ihnen den ersten Ansatz empfehlen.

Vor diesem Hintergrund würde ich empfehlen, einen benutzerdefinierten HTML-Helfer zu schreiben, um diese Deaktivierungsfunktion in einem wiederverwendbaren Code zu kapseln :

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);
    }
}

was Sie so verwenden könnten:

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

und Sie könnten noch mehr Intelligenz in diesen Helfer bringen:

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);
    }
}

Damit Sie jetzt die deaktivierte Bedingung nicht mehr angeben müssen:

@Html.MyTextBoxFor(
    model => model.ExpireDate, 
    new { 
        style = "width: 70px;", 
        maxlength = "10", 
        id = "expire-date" 
    }
)
Darin Dimitrov
quelle
Ich möchte das Textfeld deaktivieren, wenn Model.ExpireDate == null ist, sonst möchte ich es aktivieren
Ghooti Farangi
4
Diese Lösung ist großartig - soweit es geht ... aber es wäre schön, eine saubere Lösung zu finden, bei der nicht jeder von uns verwendete HTML-Helfer mit einem deaktivierten Attribut (TextBoxFor, TextAreaFor, CheckBoxFor usw.) Umhüllt werden muss .) Idealerweise etwas, das mit den vorhandenen übereinstimmt. Ich habe eine Lösung erstellt, die im Grunde nur das anonyme Objekt umschließt und ein RouteValueDictionary zurückgibt - aber es fühlt sich nicht besonders sauber an.
Mir
3
"disabled", "disabled = ''" und "disabled = 'disabled'" sind in HTML alle gleichermaßen gültig, und es ist irreführend (und falsch) zu sagen, dass die kürzeren möglicherweise nur von den verschiedenen Browsern akzeptiert werden. Vgl. dev.w3.org/html5/markup/syntax.html#syntax-attr-empty
Shautieh
53

Tatsächlich übersetzt das interne Verhalten das anonyme Objekt in ein Wörterbuch. Was ich in diesen Szenarien mache, ist ein Wörterbuch:

@{
  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 })

Oder, wie Stephen hier kommentierte :

@Html.EditorFor(m => m.Description,
    Model.IsDisabled ? (object)new { disabled = "disabled" } : (object)new { })
Shimmy Weitzhandler
quelle
@ Html.EditorFor (m => m.Description, Model.IsDisabled? (Objekt) new {disabled = "disabled"}: (Objekt) new {}) => Dies scheint der beste Weg zu sein. Danke
Carmine Checker
23

Ich mag die Darin-Methode. Aber schneller Weg, um dies zu lösen,

Html.TextBox("Expiry", null, new { style = "width: 70px;", maxlength = "10", id = "expire-date", disabled = "disabled" }).ToString().Replace("disabled=\"disabled\"", (1 == 2 ? "" : "disabled=\"disabled\""))
user571646
quelle
1
Ich denke, Sie sollten dies mit @ Html.Raw ()
Shadi Namrouti
14

Ein einfacher Ansatz, den ich verwendet habe, ist das bedingte Rendern:

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

Wenn Sie keine HTML-Helfer verwenden, können Sie einen einfachen ternären Ausdruck wie diesen verwenden:

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

Ich habe es mit einigen Erweiterungsmethoden erreicht

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);
    }

und dann....

@Html.TextBoxFor(model => model.Name, new { @class= "someclass"}).IsDisabled(Model.ExpireDate == null)
MurtuzaB
quelle
Funktioniert, wenn Sie rawstring.Length - 2 für 7 ändern und "" after last "hinzufügen.
Jozef Krchňavý
Funktioniert nicht mit TextAreaFor, benötigt eine Lösung für alle Arten von Eingabetypen
erhan355
10

Dies ist spät, kann aber für manche Menschen hilfreich sein.

Ich habe die Antwort von @ DarinDimitrov erweitert, um die Übergabe eines zweiten Objekts zu ermöglichen, das eine beliebige Anzahl von booleschen HTML-Attributen wie disabled="disabled" checked="checked", selected="selected"usw. akzeptiert .

Das Attribut wird nur gerendert, wenn der Eigenschaftswert true ist, alles andere und das Attribut wird überhaupt nicht gerendert.

Der benutzerdefinierte wiederverwendbare 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;
    }

}

Was Sie so verwenden können:

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

Wird dies mit RouteValueDictionary (funktioniert gut als htmlAttributes, da es auf IDictionary basiert) und einer Erweiterungsmethode gelöst:

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

Verwendung:

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

Das Guthaben geht an https://stackoverflow.com/a/3481969/40939

Niels Bosma
quelle
IMHO, das ist die beste Antwort
JenonD
6

Wenn Sie keine HTML-Helfer verwenden möchten, schauen Sie sich meine Lösung an

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

dass es

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

und ich denke, der bessere Weg, dies zu tun, besteht darin, diesen Check in der Steuerung durchzuführen und ihn in einer Variablen zu speichern, auf die in der Ansicht zugegriffen werden kann (Razor Engine), um dies zu tun the view free from business logic

Basheer AL-MOMANI
quelle
7
Wenn Sie das Attribut disabled in einem Steuerelement verwenden, wird das Steuerelement unabhängig vom Wert des Attributs deaktiviert. Selbst das Vorhandensein des Attributs ohne Wert deaktiviert das Steuerelement.
Geeky Guy
2
Diese Lösung funktioniert wirklich gut, und ich vermute, dass Downvoter übersehen haben, dass der Ausdruck boolesch ist. Wenn der Ausdruck boolesch ist, wird das Attribut disabled als disabled = "disabled" gerendert, wenn der Ausdruck wahr ist, oder wird vollständig weggelassen, wenn false. Welches ist genau das, was Sie wollen.
Carsten
Dies wird entweder deaktiviert = "falsch" oder deaktiviert = "wahr" rendern, nein?
Andez
4

Eine weitere Lösung wäre, Dictionary<string, object>vor dem Aufrufen TextBoxForein Wörterbuch zu erstellen und dieses weiterzugeben. "disabled"Fügen Sie im Wörterbuch nur Schlüssel hinzu, wenn das Textfeld deaktiviert werden soll. Nicht die sauberste Lösung, aber einfach und unkompliziert.

Kjell Rilbe
quelle
2

Ein anderer Ansatz besteht darin, das Textfeld auf der Clientseite zu deaktivieren.

In Ihrem Fall haben Sie nur ein Textfeld, das Sie deaktivieren müssen. Berücksichtigen Sie jedoch den Fall, dass Sie mehrere Eingabe-, Auswahl- und Textfelder haben, die Sie deaktivieren müssen.

Es ist viel einfacher, dies über jquery + zu tun (da wir uns nicht auf Daten verlassen können, die vom Client stammen). Fügen Sie dem Controller eine Logik hinzu, um zu verhindern, dass diese Felder gespeichert werden.

Hier ist ein Beispiel:

<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);
  }
}
Dror
quelle
0

Ich mag den Ansatz der Erweiterungsmethode, damit Sie nicht alle möglichen Parameter durchlaufen müssen.
Die Verwendung von regulären Ausdrücken kann jedoch ziemlich schwierig (und etwas langsamer) sein, daher habe ich XDocumentstattdessen Folgendes verwendet :

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());
}

Verwenden Sie die Erweiterungsmethode wie folgt:
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)

Kapé
quelle