Как использовать тире в атрибутах data- * HTML-5 в ASP.NET MVC

325

Я пытаюсь использовать атрибуты данных HTML5 в моем проекте ASP.NET MVC 1. (Я новичок в C # и ASP.NET MVC.)

 <%= Html.ActionLink("« Previous", "Search",
     new { keyword = Model.Keyword, page = Model.currPage - 1},
     new { @class = "prev", data-details = "Some Details"   })%>

«Данные-данные» в приведенных выше атрибутах htmlAttributes выдают следующую ошибку:

 CS0746: Invalid anonymous type member declarator. Anonymous type members 
  must be declared with a member assignment, simple name or member access.

Это работает, когда я использую data_details, но я предполагаю, что он должен начинаться с «data-» согласно спецификации.

Мои вопросы:

  • Есть ли способ заставить это работать и использовать атрибуты данных HTML5 с Html.ActionLink или аналогичными помощниками Html?
  • Есть ли другой альтернативный механизм для прикрепления пользовательских данных к элементу? Эти данные будут позже обработаны JS.
Шамим
источник
5
это старый вопрос с устаревшим ответом - пользователям MVC 3 и выше следует просмотреть этот вопрос stackoverflow.com/questions/2897733/…
ED-209

Ответы:

115

Обновление: MVC 3 и более новые версии имеют встроенную поддержку для этого. См. Высоко одобренный ответ JohnnyO ниже для рекомендуемых решений.

Я не думаю, что есть непосредственные помощники для достижения этой цели, но у меня есть две идеи для вас:

// 1: pass dictionary instead of anonymous object
<%= Html.ActionLink( "back", "Search",
    new { keyword = Model.Keyword, page = Model.currPage - 1},
    new Dictionary<string,Object> { {"class","prev"}, {"data-details","yada"} } )%>

// 2: pass custom type decorated with descriptor attributes
public class CustomArgs
{
    public CustomArgs( string className, string dataDetails ) { ... }

    [DisplayName("class")]
    public string Class { get; set; }
    [DisplayName("data-details")]
    public string DataDetails { get; set; }
}

<%= Html.ActionLink( "back", "Search",
    new { keyword = Model.Keyword, page = Model.currPage - 1},
    new CustomArgs( "prev", "yada" ) )%>

Просто идеи, не проверял это.

Мортен Мертнер
источник
5
Здравствуй. Если вы хотите использовать первый подход, просто убедитесь, что ваш словарь имеет тип Dictionary <String, Object>.
Ондрей Стастный
40
Хотя это технически работает, рекомендуемый способ (начиная с MVC 3) состоит в использовании подчеркивания вместо дефиса (как указал JohnnyO).
Кертис покупает
3
Путать весь мир с этим выбранным ответом, пока не заметить настоящий ответ выше!
Рубенс Мариуццо
648

Эта проблема была решена в ASP.Net MVC 3. Теперь они автоматически преобразуют подчеркивания в свойствах атрибута html в тире. Им повезло в этом, так как подчеркивание недопустимо в атрибутах html, поэтому MVC может с уверенностью подразумевать, что вы хотели бы использовать тире при использовании подчеркивания.

Например:

@Html.TextBoxFor(vm => vm.City, new { data_bind = "foo" })

сделает это в MVC 3:

<input data-bind="foo" id="City" name="City" type="text" value="" />

Если вы все еще используете более старую версию MVC, вы можете имитировать то, что делает MVC 3, создав этот статический метод, который я позаимствовал из исходного кода MVC3:

public class Foo {
    public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes) {
        RouteValueDictionary result = new RouteValueDictionary();
        if (htmlAttributes != null) {
            foreach (System.ComponentModel.PropertyDescriptor property in System.ComponentModel.TypeDescriptor.GetProperties(htmlAttributes)) {
                result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes));
            }
        }
        return result;
    }
}

И тогда вы можете использовать это так:

<%: Html.TextBoxFor(vm => vm.City, Foo.AnonymousObjectToHtmlAttributes(new { data_bind = "foo" })) %>

и это отобразит правильный атрибут data- *:

