ccocker
ccocker

Reputation: 1236

MVC Passing Values to Controller

Need some advice on an approach. I have designed a view using a table structure to get the layout I need and populate that table with a foreach loop based on my ViewModel.

I essentially want the user to be able to update some of the fields like noofusers etc and I want to have an addotcart button which will pass those values to the controller.

The problem I have at present is the values do not get passed by the form as they exist outside the form.

If I put in the values in the form I loose any formatting that I get from having a table.

If i repeat the values inside the form but change to hidden for, I get the values from the model passed in not the updated values

I have searched some other posts and have another post on here where it is suggested to not use foreach and use a for loop instead, but that doesn't really change anything in relation to the problem I am experiencing above.

Code is shown below - any suggestions on a general approach to achieve a simple form with a nice layout and still be able to pass values to the controller via a form would be appreciated.

@model PagedList.IPagedList<ShoppingCartCatalogue>
@using Mojito.Domain.ViewModels
@using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Mojito Products</h2>
<div class="col-md-9"></div>
<div class="col-md-3">
    @using (Html.BeginForm("Index", "MojitoProducts", FormMethod.Get))
    {
        <p>
            @Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
            <input type="submit" value="Search" />
        </p>
    }
</div>

<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.FirstOrDefault().ImageData)
        </th>
        <th>
            @Html.ActionLink("Category", "Index", new { sortOrder = ViewBag.SortByCategory, currentFilter = ViewBag.CurrentFilter })
        </th>
        <th>
            @Html.ActionLink("Product", "Index", new { sortOrder = ViewBag.SortByProduct, currentFilter = ViewBag.CurrentFilter })
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FirstOrDefault().Description)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FirstOrDefault().TypeOfSubscription)
        </th>
        <th>
            @Html.ActionLink("Price per user", "Index", new { sortOrder = ViewBag.SortByPrice, currentFilter = ViewBag.CurrentFilter })
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FirstOrDefault().NoOfUsers)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.FirstOrDefault().TotalPrice)
        </th>

    </tr>

    @foreach (ShoppingCartCatalogue t in Model)
    {

        <tr>
            <td>
                @if (t.ImageData != null)
                {
                    <div class="pull-left" style="margin-right: 10px">
                        <img class="img-thumbnail" width="75" height="75"
                             src="@Url.Action("GetImage", "MojitoProducts",
                                                  new { t.MojitoProductId })" />
                    </div>
                }
            </td>
            <td>
                @Html.DisplayFor(modelItem => t.Category, new { Name = "Category", id = "Category" })
            </td>
            <td>
                @Html.DisplayFor(modelItem => t.Name, new { Name = "Name", id = "Name" })
            </td>
            <td>
                @Html.DisplayFor(modelItem => t.Description, new { Name = "Description", id = "Description" })
            </td>
            <td>
                @Html.EnumDropDownListFor(modelItem => t.TypeOfSubscription, new { Name = "TypeOfSubscription", id = "TypeOfSubscription" })
            </td>
            <td>
                @Html.DisplayFor(modelItem => t.Price, new { Name = "Price", id = "Price" })
            </td>
            <td>
                @Html.TextBoxFor(modelItem => t.NoOfUsers, new { Name = "NoOfUsers", id = "NoOfUsers", type = "number", min = "1" })
            </td>
            <td>
                @if (t.TypeOfSubscription.ToString() == "Annual")
                {
                    t.TotalPrice = t.Price * 12;
                }
                else
                {
                    t.TotalPrice = t.Price;
                }
                @Html.DisplayFor(modelItem => t.TotalPrice, new { Name = "Total Price", id = "Total Price" })
            </td>
            <td>

                @using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
                {
                    <div class="pull-right form-group">
                        @if (Request.Url != null)
                        {
                            @Html.HiddenFor(modelItem => t.TypeOfSubscription, new { Name = "TypeOfSubscription", id = "TypeOfSubscription" })
                            @Html.HiddenFor(modelItem => t.NoOfUsers, new { Name = "NoOfUsers", id = "NoOfUsers" })
                            @Html.HiddenFor(modelItem => t.MojitoProductId, new { Name = "MojitoProductId", id = "MojitoProductId" })
                            @Html.HiddenFor(modelItem => t.Category, new { Name = "Category", id = "Category" })
                            @Html.HiddenFor(modelItem => t.Name, new { Name = "Name", id = "Name" })
                            @Html.HiddenFor(modelItem => t.Description, new { Name = "Description", id = "Description" })
                            @Html.HiddenFor(modelItem => t.Price, new { Name = "Price", id = "Price" })
                            if (t.TypeOfSubscription.ToString() == "Annual")
                            {
                                t.TotalPrice = t.Price * 12;
                            }
                            else
                            {
                                t.TotalPrice = t.Price;
                            }
                            @Html.HiddenFor(modelItem => t.TotalPrice, new { Name = "Total Price", id = "Total Price" })
                            @Html.Hidden("returnUrl", Request.Url.PathAndQuery)
                            <input type="submit" class="btn btn-success" value="Add to cart" />
                        }

                    </div>
                }
            </td>
        </tr>

    }

</table>

<div class="col-md-12">
    Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount
</div>
@Html.PagedListPager(Model, page => Url.Action("Index",
        new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))

Upvotes: 0

Views: 758

Answers (2)

user3559349
user3559349

Reputation:

3 possible solutions:

  1. Don't use a html tables but instead use css to layout the controls within each form element to give you a tabular layout (for example using floats or absolutely positioned elements
  2. Use jquery to update update the hidden elements with the form whenever the corresponding control outside the form changes (but with this solution your just rendering twice as many controls as necessary and your generating invalid html because of duplicate ID's)
  3. Replace the form and submit elements with a button and use jquery ($.post() method) to post the values to the controller. The advantage of this method is the user stays on the form and can continue to add more elements to the shopping cart. The page would then include a link to the checkout page that shows all items that have been added

Upvotes: 0

Mark
Mark

Reputation: 4873

This is a css issue, not really a mvc issue. Compare the css being applied to the table outside of the form, with the css being applied to the table inside the form. It's probably just a matter of adding a class to the table and your css file.

Upvotes: 2

Related Questions