2010-01-18 21 views
15

Jak zmienić tę deklarację DropDownList, aby wyłączony atrybut był włączony/wyłączony warunkowo?Warunkowo wyłącz Html.DropDownList

<%= Html.DropDownList("Quantity", new SelectList(...), new{@disabled="disabled"} %> 

nieczynnego przykład:

<%= Html.DropDownList("Quantity", new SelectList(...), new{@disabled=Model.CanEdit?"false":"disabled"} %> 

P.S. dodanie jeśli warunek wokół całego rachunku nie jest pożądane podejście :)

EDIT: na podstawie this metodę rozszerzenia z innym pytaniem wymyśliłem następujących rozszerzeniach:

public static IDictionary<string, object> Disabled (this object obj, bool disabled) 
{ 
    return disabled ? obj.AddProperty ("disabled", "disabled") : obj.ToDictionary(); 
} 

które następnie mogą być stosowany jako

<%= Html.DropDownList("Quantity", new SelectList(...), new{id="quantity"}.Disabled(Model.CanEdit) %> 
+0

Cześć, chcę wyłączyć/włączyć rozwijaną dla konkretnych stron wyłącznie na podstawie wartości, ja przepuszczenie go przez model. Próbowałem przekazać true/false osobom niepełnosprawnym, ale to nie działa. Możesz pomóc w tym – ravithejag

Odpowiedz

19

Proszę nie pisać kodu spaghetti. pomocnicy html istnieją do tego celu:

public static MvcHtmlString DropDownList(this HtmlHelper html, string name, SelectList values, bool canEdit) 
{ 
    if (canEdit) 
    { 
     return html.DropDownList(name, values); 
    } 
    return html.DropDownList(name, values, new { disabled = "disabled" }); 
} 

A potem:

<%= Html.DropDownList("Quantity", new SelectList(...), Model.CanEdit) %> 

Albo można wymyślić coś jeszcze lepszego (jeśli model zawiera opcje):

<%= Html.DropDownList("Quantity", Model) %> 

Otrzymasz również premię za posiadanie większej liczby testów testowalnych.

+0

W jaki sposób korzystanie z helpera sprawia, że ​​jednostka testuje twoje poglądy w łatwiejszy sposób? –

+1

Nie można przeglądać testów jednostkowych ze względu na charakter mechanizmu WebForms. Możesz jednak testować metody rozszerzeń. W ten sposób Twój widok nie będzie już zawierał warunkowej logiki wartej testowania jednostkowego. Testując metodę rozszerzenia, upewniasz się, że wszystkie widoki, które go używają, będą działać zgodnie z oczekiwaniami i będą miały dokładny znacznik w zależności od właściwości 'CanEdit' w twoim modelu. –

+0

Jak ten kod będzie wyglądał, gdy potrzebuję metody pomocnika z tym podpisem? 'public static string DropDownList (ten htmlHelper html, nazwa łańcucha, wartości SelectList, obiekt htmlAttributes, bool canEdit)' –

-2

ja nie wiem, czy ASP.NET oferuje bardziej zwięzły podejście specjalnym przypadku, ale prawdopodobnie można zrobić:

<%= Html.DropDownList("Quantity", new SelectList(...), Model.CanEdit? new{@class="quantity"} : new{@class="quantity", @disabled:"disabled"}) %> 
+2

Nie, nie możesz tego zrobić. Pojawia się błąd podczas kompilacji: "Nie można określić typu warunkowego wyrażenia, ponieważ nie ma niejawnej konwersji między" AnonymousType # 1 "i" AnonymousType # 2 "" –

+0

nie działa pls usunąć tę odpowiedź –

+0

Musisz dodać casting to anonymousTypes 'as object' niż to zadziała –

5

Jedną z opcji jest tworzenie niestandardowej wersji pliku Html.DropDownList, która pobiera dodatkowy parametr i robi to, co chcesz ... ale wtedy musisz utworzyć nowy dla każdego typu helpera: TextBoxFor, TextAreaFor, CheckBoxFor, etc ... i nadal musisz wymyślić, jak sprawić, by jego wnętrzności działały.

Zamiast tego zdecydowałem się stworzyć pomocnika HTML, który zastąpi normalny anonimowy obiekt HtmlAttributes, ponieważ wtedy będzie kompatybilny z wszystkimi Pomocnikami, którzy używają HtmlAttributes bez żadnej specjalnej pracy. To rozwiązanie pozwala również przejść przez dodatkowe Atrybuty, takie jak Klasa, Nazwa lub cokolwiek chcesz. Nie blokuje cię tylko do wyłączenia.

Utworzono następujący pomocnik - pobiera obiekt logiczny i anonimowy. Jeśli wyłączona jest prawdą, dodaje atrybut disabled do anonimowego obiektu (który jest w rzeczywistości Słownikiem) z wartością "disabled", w przeciwnym razie nie doda w ogóle właściwości.

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

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

    return dictionary; 
} 


Przykładem go w akcji:

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


Jeden Ogromną zaletą tego podejścia dla mnie było to, że współpracuje z praktycznie wszystkich MVC HtmlHelpers ponieważ wszystko mają przeciążenia, które akceptują RouteValueDictionary zamiast anonimowego obiektu.

Ostrzeżenia:
HtmlHelper.AnonymousObjectToHtmlAttributes() używa wymyślnej pracy Kod ninja, aby to zrobić. Nie jestem do końca pewny, jak jest to wykonawca ... ale to wystarczyło dla tego, do czego go używam. Twój przebieg może się różnić.

Nie podoba mi się szczególnie nazwa - ale nie mogłem wymyślić nic lepszego. Zmiana nazwy jest łatwa.

Nie lubię też składni użycia - ale znowu nie mogłem wymyślić nic lepszego. Zmiana nie powinna być trudna. Metoda rozszerzenia na object to jeden z pomysłów ... skończyłoby się z new { @class = "someClass" }.ConditionalDisable(true), ale jeśli chcesz tylko wyłączyć atrybut i nie masz nic dodatkowego do dodania, skończysz z czymś brutto, takim jak new {}.ConditionalDisable(true);, a także skończysz z metoda rozszerzenia, która pojawia się dla wszystkich obiektów ... co prawdopodobnie nie jest pożądane.

+0

Jest to jedyna odpowiedź, która bierze pod uwagę możliwość przekazywania więcej htmlAttributes niż jeden i działa dla wszystkich HtmlHelpers. Kciuk w górę. –

22

Nie ma potrzeby, aby dodać metody pomocnika, można po prostu użyć

<%= Html.DropDownList("Quantity", new SelectList(...), IsEditable == true ? new { @disabled = "disabled" } as object : new {} as object %> 

Jeśli było usunąć as object wpisy to nie działa, ponieważ domyślnie new {} jest dynamiczny obiekt skompilowany przy starcie, dlatego dwa możliwe obiekty muszą mieć te same właściwości. Ale parametr atrybutów HTML jest w rzeczywistości tylko obiektem, więc te dynamiki można rzutować jako obiekty, aby ominąć to.

Takie rozwiązanie pozwala nawet używać wielu atrybutów HTML, gdzie jeden jest opcjonalny i nie jest inny, tj class='whatever' nie jest obowiązkowe, ale disabled jest więc umieścić class='whatever' w obu obiektów, ale tylko jedna opcja w pierwszym. Odpowiedź Dimitrowa nie obsługuje żadnych niestandardowych atrybutów innych niż wyłączone.

+6

+1 To powinno być oznaczone jako najlepsza odpowiedź –

0

silnie wpisane Verison:

public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> html, 
                    Expression<Func<TModel, TProperty>> expression, 
                    IEnumerable<SelectListItem> selectList, 
                    string optionText, bool canEdit) 
    { 
     if (canEdit) 
     { 
      return html.DropDownListFor(expression, selectList, optionText); 
     } 
     return html.DropDownListFor(expression, selectList, optionText, new { disabled = "disabled" }); 
    } 
2
@bool IsEditable=true; 

@if (IsEditable) 
{ 
    Html.DropDownListFor(m => m, selectList); 
} 
else 
{ 
    Html.DropDownListFor(m => m, selectList, new { disabled = "disabled" }) 
}