Dropdownlistfor in a for

Asked

Viewed 129 times

2

I am trying to fill in with the selected value one DropDownList within a for, but it’s not working properly. What happens is that when the Action Index returns the model to a View, values are not coming selected, always getting the first item of DropDownList selected.

I set a small example to facilitate.

I edited adding @Richarddias suggestions

To help, I committed to Github https://github.com/pablotdv/TesteDropDownEnum

Classes

public class Principal
{
    public MeuEnum Item { get; set; }
    public List<Teste> Teste { get; set; }
}

    public class Teste
    {
        public MeuEnum item { get; set; }
    }

    public enum MeuEnum
    {
        Item0 = 0,

        Item1 = 1,

        Item2 = 2,

        Item3 = 3,

        Item4 = 4,

        Item5 = 5,

        Item6 = 6,

        Item7 = 7,

        Item8 = 8,
    }

    public static class Helpers
    {
        public static SelectList MeuEnumItens(this HtmlHelper html)
        {
            var item0 = new SelectListItem() { Value = "Item0", Text = "0" };
            var item1 = new SelectListItem() { Value = "Item1", Text = "1" };
            var item2 = new SelectListItem() { Value = "Item2", Text = "2" };
            var item3 = new SelectListItem() { Value = "Item3", Text = "3" };
            var item4 = new SelectListItem() { Value = "Item4", Text = "4" };
            var item5 = new SelectListItem() { Value = "Item5", Text = "5" };
            var item6 = new SelectListItem() { Value = "Item6", Text = "6" };
            var item7 = new SelectListItem() { Value = "Item7", Text = "7" };
            var item8 = new SelectListItem() { Value = "Item8", Text = "8" };

            return new SelectList(new[] { item0, item1, item2, item3, item4, item5, item6, item7, item8 }, "Value", "Text");
        }
    }

Controller

 public class HomeController : Controller
{
    public ActionResult Index()
    {
        Principal p = new Principal()
        {
            Item = MeuEnum.Item6
        };
        p.Teste = new List<Teste>();

        p.Teste.Add(new Teste() { item = MeuEnum.Item0 });
        p.Teste.Add(new Teste() { item = MeuEnum.Item1 });
        p.Teste.Add(new Teste() { item = MeuEnum.Item2 });
        p.Teste.Add(new Teste() { item = MeuEnum.Item3 });

        return View(p);
    }
}

View

    @model TesteDropDownEnum.Controllers.Principal
@using TesteDropDownEnum.Controllers
@{
    ViewBag.Title = "Home Page";
}

<!--Assim funciona-->
@Html.DropDownListFor(a => a.Item, Html.MeuEnumItens(), "Selecione", htmlAttributes: new { @class = "form-control", @readonly = "readonly" })

@using (Html.BeginForm())
{
    for (int i = 0; i < Model.Teste.Count(); i++)
    {
        <div class="row form-group">
            <div class="col-md-12">
                <label>Origem da Mercadoria @Model.Teste[i].item</label>
                <!--Assim não funciona-->
                @Html.DropDownListFor(a => a.Teste[i].item, Html.MeuEnumItens(Model.Teste[i].item), "Selecione", htmlAttributes: new { @class = "form-control", @readonly = "readonly" })
            </div>
        </div>
    }
}
  • In the edition you made, in the method MeuEnumItens you must check that the received item is equal to the Enum item.

  • I modified the method MeuEnumItens in my reply to give an example.

  • I had already made the change you made, but it didn’t solve either.

  • I modified the return type of the Meuenumitens3 method for a Ienumerable<Selectlistitem> and returned the list directly and the problem was solved.

  • The answer has been edited. Try to replicate the edit to the Meuenumitens3 method and you will see that it will work. Here it worked with your GIT code.

  • I created a Fork in Git, if you want to take a look there.

  • @Richarddias we will look yes.

  • I made a pull request with the @Richarddias + Begincollectionitem response. Only one merge.

  • @Is this modification so that the names of the camps are correct? Would have the real need to use the partialview or could do the using(Html.BeginCollectionItem) before we go and play Dropdown cool? I wonder why I never used this package and probably soon I will need a project, and I want to take advantage and do it this way if it will save work.

  • @Richarddias You can do without the Partial, but it gets harder because of the fields with Expression. What you need is just call me on chat or call me on Facebook that I help you.

Show 5 more comments

1 answer

2


The object SelectListItem owns a property Selected. if she has the value true, this item will be selected. If no item has a value true for this property the value selected is the parameter optionalLabel of DropDownListFor, if it exists. In the example below I modified and put as "Select". You doing this the problem of always coming the first selected must end.

@Html.DropDownListFor(a => a.Teste[i].item, Html.MeuEnumItens(), "Selecione", htmlAttributes: new { @class = "form-control", @readonly = "readonly" })

It would be interesting that your method MeuEnumItens accept one more optional parameter (MeuEnum? valorSelecionado) and perform comparison to set the property value Selected of the 'Selectlistitem' object. I took advantage of and left a hint on how to modify the creation of selectlists of Enumerators.

public static IEnumerable<SelectListItem> MeuEnumItens(this HtmlHelper html, MeuEnum? itemSelecionado)
{
    var lista = new List<SelectListItem>();

    foreach (MeuEnum item in System.Enum.GetValues(typeof(MeuEnum)))
    {
        lista.Add(new SelectListItem() { Text = item.ToString("F"), Value = item.ToString(), Selected = (itemSelecionado.HasValue ? itemSelecionado.Value == item : false) });
    }

    return lista;
}

Finally, make use of the Begincollectionitem to generate the list of Dropdowns dynamically, with the Binding correct:

Index.cshtml

foreach (var teste in Model.Testes)
{
    @Html.Partial("_Item", teste)
}

_Item.cshtml

@model TesteDropDownEnum.Controllers.Teste
@using TesteDropDownEnum.Controllers

@using (Html.BeginCollectionItem("Testes"))
{
    <div class="row form-group">
        <div class="col-md-12">
            <label>Origem da Mercadoria @Model.item</label>
            @Html.DropDownListFor(model => model.item, Html.MeuEnumItens(Model.item), "Selecione", htmlAttributes: new { @class = "form-control", @readonly = "readonly" })
        </div>
    </div>
}
  • The funny thing that out of the for works normally, without needing additional parameter.

  • Try using a foreach instead of for. Using an editor can be another output.

  • But with a foreach can’t give post and with the for yes.

  • This answer is correct, but you need to quote Begincollectionitem to be complete. The central problem is not the generation of the form, but the Binding as a whole.

  • @Ciganomorrisonmendez would have how to make an example?

  • @The Begincollectionitem is a separate package. Automatic Binding is not required to be correct. If its extension method receives an additional parameter as stated in the response it can validate whether the Enum foreach is the value passed by parameter and set the property Selected = true; that will work normally.

  • Yes, I agree, but he wants a little more.

  • @Pablovargas I’ll make one Fork of your package and put it all there.

  • @Ciganomorrisonmendez Blz, thank you for your cooperation

  • The weirdest I added one @Html.DropDownList("Teste", Html.MeuEnumItens(MeuEnum.Item5)) and did not render the View with the Item5 selected.

Show 5 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.