so my intention is to make a button that allow a user to add an item to his Cart, in the db.savechanges method it catch these exceptions :
Property: Item_Name Error: The Item_Name field is required.
iisexpress.exe Information: 0 : Property: Item_Description Error:
The Item_Description field is required. s
i checked from my db and every single item has all their properties filled up, since i am new to asp.net i am surely missing something obvious that is messing with my data.
this is the view(trying to pass the item object in actionlink
#foreach (var item in Model)
{
if (index > 6)
{
index = 0;
}
var newrow = 0;
if (index == 0)
{
newrow = 1;
}
if (newrow == 1)
{
index++;
<div class="product-one">
<div class="col-md-2 product-left">
<div class="p-one simpleCart_shelfItem jwe">
<a href="single.html">
<!-- go to product single view page-->
#{ if (item.Image.Image1 != null)
{
string imageBase64 = Convert.ToBase64String(item.Image.Image1);
string imageSrc = string.Format("data:image/png;base64,{0}", imageBase64);
<img src="#imageSrc" width="100" height="100" />
}
}
#Html.ActionLink("Add to Cart", "AddToCart", "Carts", new { itemdata = item }, new { #class = "btn btn-primary btn-large" })
</a>
<br />
</div>
</div>
</div>
this is the controller:
public ActionResult AddToCart(Item item)
{
//var query = from itemsel in db.Items where item.Item_ID == item.Item_ID select item;
var newcart = new Cart();
newcart.Account_ID = 1;
newcart.Cart_ID = 3;
newcart.Item_ID = item.Item_ID;
newcart.Item = item;
var itemsgroup = db.Items;
try
{
db.Carts.Add(newcart);
db.SaveChanges();
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}",
validationError.PropertyName,
validationError.ErrorMessage);
}
}
}
return View(itemsgroup.ToList());
}
and this is the cart model:
public partial class Cart
{
public int Cart_ID { get; set; }
public int Account_ID { get; set; }
public int Item_ID { get; set; }
public virtual Item Item { get; set; }
}
}
p.s i know my view is tricky but i am desperate to finish this project very soon, any suggestion for a better way of doing it would be welcomed
Since you are missing too many pieces, I could only point you to right direction.
Download the sample source code of Pro ASP.NET MVC 5 book By Adam Freeman.
Extract Chapter 9 - SportsStore, and look at those two files-
SportsStore.WebUI > Views > Product > List.cshtml
#foreach (var p in Model.Products) {
#Html.Partial("ProductSummary", p)
}
SportsStore.WebUI > Views > Shared > ProductSummary.cshtml
Notice that it uses BeginForm to add individual item to shopping cart.
#using (Html.BeginForm("AddToCart", "Cart")) {
<div class="pull-right">
#Html.HiddenFor(x => x.ProductID)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-success" value="Add to cart" />
</div>
}
Related
I'm trying to integrate pay pal into my custom cart. I have used information on official Pay Pal site for integration. I'm using my sandbox account for testing the payment. It dose not seem to work and I don't know what is causing the problem. When calling the pay Pal view it just returns pay pal error.
Here is the PayPalPartialView:
#{
int count = 1;
}
<form class="paypalform" action="https://www.paypal.com/us/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_cart">
<input type="hidden" name="upload" value="1">
<input type="hidden" name="business" value="sb-2mrjh7443549#personal.example.com">
#foreach (var item in Model)
{
<input type="hidden" name="item_name_#count" value="#item.ProductName" />
<input type="hidden" name="amount_#count" value="#item.Price" />
<input type="hidden" name="quantity_#count" value="#item.Quantity" />
count++;
}
<input type="hidden" name="currency_code" value="EUR">
<input type="image" src="http://www.paypal.com/en_US/i/btn/x-click-but01.gif" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
</form>
Also the cart index view:
#model CartViewModel
#{
ViewData["Title"] = "Cart Overview";
}
#if (Model.CartItems.Count > 0)
{
<h1>Cart Overview</h1>
<div class="cartWrapper">
<div class="cartbg d-none">
<h3 class="text-center">Redirecting you to paypal...</h3>
<img src="~/Images/ajax_loader.gif" />
</div>
<table class="table">
<tr>
<th>Product</th>
<th>Quantity</th>
<th></th>
<th>Price</th>
<th>Total</th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr>
<td>#item.ProductName</td>
<td>#item.Quantity</td>
<td>
<a asp-action="Add" asp-route-id="#item.ProductId" class="btn btn-sm btn-primary">+</a>
<a asp-action="Decrease" asp-route-id="#item.ProductId" class="btn btn-sm btn-success">-</a>
<a asp-action="Remove" asp-route-id="#item.ProductId" class="btn btn-sm btn-danger">Remove</a>
</td>
<td>#item.Price.ToString("C2")</td>
<td>#Model.CartItems.Where(x => x.ProductId == item.ProductId).Sum(x => x.Quantity * x.Price).ToString("C2")</td>
</tr>
}
<tr>
<td class="text-right" colspan="4">Grand total: #Model.GrandTotal.ToString("C2")</td>
</tr>
<tr>
<td class="text-right" colspan="4">
<a asp-action="Clear" class="btn btn-danger">Clear cart</a>
Checkout
</td>
</tr>
</table>
</div>
}
else
{
<h3 class="display-4 text-center">Cart is empty</h3>
}
<partial name="~/Views/Cart/_PayPalPartial.cshtml" for="CartItems" />
#section Scripts{
<script>
$(function () {
$("a.checkout").click(function (e) {
e.preventDefault();
$("div.cartbg").removeClass("d-none");
$.get("/cart/clear", {}, function () {
$("form.paypalform").submit();
});
});
});
</script>
}
the cart controller:
using CmsShoppingCart.Infrastructure;
using CmsShoppingCart.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CmsShoppingCart.Controllers
{
public class CartController : Controller
{
private readonly CmsSchoppingCartContext context;
public CartController(CmsSchoppingCartContext context)
{
this.context = context;
}
//GET /cart
public IActionResult Index()
{
List<CartItem> cart = HttpContext.Session.GetJson<List<CartItem>>("Cart") ?? new List<CartItem>();
CartViewModel cartVM = new CartViewModel
{
CartItems = cart,
GrandTotal = cart.Sum(x => x.Price * x.Quantity)
};
return View(cartVM);
}
//GET /cart/add/id
public async Task<IActionResult> Add(int id)
{
Product product = await context.Products.FindAsync(id);
List<CartItem> cart = HttpContext.Session.GetJson<List<CartItem>>("Cart") ?? new List<CartItem>();
CartItem cartItem = cart.Where(x => x.ProductId == id).FirstOrDefault();
if (cartItem == null)
{
cart.Add(new CartItem(product));
}
else
{
cartItem.Quantity += 1;
product.Quantity--;
context.SaveChanges();
}
HttpContext.Session.SetJson("Cart", cart);
if(HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
return RedirectToAction("Index");
return ViewComponent("SmallCart");
}
//GET /cart/decrease/id
public async Task<IActionResult> Decrease(int id)
{
Product product = await context.Products.FindAsync(id);
List<CartItem> cart = HttpContext.Session.GetJson<List<CartItem>>("Cart");
CartItem cartItem = cart.Where(x => x.ProductId == id).FirstOrDefault();
if (cartItem.Quantity > 1)
{
--cartItem.Quantity;
product.Quantity++;
context.SaveChanges();
}
else
{
cart.RemoveAll(x => x.ProductId == id);
}
if (cart.Count == 0)
{
HttpContext.Session.Remove("Cart");
}
else
{
HttpContext.Session.SetJson("Cart", cart);
}
return RedirectToAction("Index");
}
//GET /cart/remove/id
public IActionResult Remove(int id)
{
List<CartItem> cart = HttpContext.Session.GetJson<List<CartItem>>("Cart");
cart.RemoveAll(x => x.ProductId == id);
if (cart.Count == 0)
{
HttpContext.Session.Remove("Cart");
}
else
{
HttpContext.Session.SetJson("Cart", cart);
}
return RedirectToAction("Index");
}
//GET /cart/clear
public IActionResult Clear()
{
HttpContext.Session.Remove("Cart");
// return RedirectToAction("Page", "Pages");
//return Redirect("/");
if (HttpContext.Request.Headers["X-Requested-With"] != "XMLHttpRequest")
return Redirect(Request.Headers["Referer"].ToString());
return Ok();
}
}
}
Cart model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CmsShoppingCart.Models
{
public class CartItem
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal Total { get { return Quantity * Price; } }
public string Image { get; set; }
public CartItem()
{
}
public CartItem(Product product)
{
ProductId = product.Id;
ProductName = product.Name;
Price = product.Price;
Quantity = 1;
Image = product.Image;
}
}
}
And cart View model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CmsShoppingCart.Models
{
public class CartViewModel
{
public List<CartItem> CartItems { get; set; }
public decimal GrandTotal { get; set; }
}
}
Its too late but for someone who are wondering about this issue:
Change PayPal Sandbox Url to:
https://www.sandbox.paypal.com/cgi-bin/webscr
I am attempting to send a ViewModel with a IList<Hole> from the view to the controller after data is gathered in a for loop to pass into a method, however, the ViewModel being passed continues to be null. What am I missing that is not passing the ViewModel from the View to the Controller?
My ViewModel is:
public class HoleViewModel : IEnumerable
{
public int FacilityId { get; set; }
public int CourseId { get; set; }
//public Hole Hole { get; set; }
public IList<Hole> Holes { get; set; }
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
My View is:
#using GT_App.Models
#model GT_App.ViewModel.HoleViewModel
....
<form method="post" action="/Hole/Create">
<fieldset>
<div>
#{
var holeCount = 4;
}
<table style="display: inline">
<thead>
<th>Number</th>
<th>Yardage</th>
<th>Par</th>
<th>Hdcp</th>
</thead>
#for (int i = 0; i < holeCount; i++)
{
<tr>
<td>
#Html.TextBoxFor(m => m.Holes[i].Number)
</td>
<td>
#Html.TextBoxFor(m => m.Holes[i].Yardage)
</td>
<td>
#Html.TextBoxFor(model => model.Holes[i].Par)
</td>
<td>
#Html.TextBoxFor(model => model.Holes[i].Handicap)
</td>
</tr>
}
</table>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
My Controller is:
public ActionResult Create()
{
ViewBag.FacilityId = new SelectList(db.Facilities, "FacilityId", "Name");
ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(HoleViewModel holes)
{
if (ModelState.IsValid)
{
for (int i = 0; i < holes.Holes.Count; i++)
{
var item = new Hole();
if (Session["FacilityId"] != null || Convert.ToInt32(Session["FacilityId"]) != 0)
{
item.FacilityId = Convert.ToInt32(Session["FacilityId"]);
}
if (Session["CourseId"] != null || Convert.ToInt32(Session["CourseId"]) != 0)
{
item.CourseId = Convert.ToInt32(Session["CourseId"]);
}
item.Number = Convert.ToInt32(Request.Form["Number" + i]);
item.Yardage = Convert.ToInt32(Request.Form["Yardage" + i]);
item.Par = Convert.ToInt32(Request.Form["Par" + i]);
item.Handicap = Convert.ToInt32(Request.Form["Handicap" + i]);
holes.Holes.Add(item);
}
// itterate thru collection to add individual holes to Entity
foreach (Hole hole in holes)
{
db.Holes.Add(hole);
db.SaveChanges();
}
//return RedirectToAction("Index");
}
ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "Name", Session["CourseId"]);
//return View(Session["CourseId"]);
return RedirectToAction("Index");
}
If there's a model validation error in your second Create action, then typically you'd return the view again using the submitted model, which would then show the validation errors on the webpage.
You're not doing that - you're redirecting to the Index action regardless of whether the model was valid. I'd put the RedirectToAction call just after the call to SaveChanges, and then at the end of the method return View(holes);.
Oh, and I wouldn't put the SaveChanges call inside the loop. Do it after the loop. There are other issues with that code, but I'm going to stop there... :-)
I am new to asp .net mvc 4.0. i have given model. i am not getting how can i create view for model. I am facing problem at IList JournalEntries. other entry i am able to do.
public class Journal : BaseClass
{
public virtual string VoucherNo { get; set; }
public virtual DateTime VoucherDate { get; set; }
public string VoucherDateView {
get
{
return VoucherDate.ToShortDateString();
}
}
public IList<JournalEntry> JournalEntries { get; set; }
public IList<Ledger> Accounts { get; set; }
public double TotalAmount
{
get
{
double sum = 0;
if (JournalEntries != null && JournalEntries.Count>0)
foreach (var journal in JournalEntries)
sum = journal.Principal + journal.Interest+sum;
return sum;
}
}
}
I have tried below view but add entry doesn't works.
#model Sms.CoreSociety.Journal
#{
ViewBag.Title = "Create";
}
#{
string data = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model);
}
<script type="text/javascript">
$(document).ready(function () {
$('#document').validate();
$("#VoucherDate").mask("99/99/9999", { placeholder: " " });
function entryVm(entries) {
var self = this;
self.entryList = ko.observableArray(entries);
self.entry = ko.observable();
self.rowClick = function(entry1) {
alert("Delete alert");
self.dispatchList.remove(entry1);
};
self.addEntry = function() {
alert("Add alert");
this.entryList.push({ AccountName_AccountHead: "", DebitCredit: "", Principal: "0.0", Interest: "0.0", Narration: ""});
};
}
var models = #Html.Raw(Json.Encode(Model.JournalEntries)) ;
ko.applyBindings(new entryVm(models));
});
</script>
#using (Html.BeginForm(null, null, FormMethod.Post, new Dictionary<string, object>() { { "class", "form-horizontal" }, { "id", "document" } }))
{
#Html.ValidationSummary(true)
<fieldset>
<div class="row">
<div class="span1">
<label>Voucher No</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.VoucherNo)
</div>
</div>
<div class="row">
<div class="span1">
<label>Voucher Date</label>
</div>
<div class="span5">
#Html.TextBoxFor(model => model.VoucherDate, "{0:dd/MM/yyyy}", new Dictionary<string, object>() { { "class", "required" } })
</div>
</div>
<div class="row">
<div class="span1">
<label>Amount</label>
</div>
<div class="span5">
#Html.DisplayFor(model => model.TotalAmount)
</div>
</div>
<input type="submit" value="Save" class="btn" id="submit"/>
#if (Model.Id != new Guid())
{
<div style="float: right">
<a class="btn btn-danger" href='#Url.Action("Delete")/#Model.Id' aria-hidden="true">Delete</a>
</div>
}
</fieldset>
}
<h4>Journal Entry</h4>
<p >Entry for<span data-bind="text: entryList().length"> </span> entry(s)</p>
<button data-bind="click: addEntry" class="btn">Add Record</button>
<table>
<tbody data-bind="template: { name: 'entryRowTemplate', foreach: entryList }"></tbody>
</table>
<script type="text/html" id="entryRowTemplate">
<tr>
<td>AccountName_AccountHead: \$ <input data-bind="value: AccountName.AccountHead"/> </td>
<td>DebitCredit: \$ <input data-bind="value: DebitCredit"/></td>
<td>Principal: \$ <input data-bind="value: Principal"/></td>
<td>Interest: \$ <input data-bind="value: Interest"/></td>
<td>Narration: \$ <input data-bind="value: Narration"/></td>
<td>Delete</td>
</tr>
</script>
below is my Journal controller
using System;
using System.Linq;
using System.Web.Mvc;
using Sms.CoreSociety;
using System.Collections.Generic;
namespace SmsModernUI.Controllers
{
public class JournalController : BaseController
{
//
// GET: /AccountGroup/
public ActionResult Index()
{
var journals = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo);
return View(journals);
}
public ActionResult Create(Guid id)
{
if (id == new Guid())
{
var journal = new Journal();
string lastvoucherno = Repository.GetAll<Journal>().OrderBy(x => x.VoucherNo).Last().VoucherNo;
journal.VoucherNo = (int.Parse(lastvoucherno) + 1).ToString();
journal.VoucherDate = System.DateTime.Now;
journal.JournalEntries = new List<JournalEntry>();
journal.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal);
}
var journal1 = Repository.Get<Journal>(id);
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == id);
journal1.Accounts = Repository.GetAll<Ledger>();
return PartialView(journal1);
}
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Journal journal)
{
if (journal.Id == new Guid())
{
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
else
{
Journal jr = Repository.Get<Journal>(journal.Id);
var entries = Repository.GetAll<JournalEntry>(x=>x.Journal.Id == journal.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var jj = Repository.Save(journal);
foreach (var journalentry in journal.JournalEntries)
{
journalentry.Id = jj.Id;
Repository.Save(journalentry);
}
}
return RedirectToAction("Index");
}
public ActionResult Index1()
{
Journal journal1 = Repository.Get<Journal>(new Guid("7A6EEBBC-2F3A-4A27-ACF8-A1D40115A68F"));
journal1.JournalEntries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == journal1.Id);
journal1.Accounts = Repository.GetAll<Ledger>();
return View(journal1);
}
public ActionResult Delete(Guid id)
{
Journal jr = Repository.Get<Journal>(id);
var entries = Repository.GetAll<JournalEntry>(x => x.Journal.Id == jr.Id);
foreach (var entry in entries)
{
Repository.Delete(entry);
}
var result = Repository.Delete(jr);
return RedirectToAction("Index");
}
[HttpPost]
public ActionResult Create1(Journal journal)
{
var temp = journal;
return RedirectToAction("Create",journal.Id);
}
}
}
Views are not genereted from models. You need Controller Action method to pass your model to View.
public ActionResult()
{
var model = new Journal
{
//**define here value of model's properties, that you need in View
}
return View(model);
}
EDITED: After your addition.
I would devide it into two parts. Create ViewModel and pass it from View To Controller.
public JurnalViewModel
{
public Journal journal {get; set;}
public IList<JournalEntry> JournalEntries {get; set;}
}
Than in Create action first create journal and after foreach JournalEntries in model create new JournalEntry.
EDITED 2 To your comment. Quick sample:
[HttpPost]
public ActionResult Create (JurnalViewModel model)
{
var journal = new Journal();
db.Journals.Add(journal);
journal.name = model.journal.name
.....
//**some code
db.SaveChanges()
foreach(var item in model.JournalEntries )
{
var entry = new JournalEntry()
db.JournalEntries .Add(entry);
entry.property = item.property;
....
//**some code
db.SaveChanges()
}
}
Your problem is that you have no class constructor for JournalEntries.
public Journal()
{
JournalEntries = new List<JournalEntry>();
Accounts = new List<Ledger>();
}
Right click to your Action method inside controller and click add view then check create strongly typed-view checkbox then choose your desired model from dropdown in displayed dialogue box
I tried this code but I have error like this:
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[XNet.Repository.Model.RoomType]',
but this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[XNet.Repository.Model.EditRoomTypeViewModel]'.
I don't know, whats part give an error. Please help.
my service
public List<EditRoomTypeViewModel> GetViewRoom(int RoomTypeID)
{
List<RoomType> roomTypes = (from d in _RoomTypeRepository.All()
select d).ToList();
List<EditRoomTypeViewModel> editRoomTypeViewModel = new List<EditRoomTypeViewModel>();
foreach (RoomType roomType in roomTypes)
{
editRoomTypeViewModel.Add(new EditRoomTypeViewModel
{
RoomTypeID = RoomTypeID,
RoomTypeName = roomType.RoomtypeName,
RoomTypeDescription = roomType.RoomTypeDescripton,
});
}
return editRoomTypeViewModel;
}
my controller
public ActionResult Room()
{
ViewBag.hotel = _hotelService.GetByID(2).HotelName;
List<EditRoomTypeViewModel> editRoomTypeViewModel = _roomViewService.GetViewRoom(_HotelID);
return View(editRoomTypeViewModel.FirstOrDefault());
}
my view model
public class EditRoomTypeViewModel
{
public int RoomTypeID { get; set; }
public string RoomTypeName { get; set; }
public string RoomTypeDescription { get; set; }
}
my view
#model IEnumerable<XNet.Repository.Model.EditRoomTypeViewModel>
#{
ViewBag.Title = "Room";
}
<h2>Room</h2>
<div>
#Html.Label("Hotel Name");
</div>
<div>
#ViewBag.hotel
</div>
<table>
#foreach (var a in Model)
{
<tr>
<td>
#Html.DisplayFor(model => a.RoomTypeName)
</td>
<td>
<input style="width:100px;" type="button" title="EditRoomType" value="Edit" onclick="location.href='#Url.Action("EditRoom", "Hotel", new { RoomTypeID = a.RoomTypeID})'" />
</td>
</tr>
}
</table>
<input style="width:200px;" type="button" title="EditRoomType" value="New Room Type" onclick="location.href='#Url.Action("NewRoom", "Hotel") '" />
I noticed that you returned just one editRoomTypeViewModel object in your controller, but in your view you declared the model as IEnumerable<XNet.Repository.Model.EditRoomTypeViewModel>.
Another point is that the error seems to be related to an assignment of ViewBag somewhere else, cause it contains thisdictionaryrequires a model item of type and probablt the only thing that is of type dictionary is ViewBag.
Just remove the .FirstOrDefault() in the controller action and you should be good to go.
public ActionResult Room()
{
ViewBag.hotel = _hotelService.GetByID(2).HotelName;
List<EditRoomTypeViewModel> editRoomTypeViewModel = _roomViewService.GetViewRoom(_HotelID);
return View(editRoomTypeViewModel);
}
I have a simple shopping cart model which contains a list of items:
public class ShoppingCart
{
public List<Item> Items { get; set; }
public double Tax { get; set; }
// ... some other properties
}
public class Item
{
public string Name { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
public double TotalCost { get { return Quantity * Price; } }
}
I want to modify the quantity of a particular item and I've made the following View:
<%using (Html.BeginForm("Recalculate", "ShoppingCart", Model))
{ %>
<table id="cartTable" border ="5px" cellpadding="5px" cellspacing="5px" width="640">
<tr>
<td><b>Item Name</b></td>
<td><b>Item Qty</b></td>
<td><b>Item Price</b></td>
<td><b>Subtotal</b></td>
</tr>
<%
if (Model != null && Model.Items != null)
{
foreach (ShoppingCart.Models.Item item in Model.Items)
{
%>
<tr>
<td><%: item.Name%></td>
<td><%: Html.TextBoxFor(m => m.Items[Model.Items.IndexOf(item)], new { #Value = item.Quantity })%></td>
<td><%: String.Format("{0:C}", item.Price)%></td>
<td><%: String.Format("{0:C}", item.TotalCost)%></td>
</tr>
<%
}
}
%>
<!-- some other rows/columns go here -->
</table>
<input type="submit" value="Update Cart" />
<%} %>
And my controller:
public class ShoppingCartController : Controller
{
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult Show(ShoppingCart model)
{
if (model!= null && model.Items == null)
{
List<Item> items = new List<Item>();
items.Add(new Item { Name = "Hat", Price = 20.0, Quantity = 1 });
items.Add(new Item { Name = "Snowboard", Price = 430.0, Quantity = 1 });
items.Add(new Item { Name = "Goggles", Price = 24.0, Quantity = 3 });
model.Items = items;
model.Tax = 6.5;
}
return View(model);
}
[HttpPost]
public ActionResult Recalculate(ShoppingCart model)
{
if (model != null && model.Items!=null)
{
foreach (Item item in model.Items)
{
if (item.Quantity == 0)
{
model.Items.Remove(item);
}
else if (item.Quantity < 0)
{
ModelState.AddModelError("error", "The quantity for " + item.Name + " must not be smaller than 0.");
}
}
}
return RedirectToAction("Show", "ShoppingCart", model);
}
}
Unfortunately when I click on the Update Cart button it calls my Recalculate function, but now all of the items in the Items list are null. How can I keep the items AND update the quantity of a given item?
In the BeginForm function I tried passing in the current model and not passing it a model at all... nothing changes. Could anybody help me figure this out?
Do these changes in appropriate locations and things would start working. Note that while the postback the Price and TotalCost would not be populated in the model as the corresponding rendered items are static text. These can be repopulated in the Controller or add hidden field in the view so that these can be posted and repopulated.
<%using (Html.BeginForm("Recalculate", "ShoppingCart", FormMethod.Post))
<td><%: Html.TextBoxFor(m => m.Items[Model.Items.IndexOf(item)].Quantity)%></td>
//return RedirectToAction("Show", "ShoppingCart", model);
return View("Show", model);
<%= Html.TextBox("Quantity", Model.Items[Model.Items.IndexOf(item)].Quantity ) %>
This is a nice blog post, worth a read: http://weblogs.asp.net/nmarun/archive/2010/03/13/asp-net-mvc-2-model-binding-for-a-collection.aspx