SelectListItem mit Datenattributen

75

Gibt es überhaupt eine SelectList, die in ViewModel mit Datenattributen vorab ausgefüllt ist?

Ich will das tun

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

So wird Code generiert wie:

<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>
Bart Calixto
quelle

Antworten:

112

Hier ist die einfache Lösung.

Nicht alles muss mit der Erweiterungsmethode in .NET-Code geschrieben werden. Eines der großartigen Dinge an MVC ist, dass Sie auf einfache Weise Ihr eigenes HTML erstellen können.

Mit MVC4 können Sie die ID und den Namen des Elements im Ausdrucksbaum mit den Helfern HTML.NameForund abrufenHTML.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>

Angenommen, es Model.Citieshandelt sich um eine Sammlung von Elementen, die jede dieser Eigenschaften verfügbar machen. Dann sollten Sie fertig sein.

Wenn Sie die Wiederverwendbarkeit wünschen, sollten Sie sie zu einer Editorvorlage für alles machen, was eine Aufzählung von Städten ist

KyleMit
quelle
2
Interessant ... Ich wusste nichts über html.namefor usw. Ich werde es versuchen
Bart Calixto
1
Ein guter Rat, um Ihrem HTML-Code wirklich einfache Flexibilität zu verleihen.
ChandlerPelhams
5
Seit razor2 können Sie einfach tun selected="@city.Value == Model.CityId"und es wird das richtige Markup (entweder selected="selected"oder nichts) erzeugen
Diego
4
Wie schaffen Sie es, dass dies mit der Validierung noch funktioniert? Meine Auswahl wird bei einem Validierungsfehler nicht mehr richtig rot hervorgehoben.
Skelett
4
Der von @Diego gepostete Code funktionierte nicht, bis ich Klammern hinzufügte:selected="@(city.Value == Model.CityId)"
Tawab Wakil
12

Sie müssen SelectListItem erweitern und dann DropDownListFor erweitern, um das erweiterte SelectListItem zu verwenden.

Schauen Sie sich diese Lösung an:

Hinzufügen eines HTML-Klassen-Tags unter <Option> in Html.DropDownList

ataravati
quelle
1
Das sieht nach der richtigen Antwort aus, wirkt aber irgendwie hässlich. Ich schreibe die Auswahl lieber selbst, als SelectListItem und DropDownListFor zu erweitern. Ich bin mir nicht sicher.
Bart Calixto
4
Ich weiß nicht, warum du es für hässlich hältst, aber es scheint mir logischer. Jedes SelectListItem stellt ein Options-Tag im endgültigen HTML-Code dar. Sie müssen dem Options-Tag (SelectListItem) benutzerdefinierte HTML-Attribute hinzufügen, sodass es nur sinnvoll ist, das SelectListItem zu erweitern.
Ataravati
1
Ich denke, es ist hässlich aus der Perspektive des MVC-Frameworks. Aber die Lösung ist genau, wie man damit umgeht.
Bart Calixto
1
Einverstanden, ziemlich böse, nur um ein paar einfache Attribute hinzuzufügen :(
Drogon
Wirklich hässliche Lösung. Wurde es in der neuesten (5.2) Version von MVC behandelt oder möchten Sie immer noch benutzerdefinierten Code dafür schreiben? Danke
Aleksander Bethke
5

Hier ist, wie ich es ohne Erweiterung gemacht habe, aber dennoch eine unauffällige Validierung ermöglicht habe, damit es weiterhin funktioniert und an eine ViewModel-Eigenschaft gebunden ist.

Erstellt einen HTML-Helfer, um die Validierungsattribute als Zeichenfolge abzurufen:

    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() + "\"")));
    }

Verwenden Sie diesen Helfer in einer selectListe in der Ansicht:

<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>

Dies würde ungefähr so ​​ausgeben:

<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>

Ich werde die bedingten data-Attribute Ihnen überlassen , da es nur darum geht, die entsprechenden Razor-Ausdrücke zu bilden.

xr280xr
quelle
3

Wenn MVC Objektnamen in Attributnamen konvertiert, wird "_" durch "-" ersetzt.

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

NICHT MEINE ANTWORT, ANTWORTKREDIT GEHT ZU Über bruce (sqlwork.com) aus den ASP> NET-Foren.

Wie kann ich das Attribut data-rel = "selected" zur Dropdown-Liste für htmlAttributes hinzufügen?

WOLLTE NUR HELFEN, WIE DIESE MICH davor bewahrt haben, einen HACK zu codieren! GENIESSEN.

Takumi
quelle
6
Dies fügte nur die Daten-Rel zu den selectnicht zu jedem hinzuoption
ParoX
Gut zu wissen, obwohl die Attribute nicht wie gewünscht hinzugefügt werden (wie in ParoX erwähnt).
Spaark
2

Ich hatte eine ähnliche Anforderung, ich habe eine Erweiterung erstellt. Hoffe, es hilft für diejenigen, die eine Erweiterung erstellen möchten.

/*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*/

Geben Sie hier die Bildbeschreibung ein

aldo
quelle
Vielen Dank für die beste Lösung von allen. Ich habe diese Erweiterung an meine Bedürfnisse angepasst.
Harry