Est-il possible de pré-renseigner une liste SelectList sur ViewModel avec des attributs de données?
Je veux faire
@Html.DropdownListFor(m=> m.CityId, Model.Cities);
il génère donc un code comme:
<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>
Voici la solution simple.
Tout ne doit pas être écrit avec la méthode d'extension dans le code .NET. L'un des avantages de MVC est qu'il vous permet d'accéder facilement à la construction de votre propre code HTML.
Avec MVC4, vous pouvez obtenir l’ID et le nom de l’élément sur l’arbre des expressions avec les assistants HTML.NameFor
et 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>
En supposant que Model.Cities
est une collection d’éléments qui exposent chacune de ces propriétés. Ensuite, vous devriez être tous ensemble.
Si vous voulez la réutilisabilité, envisagez d'en faire un modèle d'éditeur pour tout ce qui est un énumérable de villes.
Vous devrez étendre SelectListItem, puis DropDownListFor pour utiliser l'objet SelectListItem.
Regardez cette solution:
Ajout d'une balise de classe html sous <option> dans Html.DropDownList
MVC lorsqu'il convertit les noms d'objet en noms d'attributs, il remplace "_" par "-", ainsi:
@Html.DropDownList(a=>a.websiteid, Model.GetItems, new{ data_rel="selected" })
PAS MA RÉPONSE, LE CRÉDIT DE RÉPONSE VA À propos de bruce (sqlwork.com) de ASP> NET Forums.
JUSTE VOULU AIDER CELA ME SAUVE DE CODER UN HACK! PRENDRE PLAISIR.
J'ai eu une exigence similaire, j'ai créé une extension. J'espère que cela aide pour ceux qui veulent créer une extension.
/*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*/
Voici comment j'ai fini par le faire sans extension, tout en permettant à la validation non intrusive de continuer à fonctionner et d'être lié à une propriété ViewModel.
Création d'un assistant HTML pour obtenir les attributs de validation sous forme de chaîne:
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() + "\"")));
}
Utilisez cet assistant dans une liste select
dans la vue:
<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>
Cela produirait quelque chose comme ceci:
<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>
Je vous laisse les attributs data-
conditionnels, car il ne s'agit que de former les expressions Razor appropriées.