ASP.NET MVC 3 Razor - Dodawanie klasy do EditorFor

190

Próbuję dodać klasę do wejścia.

To nie działa:

@Html.EditorFor(x => x.Created, new { @class = "date" })
user137348
źródło
1
hej, masz nawet właściwą nazwę! - (dla mojego kodu)
Pinch.
1
UWAGA: W przypadku niektórych odpowiedzi, nawet jeśli są one poprawne, konieczne może być wyczyszczenie pamięci podręcznej przeglądarki, aby je zaktualizować. Jest to szczególnie ważne, jeśli rozwiązanie jest oparte na css lub obejmuje klasę css! Po prostu spędziłem trochę czasu zdając sobie z tego sprawę z nieco innym problemem…
JosephDoggie,

Odpowiedzi:

183

Dodanie klasy do Html.EditorFornie ma sensu, ponieważ wewnątrz jej szablonu możesz mieć wiele różnych tagów. Musisz więc przypisać klasę w szablonie edytora:

@Html.EditorFor(x => x.Created)

aw szablonie niestandardowym:

<div>
    @Html.TextBoxForModel(x => x.Created, new { @class = "date" })
</div>
Darin Dimitrov
źródło
5
To działa świetnie, dzięki. Wystąpił problem z formatowaniem wartości pola zgodnie z adnotacją DisplayFormat w moim modelu. Sformatowano jako z adnotacjami EditorFor i DisplayFor, ale nie TextBoxFor :( Wygląda na to, że muszę użyć niestandardowego szablonu, chyba że ktoś może wskazać mi coś, czego mi brakuje.?
Sean,
Mając ten sam problem, w którym TextBoxFor nie honoruje zestawu DisplayFormat.
wesoły
14
To jest GroundController do ModelTom, wysyłam Ci View i pływam w sposób najbardziej MVC.
Trent Stewart
3
Mam ten sam problem, ale nie mogę używać TextBoxFor, ponieważ potrzebuję DisplayFormat, który działa z edytorem lub wyświetlaczem, ale jednocześnie potrzebuję też klasy, aby móc wyświetlać tekst w formie tylko do odczytu
AT
156

Począwszy od ASP.NET MVC 5.1, dodanie klasy do an EditorForjest możliwe (pierwotne pytanie określało ASP.NET MVC 3, a zaakceptowana odpowiedź jest nadal najlepsza z rozważanym).

@Html.EditorFor(x=> x.MyProperty,
    new { htmlAttributes = new { @class = "MyCssClass" } })

Zobacz: Co nowego w ASP.NET MVC 5.1, obsługa Bootstrap dla szablonów edytorów

EF0
źródło
To cudownie. Dzięki!
Neill
1
Prawie to przegapiłem, ponieważ jest 3 na liście. Prawdopodobnie pomocne byłoby sformułowanie własnego pytania, a następnie samodzielna odpowiedź.
Robb Sadler
Podczas MVC 2,3,4 I nie ma sensu ... ale jak więcej ludzi zaczęło używać i narzekają na to - nagle ona wykonana w sensie w MVC 5: D +1
Piotr Kula
Moim zdaniem powinna to być teraz akceptowana odpowiedź.
Manfred,
102

Nie możesz ustawić klasy dla ogólnego EditorFor. Jeśli znasz żądany edytor, możesz go od razu użyć, tam możesz ustawić klasę. Nie musisz tworzyć żadnych niestandardowych szablonów.

@Html.TextBoxFor(x => x.Created, new { @class = "date" }) 
TuomasK
źródło
5
Dobra okazja, miło było nie tworzyć własnego szablonu.
Steve Duitsman
zaoszczędziłeś mi dużo czasu jo!
Prashanth Benny
40

Możesz użyć:

@Html.EditorFor(x => x.Created, new { htmlAttributes = new { @class = "date" } })

(Przynajmniej z ASP.NET MVC 5, ale nie wiem, jak to było z ASP.NET MVC 3).

przno
źródło
Przeczytaj tytuł pytania, to jest problem dotyczący MVC3, zapewniasz rozwiązanie MVC5, które jest całkowicie mylące.
Vincent
11
I proszę przeczytać cały mój post, w którym napisałem, dotyczy MVC5. To był pierwszy wynik z Google, więc kiedy znalazłem rozwiązanie, które chciałem, udostępnij je tutaj, może to pomoże niektórym osobom.
przno 23.04.15
Ten mi pomógł! Dzięki @przno
Joakim M
29

Miałem ten sam frustrujący problem i nie chciałem tworzyć EditorTemplate, który byłby stosowany do wszystkich wartości DateTime (w moim interfejsie użytkownika były chwile, w których chciałem wyświetlić czas, a nie kalendarz rozwijany interfejsu jQuery ). Podczas moich badań główne problemy, które napotkałem, to:

  • Standardowy pomocnik TextBoxFor pozwolił mi zastosować niestandardową klasę „ Date-Picker ” w celu renderowania dyskretnego kalendarza interfejsu użytkownika jQuery, ale TextBoxFor nie sformatowałby DateTime bez czasu, powodując tym samym niepowodzenie renderowania kalendarza.
  • Standardowy EditorFor wyświetlałby DateTime jako sformatowany ciąg (gdy został ozdobiony odpowiednimi atrybutami, takimi jak [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")], ale nie pozwoliłoby mi to zastosować niestandardowej klasy „date-picker”.

Dlatego utworzyłem niestandardową klasę HtmlHelper, która ma następujące zalety:

  • Metoda automatycznie konwertuje DateTime na ShortDateString wymagane przez kalendarz jQuery (jQuery zakończy się niepowodzeniem, jeśli czas jest obecny).
  • Domyślnie pomocnik zastosuje wymagane atrybuty htmlAttributes, aby wyświetlić kalendarz jQuery, ale w razie potrzeby można je zastąpić.
  • Jeśli data jest null, ASP.NET MVC umieści datę 1/1/0001 jako wartość.

Ta metoda zastępuje ją pustym ciągiem.

public static MvcHtmlString CalenderTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
{
    var mvcHtmlString = System.Web.Mvc.Html.InputExtensions.TextBoxFor(htmlHelper, expression, htmlAttributes ?? new { @class = "text-box single-line date-picker" });
    var xDoc = XDocument.Parse(mvcHtmlString.ToHtmlString());
    var xElement = xDoc.Element("input");
    if (xElement != null)
    {
        var valueAttribute = xElement.Attribute("value");
        if (valueAttribute != null)
        {
            valueAttribute.Value = DateTime.Parse(valueAttribute.Value).ToShortDateString();
            if (valueAttribute.Value == "1/1/0001")
                valueAttribute.Value = string.Empty;
        }
    }
    return new MvcHtmlString(xDoc.ToString());
}

A dla tych, którzy chcą poznać składnię JQuery, która szuka obiektów z date-pickerdekoracją klasy, aby następnie renderować kalendarz, oto jest:

$(document).ready(function () {
    $('.date-picker').datepicker({ inline: true, maxDate: 0, changeMonth: true, changeYear: true });
    $('.date-picker').datepicker('option', 'showAnim', 'slideDown');
});
bigmac
źródło
Pomogło mi to teraz, mały problem z tym - musisz sprawdzić, czy wartość valueAttribute.Value nie jest pusta ani spacja przed przekazaniem jej do metody DateTime.Parse, w przeciwnym razie ryzykujesz, że FormatException zostanie wyrzucony w pustym polu.
Moo
Dzięki. Bardzo mi pomogłeś.
Bronzato
Pomogło mi to, jednak jeśli wdrażasz to i spodziewasz się, że pole przeprowadzi walidację, będziesz musiał zastosować tę logikę: stackoverflow.com/questions/12023970/ ...
Aaron Newton
Dobra robota, ale czy wiesz, że możesz kontrolować, czy pojawia się formant DateTime lub po prostu Date, używając DateTimePickerFori aktualizując pole daty modelu, które reprezentujesz, [DataType(DataType.Date)]lub [DataType(DataType.DateTime)]? Możesz również umieścić go w, powiedzmy, mm / dd / rrrr za pomocą .ParseFormats(new string[] { "MM/dd/yyyy" })(lub łatwo zmodyfikować go do dowolnego). Jeśli jest null, pole renderuje się jako puste bez konieczności kodowania tego w.
vapcguy
Razor nie rozpozna @MyHtmlHelpers.CalenderTextBoxFor(model => model.ExpirationDate). Jakieś pomysły, jak to wdrożyć?
Mehdiway
15

Możliwe jest dostarczenie klasy lub innych informacji poprzez AdditionalViewData - używam tego, gdy pozwalam użytkownikowi stworzyć formularz oparty na polach bazy danych (propertyName, editorType i editorClass).

Na podstawie pierwszego przykładu:

@Html.EditorFor(x => x.Created, new { cssClass = "date" })

aw szablonie niestandardowym:

<div>
    @Html.TextBoxFor(x => x.Created, new { @class = ViewData["cssClass"] })
</div>
Brett
źródło
8
@ Html.EditorFor (x => x.Created, new {cssClass = "date"}) nie działa dla mnie
Alan Macdonald
1
To zadziałało dla mnie i jest lepszą odpowiedzią niż zaznaczona. Zapewnia korzyści płynące z używania szablonu, ale pozwala na pewne dostosowanie bez hacków jQuery.
Chad Hedgcock
TextBoxFor ignoruje inne atrybuty, które można ustawić w modelu, na przykład „DataType”.
Markus,
8

Nie ma żadnego EditorFornadpisania, które pozwoliłoby na przekazanie anonimowego obiektu, którego właściwości zostałyby w jakiś sposób dodane jako atrybuty do jakiegoś znacznika, szczególnie w przypadku wbudowanych szablonów edytora. Musisz napisać własny niestandardowy szablon edytora i przekazać żądaną wartość jako dodatkowe dane widoku.

marcind
źródło
2
@Html.EditorFor(m=>m.Created ...) 

nie zezwala na przekazywanie żadnych argumentów do pola tekstowego

W ten sposób możesz zastosować atrybuty.

@Html.TextBoxFor(m=>m.Created, new { @class= "date", Name ="myName", id="myId" })
Jayant Varshney
źródło
2

Korzystając z jQuery, możesz to łatwo zrobić:

$("input").addClass("class-name")

Oto Twój tag wejściowy

@Html.EditorFor(model => model.Name)

W przypadku DropDownlist możesz użyć tego:

$("select").addClass("class-name")

Lista rozwijana:

@Html.DropDownlistFor(model=>model.Name)
Praveen MP
źródło
2

Chociaż pytanie było skierowane do MVC 3.0, okazuje się, że problem występuje również w MVC 4.0. MVC 5.0 zawiera teraz natywnie przeciążenie dla htmlAttributes.

Jestem zmuszony korzystać z MVC 4.0 w moim obecnym miejscu pracy i muszę dodać klasę css do integracji JQuery. Rozwiązałem ten problem za pomocą metody pojedynczego rozszerzenia ...

Metoda rozszerzenia:

using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;

namespace MyTest.Utilities
{
    public static class MVCHelperExtensionMethods
    {
        public static MvcHtmlString AddHtmlAttributes(this MvcHtmlString input, object htmlAttributes)
        {
            // WE WANT TO INJECT INTO AN EXISTING ELEMENT.  IF THE ATTRIBUTE ALREADY EXISTS, ADD TO IT, OTHERWISE
            // CREATE THE ATTRIBUTE WITH DATA VALUES.

            // USE XML PARSER TO PARSE HTML ELEMENT
            var xdoc = XDocument.Parse(input.ToHtmlString());
            var rootElement = (from e in xdoc.Elements() select e).FirstOrDefault();

            // IF WE CANNOT PARSE THE INPUT USING XDocument THEN RETURN THE ORIGINAL UNMODIFIED.
            if (rootElement == null)
            {
                return input;
            }

            // USE RouteValueDictionary TO PARSE THE NEW HTML ATTRIBUTES
            var routeValueDictionary = new RouteValueDictionary(htmlAttributes);

            foreach (var routeValue in routeValueDictionary)
            {
                var attribute = rootElement.Attribute(routeValue.Key);

                if (attribute == null)
                {
                    attribute = new XAttribute(name: routeValue.Key, value: routeValue.Value);
                    rootElement.Add(attribute);
                }
                else
                {
                    attribute.Value = string.Format("{0} {1}", attribute.Value, routeValue.Value).Trim();
                }
            }

            var elementString = rootElement.ToString();
            var response = new MvcHtmlString(elementString);
            return response;
        }
    }
}

Wykorzystanie znaczników HTML:

@Html.EditorFor(expression: x => x.MyTestProperty).AddHtmlAttributes(new { @class = "form-control" })

(Upewnij się, że w widoku maszynki do golenia uwzględniono przestrzeń nazw metody rozszerzenia)

Objaśnienie: Pomysł polega na wstrzyknięciu do istniejącego kodu HTML. Zdecydowałem się przeanalizować bieżący element za pomocą Linq-to-XML przy użyciu XDocument.Parse(). Jako typ przekazuję htmlAttributes object. Używam MVC RouteValueDictionarydo analizowania htmlAttributes przekazanych. Scalam atrybuty tam, gdzie już istnieją, lub dodaję nowy atrybut, jeśli jeszcze nie istnieje.

W przypadku, gdy dane wejściowe nie są analizowalne XDocument.Parse(), porzucam wszelką nadzieję i zwracam oryginalny ciąg wejściowy.

Teraz mogę korzystać z zalet DisplayFor (odpowiednio renderować typy danych, takie jak waluta), ale mam również możliwość określenia klas css (i wszelkich innych atrybutów w tym zakresie). Może być pomocny przy dodawaniu atrybutów, takich jak data-*, lub ng-*(Angular).

barrypicker
źródło
1

Możesz stworzyć to samo zachowanie, tworząc prosty edytor niestandardowy o nazwie DateTime.cshtml, zapisując go w Views / Shared / EditorTemplates

@model DateTime

@{
    var css = ViewData["class"] ?? "";
    @Html.TextBox("", (Model != DateTime.MinValue? Model.ToString("dd/MM/yyyy") : string.Empty), new { @class = "calendar medium " + css});
}

i w swoich poglądach

@Html.EditorFor(model => model.StartDate, new { @class = "required" })

Zauważ, że w moim przykładzie na stałe koduję dwie klasy css i format daty. Możesz to oczywiście zmienić. Możesz również zrobić to samo z innymi atrybutami HTML, takimi jak tylko do odczytu, wyłączone itp.

Alexandre
źródło
1

Użyłem innego rozwiązania wykorzystującego selektory atrybutów CSS, aby uzyskać to, czego potrzebujesz.

Wskaż atrybut HTML, który znasz i umieść w odpowiednim stylu względnym.

Jak poniżej:

input[type="date"]
{
     width: 150px;
}
Max Clapton
źródło
1

Nie ma potrzeby tworzenia własnego szablonu dla MVC 4. Użyj TextBox zamiast Edit , ponieważ tutaj specjalne atrybuty html nie są obsługiwane, jest obsługiwany tylko z MVC 5. TextBox powinien obsługiwać MVC 4, nie wiem o innej wersji.

@Html.TextBox("test", "", new { @id = "signupform", @class = "form-control", @role = "form",@placeholder="Name" })
Merbin Jo
źródło
0

Możesz to również zrobić za pomocą jQuery:

$('#x_Created').addClass(date);
Scott R. Frost
źródło
0

Musiałem tylko ustawić rozmiar jednego pola tekstowego na jednej stronie. Kodowanie atrybutów w modelu i tworzenie niestandardowych szablonów edytorów było przesadą, więc po prostu opakowałem wywołanie @ Html.EditorFor tagiem span, który wywołał klasę, która określa rozmiar pola tekstowego.

Deklaracja klasy CSS:

.SpaceAvailableSearch input
{
    width:25px;
}

Wyświetl kod:

<span class="SpaceAvailableSearch">@Html.EditorFor(model => model.SearchForm.SpaceAvailable)</span>
Hrabia
źródło
0

Jednym z najlepszych sposobów zastosowania klasy @Html.EditorFor()w MVC3 RAzor jest

@Html.EditorFor(x => x.Created)


<style type="text/css">

#Created
{
    background: #EEE linear-gradient(#EEE,#EEE);   
    border: 1px solid #adadad;
    width:90%;
    }
</style>

Doda powyższy styl do twojego EditorFor()

Działa z MVC3.

Bilal
źródło