SelectListItem з атрибутами даних


76

Чи є в будь-якому випадку список SelectList, попередньо заповнений на ViewModel з атрибутами даних?

Я хочу зробити

@Html.DropdownListFor(m=> m.CityId, Model.Cities);

отже, він генерує код типу:

<select id="City" class="location_city_input" name="City">
    <option data-geo-lat="-32.522779" data-geo-lng="-55.765835" data-geo-zoom="6" />
    <option data-geo-lat="-34.883611" data-geo-lng="-56.181944" data-geo-zoom="13" data-geo-name="Montevideo" data-child=".state1" value="1">Montevideo</option>               
    <option data-geo-lat="-34.816667" data-geo-lng="-55.95" data-geo-zoom="13" data-geo-name="Canelones, Ciudad de la Costa" data-child=".state41" value="41">Ciudad de la Costa</option>
</select>

Відповіді:


113

Ось просте рішення.

Не все потрібно писати методом розширення в коді .NET. Однією з чудових речей MVC є те, що він дає вам легкий доступ до побудови власного HTML.

За допомогою MVC4 ви можете отримати ідентифікатор та ім'я елемента у дереві виразів за допомогою допоміжних HTML.NameForтаHTML.IdFor

<select name="@Html.NameFor(Function(model) model.CityId)"
        id="@Html.IdFor(Function(model) model.CityId)"
        class="location_city_input">
    @For Each city In Model.Cities
        @<option value="@city.Value"
                 @(If(city.Value = Model.CityId, "selected", ""))
                 data-geo-lat="@city.Lat"
                 data-geo-lng="@city.Lng"
                 data-geo-zoom="@city.Zoom">
            @city.Text
        </option>
    Next
</select>

Припускаючи Model.Cities - це сукупність предметів, які виявляють кожну з цих властивостей. Тоді у вас повинно бути все готово.

Якщо ви хочете багаторазового використання, подумайте про те, щоб зробити його шаблоном редактора для всього, що є Нескінченною містом


2
Цікаво ... Я не знав про html.namefor тощо. Спробую
Барт Каліксто

1
Чудова порада для додавання справжньої простої гнучкості до вашого html.
ChandlerPelhams

5
Оскільки razor2 ви можете просто зробити, selected="@city.Value == Model.CityId"і він генеруватиме правильну розмітку ( selected="selected"або взагалі, або нічого)
Дієго,

4
Як зробити так, щоб це все ще працювало з валідацією? Мій вибір більше не відображає червоним кольором правильно, коли є помилка перевірки.
skeletank

4
Код, опублікований @Diego, не працював, доки я не додав дужки:selected="@(city.Value == Model.CityId)"
Tawab Wakil

12

Вам доведеться розширити SelectListItem, а потім розширити DropDownListFor, щоб використовувати розширений SelectListItem.

Погляньте на це рішення:

Додавання тегу класу html під <option> у Html.DropDownList


1
це виглядає як правильна відповідь, але здається трохи потворним. Я радше сам пишу select, ніж розширюю SelectListItem та DropDownList, на мою думку. Я не впевнений.
Барт Каліксто,

4
Не знаю, чому ви вважаєте це потворним, але мені це здається більш логічним. Кожен SelectListItem представляє тег опцій у кінцевому html, і що вам потрібно зробити, це додати власні атрибути html до тегу параметра (SelectListItem), тому має сенс лише розширити SelectListItem.
атаравати

1
я думаю, що це негарно з точки зору mvc framework. але рішення полягає саме в тому, як з цим боротися.
Барт Каліксто

1
Погодився, досить неприємно, просто додати кілька простих атрибутів :(
drogon

Дійсно потворне рішення. Це було висвітлено в останній (5.2) версії MVC, або ви все ще пишете спеціальний код для цього? Дякую
Олександр Бетке

6

Ось як я в кінцевому підсумку робив це без розширення, але все одно дозволяв ненав’язливу перевірку продовжувати працювати і бути прив’язаним до властивості ViewModel.

Створив Html Helper для отримання атрибутів перевірки у вигляді рядка:

    public static IHtmlString GetUnobtrusiveValidationAttributesFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> propertySelector)
    {
        string propertyName = html.NameFor(propertySelector).ToString();
        ModelMetadata metaData = ModelMetadata.FromLambdaExpression(propertySelector, html.ViewData);
        IDictionary<string, object> attributeCollection = html.GetUnobtrusiveValidationAttributes(propertyName, metaData);

        return html.Raw(String.Join(" ", attributeCollection.Select(kvp => kvp.Key + "=\"" + kvp.Value.ToString() + "\"")));
    }

Використовуйте цього помічника у selectсписку у поданні:

