web-dev-qa-db-fra.com

Exclure / supprimer une valeur de MVC 5.1 EnumDropDownListFor

J'ai une liste d'énumérations que j'utilise pour une page de gestion des utilisateurs. J'utilise le nouveau HtmlHelper dans MVC 5.1 qui me permet de créer une liste déroulante pour les valeurs Enum. J'ai maintenant besoin de supprimer la valeur En attente de la liste, cette valeur ne sera jamais définie que par programme et ne devrait jamais être définie par l'utilisateur.

Enum:

public enum UserStatus
{
    Pending = 0,
    Limited = 1,
    Active = 2
}

Vue:

@Html.EnumDropDownListFor(model => model.Status)

Existe-t-il de toute façon, soit en remplaçant le contrôle actuel, soit en écrivant un HtmlHelper personnalisé qui me permettrait de spécifier une énumération ou des énumérations à exclure de la liste résultante? Ou suggéreriez-vous que je fasse quelque chose côté client avec jQuery pour supprimer la valeur de la liste déroulante une fois qu'elle a été générée?

Merci!

34
Jak Hammond

Vous pouvez construire une liste déroulante:

@{ // you can put the following in a back-end method and pass through ViewBag
   var selectList = Enum.GetValues(typeof(UserStatus))
                        .Cast<UserStatus>()
                        .Where(e => e != UserStatus.Pending)
                        .Select(e => new SelectListItem 
                            { 
                                Value = ((int)e).ToString(),
                                Text = e.ToString()
                            });
}
@Html.DropDownListFor(m => m.Status, selectList)
40
dav_i

Modifié à partir de la réponse de @ dav_i.

Ce n'est pas parfait, mais c'est ce que j'utilise. Ci-dessous, une extension de HtmlHelper. La méthode d'extension ressemblera à EnumDropDownListFor à partir d'ASP.NET et utilisera DisplayAttribute s'il y en a une appliquée à la valeur Enum.

/// <summary>
/// Returns an HTML select element for each value in the enumeration that is
/// represented by the specified expression and predicate.
/// </summary>
/// <typeparam name="TModel">The type of the model.</typeparam>
/// <typeparam name="TEnum">The type of the value.</typeparam>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="expression">An expression that identifies the object that contains the properties to display.</param>
/// <param name="optionLabel">The text for a default empty item. This parameter can be null.</param>
/// <param name="predicate">A <see cref="Func{TEnum, bool}"/> to filter the items in the enums.</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
/// <returns>An HTML select element for each value in the enumeration that is represented by the expression and the predicate.</returns>
/// <exception cref="ArgumentNullException">If expression is null.</exception>
/// <exception cref="ArgumentException">If TEnum is not Enum Type.</exception>
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, Func<TEnum, bool> predicate, string optionLabel, object htmlAttributes) where TEnum : struct, IConvertible
{
    if (expression == null)
    {
        throw new ArgumentNullException("expression");
    }

    if (!typeof(TEnum).IsEnum)
    {
        throw new ArgumentException("TEnum");
    }

    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    IList<SelectListItem> selectList = Enum.GetValues(typeof(TEnum))
            .Cast<TEnum>()
            .Where(e => predicate(e))
            .Select(e => new SelectListItem
                {
                    Value = Convert.ToUInt64(e).ToString(),
                    Text = ((Enum)(object)e).GetDisplayName(),
                }).ToList();
    if (!string.IsNullOrEmpty(optionLabel)) {
        selectList.Insert(0, new SelectListItem {
            Text = optionLabel,
        });
    }

    return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes);
}

/// <summary>
/// Gets the name in <see cref="DisplayAttribute"/> of the Enum.
/// </summary>
/// <param name="enumeration">A <see cref="Enum"/> that the method is extended to.</param>
/// <returns>A name string in the <see cref="DisplayAttribute"/> of the Enum.</returns>
public static string GetDisplayName(this Enum enumeration)
{
    Type enumType = enumeration.GetType();
    string enumName = Enum.GetName(enumType, enumeration);
    string displayName = enumName;
    try
    {
        MemberInfo member = enumType.GetMember(enumName)[0];

        object[] attributes = member.GetCustomAttributes(typeof(DisplayAttribute), false);
        DisplayAttribute attribute = (DisplayAttribute)attributes[0];
        displayName = attribute.Name;

        if (attribute.ResourceType != null)
    {
            displayName = attribute.GetName();
        }
    }
    catch { }
    return displayName;
}