<input data-bind="foo" id="City" name="City" type="text" value="" />
Джонни Ошика
источник
6
Это не работает для меня по какой-то причине. Просмотр источника показывает данные_ *. Использование MVC3. Любые идеи?
Саймон Хартчер
Привет Саймон, ты решил свою проблему? Если нет, можете ли вы предоставить свой код, который вызывает у вас проблему?
Джонни Ошика
Все еще не повезло с WebGrid.GetHtml(htmlAttributes: new { data_some : "thing" }). : '(
Рубенс Мариуццо
+1 за указание, почему подчеркивание будет работать. Мне не пришло в голову, что подчеркивания недопустимы в именах атрибутов для HTML!
Умар Фарук Хаваджа
2
@RubensMariuzzo - это не то, что нужно, RouteValueDictionaryа Html.Something()методы MVC3 . Возможно, что WebGridне был обновлен таким же образом, или вы можете проверить версию наSystem.Web.Helpers.dll
Кит
58

Это даже проще, чем все предложенное выше. Атрибуты данных в MVC, которые включают тире (-), обрабатываются с использованием подчеркивания (_).

<%= Html.ActionLink("« Previous", "Search",
 new { keyword = Model.Keyword, page = Model.currPage - 1},
 new { @class = "prev", data_details = "Some Details"   })%>

Я вижу, Джонни уже упоминал об этом.

Оливер
источник
12
Ответственный за это метод: HtmlHelper.AnonymousObjectToHtmlAttributes (object), если кому-то интересно, почему их пользовательское расширение не заменяет знак подчеркивания дефисом.
Никкельман
1
Это действительно нуждается в голосовании, поскольку это самый простой ответ и работает отлично!
Дэн Дип
21

В MVC 4 может быть отображено с Underscore ("_")

Razor:

@Html.ActionLink("Vote", "#", new { id = item.FileId, }, new { @class = "votes", data_fid = item.FileId, data_jid = item.JudgeID, })

Рендеринг HTML

<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>
mzonerz
источник
Привет, есть ли способ POST data-fid к контроллеру, через Ajax или отправить. интересно, как использовать данные. Например, если у меня есть data-dateатрибут, как я могу отправить его в контроллер / действие? И что там за% 23
трансформер
Да, используйте коллекцию форм и получите доступ к ней с помощью идентификатора или имени, и% 23 будет #
mzonerz
4

Вы можете реализовать это с помощью новой вспомогательной функции расширения Html, которая затем будет использоваться аналогично существующим ссылкам ActionLinks.

public static MvcHtmlString ActionLinkHtml5Data(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, object htmlDataAttributes)
{
    if (string.IsNullOrEmpty(linkText))
    {
        throw new ArgumentException(string.Empty, "linkText");
    }

    var html = new RouteValueDictionary(htmlAttributes);
    var data = new RouteValueDictionary(htmlDataAttributes);

    foreach (var attributes in data)
    {
        html.Add(string.Format("data-{0}", attributes.Key), attributes.Value);
    }

    return MvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, actionName, controllerName, new RouteValueDictionary(routeValues), html));
}

И ты называешь это так ...

<%: Html.ActionLinkHtml5Data("link display", "Action", "Controller", new { id = Model.Id }, new { @class="link" }, new { extra = "some extra info" })  %>

Simples :-)

редактировать

немного больше писать здесь

WestDiscGolf
источник
3

В итоге я использовал обычную гиперссылку Url.Action, как в:

<a href='<%= Url.Action("Show", new { controller = "Browse", id = node.Id }) %>'
  data-nodeId='<%= node.Id %>'>
  <%: node.Name %>
</a>

Это ужаснее, но у вас есть немного больше контроля над aтегом, который иногда полезен на сайтах с высокой степенью AJAXified.

НТН

Кит Уильямс
источник
0

Я не люблю использовать чистый тег "a", слишком много печатать. Итак, я пришел с решением. В виду это выглядит

<%: Html.ActionLink(node.Name, "Show", "Browse", 
                    Dic.Route("id", node.Id), Dic.New("data-nodeId", node.Id)) %>

Реализация класса Dic

public static class Dic
{
    public static Dictionary<string, object> New(params object[] attrs)
    {
        var res = new Dictionary<string, object>();
        for (var i = 0; i < attrs.Length; i = i + 2)
            res.Add(attrs[i].ToString(), attrs[i + 1]);
        return res;
    }

    public static RouteValueDictionary Route(params object[] attrs)
    {
        return new RouteValueDictionary(Dic.New(attrs));
    }
}
msa.im
источник
1
Конечно, есть лучшее имя класса ... tпо крайней мере, дополнительный в конце!
hvaughan3
-2

Вы можете использовать это так:

В мвк:

@Html.TextBoxFor(x=>x.Id,new{@data_val_number="10"});

В HTML:

<input type="text" name="Id" data_val_number="10"/>
гурурадж надагер
источник