<select name="@Html.NameFor(m => m.CityId)" id="@Html.IdFor(m => m.CityId)"
    @Html.GetUnobtrusiveValidationAttributesFor(m => m.CityId)
    class="location_city_input">
    @foreach(var city in Model.Cities)
    {
        <option value="@city.Id.ToString()" @(city.Id == Model.CityId ? "selected" : "") 
            data-geo-lat="@city.Lat" data-geo-lng="@city.Lng" data-geo-zoom="@city.Zoom">
            @city.Name
        </option>
    }
</select>

Це вивело б приблизно таке:

<select id="CityId" name="CityId" 
    data-val-required="The SelectedTaxRateID field is required." data-val="true" 
    class="location_city_input">
    <option value="1" selected data-geo-lat="-34.883611" data-geo-lng="-56.181944" data-geo-zoom="13">Montevideo</option>               
    <option value="41" data-geo-lat="-34.816667" data-geo-lng="-55.95" data-geo-zoom="13">Ciudad de la Costa</option>
</select>

Умовні data-атрибути я залишу за вами, оскільки це лише питання формування відповідних виразів Razor.


3

MVC, коли він перетворює імена об'єктів в імена атрибутів, співвідносить "_" з "-", тому його:

@Html.DropDownList(a=>a.websiteid, Model.GetItems, new{ data_rel="selected" })

НЕ МОЙ ВІДПОВІДЬ, ВІДПОВІДЬ КРЕДИТ ПРО ПРО БРУС (sqlwork.com) з форумів ASP> NET.

Як я можу додати атрибут data-rel = "selected" у випадаючий список для htmlAttributes?

ПРОСТО ХОТЕЛО ДОПОМОГТИ, ЩО ЦЕ Врятувало мене від кодування злому! НАСЛАДУЙТЕСЬ.


6
Це лише додало rel-дані до selectне кожногоoption
ParoX

Чудово знати, хоча він не додає атрибути як бажано (як згадано в ParoX).
spaark

2

У мене була подібна вимога, я створив розширення. Сподіваюся, це допоможе тим, хто хоче створити розширення.

/*cs file*/
/*This contains your information with List<vmListItem>*/
public class vmListItem
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string Tag { get; set; }
}

/*This contains the attributes in select, using List<vmAttribute>. Check cshtml */
public class vmAttribute
{
   public string Key { get; set; }
   public string Value { get; set; }
}

    /// <summary>
    /// Creates a dropdownlist using a list with data attributes included
    /// </summary>
    /// <param name="helper"></param>
    /// <param name="id">id and name of the select</param>
    /// <param name="attributes">list of attrs for select</param>
    /// <param name="items"><list of options/param>
    /// <param name="idSelected">id selected in option</param>
    /// <param name="tagName">data-tagName you can choose the name of your tag</param>
    /// <param name="textHeader">first option in select</param>
    /// <returns></returns>
    public static MvcHtmlString DropDownListForWithTag(this HtmlHelper helper, string id, List<vmAttribute> attributes, List<vmListItem> items, int idSelected, string tagName = "tag", string textHeader= "")
    {
        var select = new TagBuilder("select");
        select.GenerateId(id);
        select.MergeAttribute("name", id);
        foreach (vmAttribute att in atributos) select.MergeAttribute(att.Key, att.Value);

        TagBuilder headerOption = new TagBuilder("option");
        headerOption .MergeAttribute("value", null);
        headerOption .InnerHtml = textHeader;
        select.InnerHtml += headerOption ;

        foreach(var item in items)
        {                
            TagBuilder option = new TagBuilder("option");
            option.MergeAttribute("value", item.Id.ToString());
            option.MergeAttribute("data-" + tagName, item.Tag);
            if (idSelected == item.Id) option.MergeAttribute("selected", "selected");
            option.InnerHtml = item.Name;

            select.InnerHtml += option.ToString();
        }

        return new MvcHtmlString(select.ToString());
    }

/*cshtml file*/
@Html.DropDownListForWithTag("MovimientoBienMotivoId", new List<vmAttribute> {
                        new vmAttribute("class", "form-control"),
                        new vmAttribute("data-val", "true"),
                        new vmAttribute("data-val-required", "El campo Motivo es obligatorio"),
                        new vmAttribute("onchange", "movValidarCambioMotivo()"),
                    }, (List<vmListItem>)ViewBag.MovimientoBienMotivoId, Model.MovimientoBienMotivoId, "codigo", "Seleccione")
                    @Html.ValidationMessageFor(model => model.ColumnId, "", new { @class = "text-danger" })


/*html results*/

введіть тут опис зображення


Дякую найкраще рішення з усіх. Я налаштував це розширення відповідно до своїх потреб.
Гаррі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.