Asp.net razor textbox array for list items
Asked Answered
B

2

13

I can't find or figure out how to take a list of items (cupcakes) and display them in razor with a quantity field.

What is happening is I am not able to get the values for each cupcake quantity in the list. Can you do textbox arrays in Razor?

VIEW

<div class="form-group">
    <label>Cupcakes</label>
    @foreach (var cupcake in Model.CupcakeList)
    {
        @Html.TextBox("CupcakeQuantities", cupcake.Id)  @cupcake.Name <br/>
    }
</div>

MODEL

public List<Cupcake> CupcakeList { get; set; }
public List<int> CupcakeQuantities { get; set; }

CONTROLLER

public ActionResult Create()
{
    var model = new PartyBookingModel()
    {
        CupcakeList = db.Cupcakes.ToList(),
        CupcakeQuantities = new List<int>()
    };

    return View(model);
}

CUPCAKE (ENTITY)

public class Cupcake
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal PerDozen { get; set; }
}
Basinger answered 10/6, 2014 at 21:4 Comment(2)
Your question seems to be inconsistent, you're showing CupcakeQuantites in your model, but in controller you're filling CupcakeSelection array. Could you please specify where is your quantity field located?Terreverte
Sorry, typo. Should be the CupcakeQuantities. Question updated.Basinger
R
39

You have to use an index, rather than foreach for it to work.

@for (int i = 0; i < Model.CupcakeList.Count; i++)
{
    @Html.TextBoxFor(x=>Model.CupcakeQuantities[i]) @Model.CupcakeList[i].Name <br/>
}

This will create sequentially named+number entries that will be recombined back into the model on post back.

I realise this may seem like "why doesn't foreach work?", but with foreach there is not enough reflected information available to TextBoxFor (as it is just a single object), whereas the array index is extracted by reflection from the Model.CupcakeQuantities[i] expression.

The receiving controller method should take the same as the model passed to the view:

e.g.

[HttpPost]
public ActionResult(PartyBookingModel model)
Recognizance answered 10/6, 2014 at 21:9 Comment(7)
Yes, that is what I was trying to figure out. But I don't know how to "capture" the values on post in the controller. Can your answer show that please?Basinger
Added example of receiving controller method. When you use the scaffolding wizards for EF models + create, you will usually get a good example to build on.Recognizance
Just realised I have put the wrong model property in the array... Now fixed to be your quantities :) It would be cleaner if the CupCake model contained a quantity property, rather than have 2 lists. e.g. adding a CupCakeCreate model that derives from CupCake and adds a Qty property is one option.Recognizance
I am not sure how to implement a CupCakeCreate model into the current model/view/controller. Your thought makes sense but I am a bit of a noob on this :)Basinger
My suggestion is not really applicable here as you are only editing the qty, but basically ViewModels are just C# classes with properties so you can always extend other models with inheritance. In this instance stick with the list of ints. Hope this helped. The key is the indexing of the properties. CheersRecognizance
changing it to x=>Model.CupcakeQuantities[i] gives an "Index out of range error. Also shouldn't i < Model.CupcakeList have .Count on the end?Basinger
Yes my bad. Typed all that from memory. Add basic .Count :)Recognizance
T
2

Try it this way:

view:

@for (int i = 0; i < Model.Count; i++)
{
    @Html.HiddenFor(x=>Model[i].Id) @Model[i].Name  
    @Html.TextBoxFor(x => Model[i].Quantity) <br/>
}

model:

public class CupcakeViewModel
{
   public int Id {get;set;}
   public string Name {get;set;}
   public int Quantity {get;set;}   
}

controller:

public ActionResult Create()
{
    var model = db.Cupcakes.Select(c => new CupcakeViewModel {
                                                Id = c.Id,
                                                Name = c.Name,
                                                Quantity = 0 
                           })
                           .ToList();

    return View(model);
}

[HttpPost]
public ActionResult Create(CupcakeViewModel[] cakes)
{
     //Save choosen cakes
}
Terreverte answered 10/6, 2014 at 21:21 Comment(6)
I am getting textboxes with "ProjectTest.Domain.Cupcake" text inside of them.Basinger
@Html.TextBoxFor(x=>Model.CupcakeList[i].Id) puts the Id in the value of the textbox, I need it to be empty as the user is entering in how many of each they want. I changed it to @Html.TextBoxFor(x=>Model.CupcakeList[i].Id, null) but it won't let me assign an int (Id) to a string. :(Basinger
Which property do you want to allow user to change? If it's Id - why is it should be empty? for geting it empty you should pass object with Value = "" like this: @Html.TextBoxFor(x=>Model.CupcakeList[i].Id, new { Value = "" })Terreverte
The way I am trying to make the form is 1) Call database, get list of cupcakes 2) display cupcakes with qty field for user to enter how many of each they want 3) Get values and build a order from each qty.Basinger
Thanks, actually I copied your code as template )))Terreverte
Well in that case :P :)Recognizance

© 2022 - 2024 — McMap. All rights reserved.