AnonymousObjectToHtmlAttributes, czyli sposób na “minus” w nazwach atrybutów HTML

25.06.2013

TLDR; Jeżeli chcesz użyć “-“ w nazwie parametru HTML w htmlAttributes np. w Html.TextBox zamiast data-costam, napisz data_costam. Pisząc własne kontrolki (rozszerzenia HtmlHelper) obsługuj htmlAttributes przy użyciu Htmlhelper.AnonymousObjectToHtmlAttributes, zamiast tworzyć słowniki.

Co w tej metodzie takiego specjalnego? Nazwa metody mówi wszystko, no prawie wszystko. Metoda używana często i gęsto w kodzie HtmlHelper przy okazji tworzenia kontrolek TextBox, CheckBox, DropDown itd. Zamienia ona jeden z parametrów – htmlAttributes z obiektu anonimowego na RouteValueDictionary, pozwalając na dodanie własnych atrybutów HTML do tworzonej kontrolki. Dzięki anonimowemu obiektowi można uprościć wywołanie takiego TextBox i napisać coś takiego:

@Html.TextBoxFor(x => x.Name, new {@class = "product-name"})

Wygenerowany input otrzyma klasę CSS product-name. Normalna sprawa, jeżeli ktoś wcześniej miał choć trochę do czynienia z ASP.NET MVC. Jednak zastosowanie obiektu jako takiego (nie koniecznie anonimowego) niesie za sobą ograniczenia dotyczące nazewnictwa zmiennych. Widać to na powyższym przykładzie, gdzie słowo kluczowe języka C# – class musiało zostać poprzedzone “małpą” w celu zapewnienia poprawnej interpretacji przez kompilator (czyt. “bez małpy się nie kompiluje”).

Co jeżeli chcemy w parametrze htmlAttributes przekazać atrybuty specjalne HTML5, z rodziny data-?  Jest problem. Znak “-“ nie jest dozwolony w nazwach właściwości i kod się nie skompiluje. Można co prawda ominąć ten problem przez przekazanie jako parametry htmlAttributes gotowego słownika RouteValueDictionary czy Dictionary<string,object>, ale jego inicjacja w kodzie widoku wygląda paskudnie, ręce bolą od pisania i na dodatek trzeba liczyć ilość nawiasów klamrowych. Poniżej próbka:

@Html.TextBox("CenaNetto", Model.Cena, new Dictionary<string, object>
{
    { "class", "input-mini wiersz-cena" },
    { "data-onchange", "cenaModule.oblicz" },
    { "readonly", "readonly" },
})

Żeby uniknąć takiego potwora, wystarczy zamienić “-“ na “_” i wrócić do korzystania z obiektu anonimowego . Tytułowa metoda wykonywana wewnątrz TextBox automatycznie zamieni znaki “_” na “-“ i w kodzie HTML dostaniemy ładne nazwy “z minusami”.

@Html.TextBox("Cena", Model.Cena, new { @class = "input-mini wiersz-cena", data_onchange = "cenaModule.oblicz", @readonly = "readonly" })

Jeżeli piszesz własne rozszerzenia do HtmlHelper, warto skorzystać z Htmlhelper.AnonymousObjectToHtmlAttributes  do przerabiania htmlAttributes i zaoszczędzić trochę czasu i energii.