Par exemple:

@Html.EnumDropDownListFor(
    model => model.UserStatus,
    (userStatus) => { return userStatus != UserStatus.Active; },
    null,
    htmlAttributes: new { @class = "form-control" });

Cela créera une liste déroulante Enum sans l'option Actif.

28
Steven

Vous pouvez créer le menu déroulant vous-même en parcourant les valeurs de l'énumération et n'inclure que le <option> s'il n'est pas en attente.

Voici comment cela devrait fonctionner, mais comme vous pouvez le voir, je ne suis pas sûr de ce que vous utiliseriez pour la valeur ou le texte de la balise d'option.

<select>
foreach (var status in Enum.GetValues(typeof(UserStatus)))
{
    if(status != UserStatus.Pending)
    {
        <option value="status.???">@status.???</option>
    }
}
</select>
6

Vous trouverez ci-dessous une extension de HtmlHelper. Elle est très similaire à l'extension EnumDropDownListFor d'ASP.NET, mais elle trie SelectListItem par le nom d'affichage de l'élément. Il a un nom suggestif: SortedEnumDropDownListFor pour ne pas entrer en conflit avec l'extension d'origine.

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TModel">The type of the model.</typeparam>
    /// <typeparam name="TEnum">The type of the value.</typeparam>
    /// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
    /// <param name="expression">An expression that identifies the object that contains the properties to display</param>
    /// <param name="initalValue">The unselected item initial value</param>
    /// <param name="htmlAttributes"></param>
    /// <returns></returns>
    public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, string initalValue, object htmlAttributes = null)
    {

        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        Type enumType = GetNonNullableModelType(metadata);
        Type baseEnumType = Enum.GetUnderlyingType(enumType);
        List<SelectListItem> items = new List<SelectListItem>();

        foreach (FieldInfo field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
        {
            string text = field.Name;
            string value = Convert.ChangeType(field.GetValue(null), baseEnumType).ToString();
            bool selected = field.GetValue(null).Equals(metadata.Model);

            foreach (DisplayAttribute displayAttribute in field.GetCustomAttributes(true).OfType<DisplayAttribute>())
            {
                text = displayAttribute.GetName();
            }

            items.Add(new SelectListItem
            {
                Text = text,
                Value = value,
                Selected = selected
            });
        }

        items = new List<SelectListItem>(items.OrderBy(s => s.Text));
        items.Insert(0, new SelectListItem { Text = initalValue, Value = "" });

        return htmlHelper.DropDownListFor(expression, items, htmlAttributes);

    }        

    private static Type GetNonNullableModelType(ModelMetadata modelMetadata)
    {
        Type realModelType = modelMetadata.ModelType;
        Type underlyingType = Nullable.GetUnderlyingType(realModelType);

        if (underlyingType != null)
        {
            realModelType = underlyingType;
        }

        return realModelType;
    }

Si vous ne voulez pas vous soucier de l'élément non sélectionné, créez simplement une surcharge comme celle-ci:

public static MvcHtmlString SortedEnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, object htmlAttributes = null)
        {
            MvcHtmlString helper = SortedEnumDropDownListFor(htmlHelper, expression, string.Empty, htmlAttributes);
            return helper;
        }

Et vous êtes prêt à partir. J'espère que ça aide.

1
PedroSouki

Je cherchais la réponse à cette question en ce qui concerne .NET Core MVC. Étant donné le code suivant, vous pouvez limiter les énumérations que vous ne souhaitez pas afficher dans l'interface utilisateur:

<select asp-for="UserStatus" asp-items="@(Html.GetEnumSelectList<UserStatus>().Where(x => x.Value != 0))" class="form-control">
    <option selected="selected" value="">Please select</option>
</select>

J'espère que cela aidera toute autre personne à la recherche de cette réponse.

1
Kyle Barnes