[SOLVED] id is null in mvc4 controller on form postback

Table of Contents

Issue

I’m trying to send to the cart controller some values but when I’m trying to access them in the cart controller they are null in the controller, although I have them in hidden field in the view with correct value.

That is happening when I’m trying to add item to a cart. This is what I have:

Razor view:

@using Solution.Order.Models
@model IEnumerable<CategoriesViewModel>

@{
    ViewBag.Title = "Categories";
}
@using (Html.BeginForm())
{
       <div class="panel-group">                   
    @foreach (var m in Model)
    {
        <div class="panel panel-default">
            <div class="panel-heading">
                <h4 class="panel-title">
                    <a data-toggle="collapse" id="#accordion" data-parent="#accordion" href="#@m.Categories.ID.ToString()">
                        @m.Categories.Name <span class="badge">@m.Categories.ItemCount</span>
                    </a>                     
                </h4>
            </div>
            <div id="@m.Categories.ID.ToString()" class="panel-collapse collapse">                
                <div class="panel-body">
                    <ul class="list-group">
                        @foreach (var i in m.Items)
                        {                            
                            <li class="list-group-item">
                                @i.Name | Price £@i.Price 
                                
                                @using (Html.BeginForm("AddToCart", "Cart"))
                                {
                                    <div class="pull-right">
                                        @Html.HiddenFor(k => @i.Id)
                                        @Html.Hidden("returnUrl", Request.Url.PathAndQuery)
                                        <input type="submit" class="btn btn-success" value="Add"/>
                                    </div>
                                }
                            </li>                            
                        }
                    </ul>  
                </div>
            </div>
        </div>     
    }        
</div>                                  
}

<script>
    $(document).ready(function() {
        $('#accordion').on('click', function() {
            $('#accordion .in').collapse('hide');
        });
    });
</script>

Controller content:

public RedirectToRouteResult AddToCart(Guid? Id, string returnUrl)
    {
        RestItem itemSingle = restItem.Items.FirstOrDefault(p => p.Id == Id);
        if (itemSingle != null)
        {
            GetCart().AddItem(itemSingle, 1);
        }
        return RedirectToAction("Index", new {returnUrl});
    }

In the controller, the Id value is null, although when I view the source of the page I’m able to see the hidden value for the id:

enter image description here

Since I’m still trying to find the best ways to develop in MVC, I know the approach I’m taking might not be the best one.

Solution

The input field you have in your form is having the name "i.Id" , but your action method expects parameter with name just Id.MVC model binding expects you to have the same name attribute values as your parameter name.

You may explicitly keep a hidden field with matching name

@foreach (var m in Model)
{
  <h4>Items</h4>
  <ul>
  @foreach(var i in m.Items)
  {
   <li>
     <h4>@i.Name | Price @i.Price</h4>
     @using(Html.BeginForm())
     {
       <div> 
          <input type="submit" class="btn btn-success" value="Add"/>
          @Html.Hidden("returnUrl", Request.Url.PathAndQuery)  
         
          <input type="hidden" name="Id" value="@m.Id" />   
 
       </div>
     }
    </li>
  }
}

This should work, Assuming the Id property of your Item is of type Guid.

Also, Your outer form tag is nolonger being used. You may remove it. Without seeing your viewmodel class, i won’t be able to say you are doing it wrong /rite.

Few suggestions

  • If you are showing many items in a loop, Consider using EditorTemplates.
  • In this specific case, I prefer to avoid the multiple form tags in my razor
    view and catch the submit button click event in javascript and read
    the hidden variable values (For returnUrl and itemId) and redirect
    the user to the new action method (Since you are not worried about
    keeping the action method with HttpPost attribute.

Answered By – Shyju

Answer Checked By – Dawn Plyler (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *