7

I am fairly new to MVC and am really trying to a get used to the Model Binding. I have a simple model that i have created in a form. However, when i post that form ONLY the textbox values are carrying over to the controller. I need the description field also which is done using DisplayTextFor. Is this something i am going to have to make a custom model binder for? I could take a shortcut and just make the description a read only textbox with no border so it looks like text, but i want to do it the correct way. Here is my code:

public class FullOrder
{
    public List<FullOrderItem> OrderList { get; set; }
    public string account { get; set; }
    public string orderno { get; set; }
}

public class FullOrderItem
{
    public int? ID { get; set; }
    public int? OrderId { get; set; }
    public string Description { get; set; }
    public int Qty { get; set; }
    public decimal? Price { get; set; }
}

Here is the View

<table class="ExceptionAltRow">
    <tr style="background-color: #DDD;">
        <td class="strong" style="width:500px;">
            Description
        </td>
        <td class="strong" style="width:100px;">
            Qty
        </td>
        <td class="strong" style="width:100px;">
            Previous Purchases
        </td>
    </tr>
    @for (int i = 0; i < Model.FullOrder.OrderList.Count(); i++)
    {
        <tr>
            <td>
                @Html.DisplayTextFor(m => m.FullOrder.OrderList[i].Description)
            </td>
            <td>
                @Html.TextBoxFor(m => m.FullOrder.OrderList[i].Qty, new { @style = "width:50px;" })
            </td>
        </tr>
    }
    </table>

Here is the Controller:

[HttpPost]
public ActionResult AddItem(FullOrder f)
{
    //doesn't work description is not passed but qty is
}

Is there a way that i can get my Model to just simply pass on the description on a post even though it is not a textboxfor bound item from my model?

CAbbott
  • 7,998
  • 4
  • 29
  • 38
mscard02
  • 285
  • 4
  • 15

3 Answers3

2

The only data that will be posted to your application is that data which is available on the form that's being submitted (unless the form fields are disabled, of course). You can override what the controller sees by implementing a custom model binder.

In this case, your form consists of many instances of a single text field:

@Html.TextBoxFor(m => m.FullOrder.OrderList[i].Qty, new { @style = "width:50px;" })

If you'd like description and other things filled out, they need to be present on the form. If they don't need to be visible, then you can use the HiddenFor helper:

@Html.HiddenFor(m => m.FullOrder.OrderList[i].Description)

See also What does Html.HiddenFor do?

Community
  • 1
  • 1
Kaleb Pederson
  • 43,537
  • 19
  • 96
  • 144
1

Of course you cannot make it work that way

First, you should know that model binding occurs basically using data send from inputs on client side. Html.DisplayTextFor helper does not generate input, it generates simple text. Texts do not participate in data, sent from client when the form is submitted, so you do not get them model-bound. If you take a look at Request.Form property, you should see the proof - there're no description fields.

What you can do if you want to display text and also let description participate in form values, is to use hidden field. MVC got helper for this

 @for (int i = 0; i < Model.FullOrder.OrderList.Count(); i++)
    {
        <tr>
            <td>
                @Html.DisplayTextFor(m => m.FullOrder.OrderList[i].Description)
                @Html.HiddenFor(m => m.FullOrder.OrderList[i].Description)
            </td>
            <td>
                @Html.TextBoxFor(m => m.FullOrder.OrderList[i].Qty, new { @style = "width:50px;" })
            </td>
        </tr>
    }

This way, submitted form will contain description values too

archil
  • 37,513
  • 7
  • 61
  • 81
0

The DisplayTextFor function is only going to output that text to the browser's DOM. The MVC framework's binding basically looks at the POST/GET variables, and automatically sets those values to your model.

If you want to bind any data automatically (such as your description text) you would have to store that to some type of input and/or hidden field. Hidden fields work but are inefficient since you're putting a bunch of extra elements in your HTML and could even be edited by the user with something like Firebug.

My recommendation and what I've always done is to expect not to have some of that information posted back, and just set it explicitly within the controller action:

 [HttpPost]
    public ActionResult AddItem(FullOrder f)
    {
         // Next line is just showing that you should get the existing order
         // from your data layer
         FullOrder existingOrder = orderRepository.GetExistingOrder();

         // Now loop through f.OrderList and update the quantities
         foreach(OrderItem item in f.OrderList) {
             // Find the existing item and update the quantity.
         }

         // Now you have the original information from the DB along with
         // updated quantities.

         // Save results or do whatever is next
         existingOrder.Save();
    }
jkriddle
  • 688
  • 6
  • 15