I am having trouble passing my id parameter through an action link. I want to add a cancel button to my view which will return the eventID to the method, do something to the database, then redirect to another view. I have entered debug mode and the id param is null when it is returned to the method and I don't understand why.
Here is my controller method to create the initial view
public ActionResult Create(OrderVM model)
{
//get the currentUser ID to search database for user
string currentUserId = User.Identity.GetUserId();
int quantity = 10;
ApplicationUser currentUser = db.Users.Find(currentUserId);
Order order = new Order
{
OrderDate = DateTime.UtcNow,
EventID = model.EventID,
Event = currentEvent,
user = currentUser
};
//add this order to the database
db.Orders.Add(order);
//save changes to database
db.SaveChanges();
SummaryVm summaryVm = new SummaryVm
{
email = order.user.Email,
orderID = order.OrderID,
tickets = model.Tickets,
totalPrice = total,
ticketQuantity = quantity,
orderDate = order.OrderDate,
eventID = model.EventID,
};
return View("OrderSummary", summaryVm);
}
This is the OrderSummary view
#model Site.ViewModels.SummaryVm
<head>
<title>Next Page</title>
</head>
<header>
<h2> Here is your order summary, please review before proceeding with payment. Please complete this transaction within 15 minutes or your order will be cancelled. </h2>
</header>
<div class="float-left">
<h2 id="countdown"></h2>
</div>
<div id="content">
<div class="panel panel-default">
<div class="panel-heading">Order Summary</div>
<div class="panel-body">
<table class="table">
<thead>
<tr>
<th>Ticket Type</th>
<th><span contenteditable>Price</span></th>
<th><span contenteditable>Quantity</span></th>
</tr>
</thead>
<tbody>
#foreach (GeoSocietySite.ViewModels.TicketVm ticket in #Model.tickets)
{
<tr>
<td><span contenteditable>#ticket.Description</span></td>
<td><span contenteditable>#ticket.Price</span></td>
<td><span contenteditable>#ticket.Quantity</span></td>
</tr>
}
</tbody>
</table>
<table id="total-table">
<tr>
<th>Total Price in £: </th>
<td id="custom-amount">#Model.totalPrice</td>
</tr>
</table>
</div>
</div>
</div>
#Html.ActionLink("Cancel", "CancelOrder", "Order", new { id = #Model.eventID })
This is my CancelOrder controller method
public ActionResult CancelOrder(int eventID)
{
//do something to db
return RedirectToAction("CreateOrder", "Order", new { id = eventID });
}
This is my create order method
public ActionResult CreateOrder(int? id)
{
Event currentEvent = db.Events.Find(id);
//check event exists
if (currentEvent != null)
{
//get the ID of the user currently logged in to the site
string currentUserId = User.Identity.GetUserId();
//retreive details of current user from db based on ID
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
// Initialize a new order
OrderVM model = new OrderVM
{
EventID = currentEvent.EventID,
EventName = currentEvent.Name,
OrderDate = DateTime.Now,
FirstName = currentUser.FirstName,
EventDate = currentEvent.Date,
EventDescription = currentEvent.Description,
EventLocation = currentEvent.Location,
//create view model for each ticket type then place in list
Tickets = currentEvent.Tickets.Select(t => new TicketVm
{
TicketID = t.TicketID,
Description = t.Description,
Price = t.Price
}).ToList(),
};
return View(model);
}else
{
return RedirectToAction("Index", "Events");
}
}
When I try to run this code I am redirect to the Events Index page, meaning the Event has not been retrieved from the database and through debugging I can see this is because the ID parameter is null. I have checked that when the summaryVm is passed to the OrderSummary view it is fully populated with data.If anyone can see what I am doing wrong any help would be greatly appreciated. Thank you!
Your using the wrong overload of ActionLink (and your adding htmlAttributes, not route values). In addition, the parameter in your method is named eventID, not id. Change it to
#Html.ActionLink("Cancel", "CancelOrder", "Order", new { eventID = Model.eventID }, null)
Related
I need help making my list filtering more efficient.
I have a ASP.NET MVC application where there is a view for records. I've added a filter option that has a number of dropdowns where, based on the values selected in the dropdowns, filter out the result set of the records. The way I've constructed this filter was based off another filter I've seen but I know there has to be a more effective way to do what I would like to do without taking so many steps or using up as much resource. I can tell this isn't very scalable.
Right now the process involves a number of components.
The view, where the results are displayed. Reports.cs
The viewModel, to provide data to the view. ReportViewModel.cs
The view references a controller that uses a method that references a service method. ReportController.cs using GetReportFilters()
The service method refers to another method that pulls all relevant files and filters them GetReportFilters uses RetrieveFilteredReports() located in ReportsService.cs
RetrieveFilteredReports() references RetrieveReportsForFilter() Where RetrieveReportsForFilter runs a query against the DB and pulls all needed files. Here are the corresponding code snippets. (edited to save space, change some namespaces, and DB name)
This is a section of the view Reports.cs
<form class="form" asp-action="GetReportFilters" asp-controller="REPORTS">
<div class = "row">
<div class="form-group">
<p>
Types: #Html.DropDownList("TypeDropdown", new ReportApp.Services.ReportService().GetDropDown("Type"), "select", new { id = "type" })
</p>
</div>
<div class="form-group">
<p>
Shift: #Html.DropDownList("ShiftDropdown", new ReportApp.Services.ReportService().GetDropDown("Shift"), "select", new { id = "shifts" })
</p>
</div>
</div>
</form>
<table class="table table-striped" id="myTable">
<thead>
<tr>
<th>
Type
</th>
<th>
Shift
</th>
<th>
Edit
</th>
</tr>
</thead>
#foreach (var item in Model)
{
<tr class="cost">
<td>
#Html.DisplayFor(modelItem => item.TypeId)
</td>
<td>
#Html.DisplayFor(modelItem => item.ShiftTimeFound)
</td>
<a class="anchorDetail" href="#Url.Action("GetSpecificReport", "Report", new {ReportId = item.ReportId})">
<i class="fa fa-eye" style="font-size: 30px;"></i>
</a>
</td>
</tr>
}
</tbody>
Here is the snippet from the method referenced in the controller
public ViewResult GetReportFilters(string TypeDropdown, string ShiftDropdown)
{
AppContexts.Current.Session.SetObject("TypeDropdown", TypeDropdown);
AppContexts.Current.Session.SetObject("ShiftDropdown", ShiftDropdown);
var viewModel = new ReportService().RetrieveFilteredReports(TypeDropdown, ShiftDropdown);
return View("ReportHistory", viewModel.ToPagedList(p ?? 1, s ?? 10));
}
Here is the RetrieveFilteredReports as referenced in the above method. Also here is and RetrieveReportsForFilter which is referenced in RetrieveFilteredNdrs
public List<ReportViewModel> RetrieveFilteredReports(string TypeName, string Shift)
{
var listOfReports = new ReportService().RetrieveReportsForFilter();
Dictionary<string, string> filterDictionary = new Dictionary<string, string>
{
{ "TypeName", TypeName },
{ "Shift", Shift },
};
foreach (KeyValuePair<string, string> entry in filterDictionary)
{
if (entry.Value != null)
{
switch (entry.Key)
{
case "TypeName":
listOfReports = listOfReports.Where(x => x.TypeId == entry.Value).ToList();
break;
case "Shift":
listOfNdrs = listOfNdrs.Where(x => x.ShiftTimeId == entry.Value).ToList();
break;
return listOfReports.Select(x => new ReportViewModel
{
TypeItemsId = x.TypeId ,
ShiftId = x.ShiftTimeId
}).ToList();
}
public List<ReportViewModel> RetrieveReportsForFilter()
{
var listOfAudits = new List<ReportViewModel>();
using var context = new ReportContext();//contains the formatting for fields
var dropdowns = context.DB.AsNoTracking().ToList();//replaced actually db name with just DB
var query = context.Reports.AsNoTracking().ToList();
listOfAudits = query.Select(x => new ReportViewModel
{
TypeId = x.ReportType,
ShiftTimeId = x.ShiftTimeFound,
}).ToList();
return listOfAudits;
}
As you can see the code bounces around quite a bit. As more and more entries are added to the DB it'll get continually slower until it becomes unbearable. How can I improve the efficiency of this process for scalability?
If there is any more needed information please let me know.
Hello I have a view page that looks like this
#model PIC_Program_1._0.Models.Shipping
#using PIC_Program_1._0.Models;
#{
PIC_Program_1_0Context db = new PIC_Program_1_0Context();
Model.preparedBy = Model.preparedBy != null ? Model.preparedBy : IGT.user;
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<table>
<tr>
<th rowspan="3">Items</th>
<td>
#Html.DropDownList("ItemID", null, null, htmlAttributes: new { #class = "form-control chosen-select", })
#{
Item i = db.Items.Find(int.Parse(Request["ItemID"]));
var packedItems = Model.packed(i);
var orderedItems = Model.SalesOrder.totalItems(i);
var itemMax = orderedItems - packedItems;
}
</td>
<td>
<input type="number" value="#ViewBag.ItemQ" name="item_qty" class="form-control" max="#itemMax" />
</td>
</tr>
I want the user to be able to choose the item from the dropdown, then I want to grab the item that the user selected and I want it to put it into the method parameter
On the backend
string strDDLValue = Request.Form["ddlVendor"].ToString();
you can view this in debug to help
#Html.DropDownList("ItemsXY", new SelectList(ViewBag.ItemsXY), "Choose Category", new { #class = "form-control" })
$("#ItemsXY").on("change", function () {
var q = $("#Category").val();
console.log("val = " + q);
});
In your form collection
[HttpPost]
public ActionResult PIC_Program_1(SomeViewModel someMV,FormCollection form)
{
string strDDLValue = form["ItemsXY"].ToString();
return View(MV);
}
or
string strDDLValue = Request.Form["ItemsXY"].ToString();
If you need the text of selected item as well, add a hidden field and on drop down selection change set selected item text in the hidden field:
Update your model to hold hidden values
// Add this to your VM
public string SelectItemsXY {get;set;}
public string SelectedItemsXYText { get; set; }
<script type="text/javascript">
$(function(){
$("#ItemsXY").on("change", function {
$("#SelectedvendorText").val($(this).text());
});
});
</script>
#Html.DropDownListFor(m=>m.SelectedItemsXY , Model.ItemsXY, "Select ItemsXY")
#Html.HiddenFor(m=>m.SelectedItemsXYText)
I have my site working so a user can pay via card however now I also need to use PayPal, I can't seem to send the products over from the shopping cart to the paypal controller, each individual product needs to be sent over in the order.
Here is my PayPal controller;
namespace T_shirt_Company_v3.Controllers
{
public class PayPalController : Controller
{
public ActionResult RedirectFromPaypal()
{
return View();
}
public ActionResult CancelFromPaypal()
{
return View();
}
public ActionResult NotifyFromPaypal()
{
return View();
}
public ActionResult ValidateCommand(string RecordId, string CartTotal)
{
bool useSandbox = Convert.ToBoolean(ConfigurationManager.AppSettings["IsSandbox"]);
var paypal = new PayPal(useSandbox);
paypal.item_name = RecordId;
paypal.amount = CartTotal;
return View(paypal);
}
}
}
And my View for checkout that I need the details from;
#model T_shirt_Company_v3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.4.4.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", {"id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
</script>
<center>
<h3>
Review your cart:
</h3>
<p class="button">
#using (Html.BeginForm("ValidateCommand", "PayPal"))
{
<input type="submit" name="btnConfirm" value="Check Out with Paypal" />
}
#Html.ActionLink((string)ViewBag.CartStatus, (string)ViewBag.Link, (string)ViewBag.Link2)
#Html.ActionLink("Continue Shopping ", "Index", "Store")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Product Name
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
#foreach (var item in
Model.CartItems)
{
<tr id="row-#item.RecordId">
<td>
#Html.ActionLink(item.Product.Title,
"Details", "Store", new { id = item.ProductId }, null)
</td>
<td>
#item.Product.Price
</td>
<td id="item-count-#item.RecordId">
#item.Count
</td>
<td>
<a href="#" class="RemoveLink"
data-id="#item.RecordId">
Remove
from cart
</a>
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
</center>
And the controller;
namespace T_shirt_Company_v3.Controllers
{
public class ShoppingCartController : Controller
{
TshirtStoreDB storeDB = new TshirtStoreDB();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
// Set up the ViewModel
ShoppingCartViewModel viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(),
CartTotal = cart.GetTotal()
};
if (viewModel.CartItems.Any())
{
ViewBag.CartStatus = "Proceed to checkout or ";
ViewBag.Link = "AddressAndPayment";
ViewBag.Link2 = "Checkout";
}
else
{
ViewBag.CartStatus = "Cart is empty please ";
ViewBag.Link = "Index";
ViewBag.Link2 = "Store";
}
// Return the view
return View(viewModel);
}
//
// GET: /Store/AddToCart/5(ID)
public ActionResult AddToCart(int id)
{
// Retrieve the Product from the database
var addedProduct = storeDB.Products
.Single(product => product.ProductId == id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedProduct);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
//
// AJAX: /ShoppingCart/RemoveFromCart/5(ID)
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the product to display confirmation
string productName = storeDB.Carts
.Single(item => item.RecordId == id).Product.Title;
// Removes item from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message saying removed from cart
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(productName) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return Json(results);
}
//
// GET: /ShoppingCart/CartSummary
[ChildActionOnly]
public ActionResult CartSummary()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
ViewData["CartCount"] = cart.GetCount();
return PartialView("CartSummary");
}
//test close connection when done
protected override void Dispose(bool disposing)
{
storeDB.Dispose();
}
}
}
Assuming I read your code correctly, you're only rendering the data, you're not sending it (at all).
your form only has a button (it's the only "data" sent)
you need to include the data you rendered as form fields (<input />)
Hth.
As PayPal Api is dependent on a set of operations that must be understood before used, developers should focus on understanding the operations summary, before using the Api, also a sandbox is available for testing before officially using the Api.
You should know how to use the RESTful endpoint structure of PayPal.
You can check the PayPal Api documentation for details on how to integrate your web application with PayPal using REST API Reference.
I'm developing an ASP.NET MVC 5 web with C# and .NET Framework 4.5.1.
I have this form in a cshtml file:
#model MyProduct.Web.API.Models.ConnectBatchProductViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Create</title>
</head>
<body>
#if (#Model != null)
{
<h4>Producto: #Model.Product.ProductCode, Cantidad: #Model.ExternalCodesForThisProduct</h4>
using (Html.BeginForm("Save", "ConnectBatchProduct", FormMethod.Post))
{
#Html.HiddenFor(model => model.Product.Id, new { #id = "productId", #Name = "productId" });
<div>
<table id ="batchTable" class="order-list">
<thead>
<tr>
<td>Cantidad</td>
<td>Lote</td>
</tr>
</thead>
<tbody>
<tr>
<td>#Html.TextBox("ConnectBatchProductViewModel.BatchProducts[0].Quantity")</td>
<td>#Html.TextBox("ConnectBatchProductViewModel.BatchProducts[0].BatchName")</td>
<td><a class="deleteRow"></a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: left;">
<input type="button" id="addrow" value="Add Row" />
</td>
</tr>
</tfoot>
</table>
</div>
<p><input type="submit" value="Seleccionar" /></p>
}
}
else
{
<div>Error.</div>
}
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/js/createBatches.js"></script> <!-- Resource jQuery -->
</body>
</html>
And this is the action method:
[HttpPost]
public ActionResult Save(FormCollection form)
{
return null;
}
And the two ViewModel:
public class BatchProductViewModel
{
public int Quantity { get; set; }
public string BatchName { get; set; }
}
public class ConnectBatchProductViewModel
{
public Models.Products Product { get; set; }
public int ExternalCodesForThisProduct { get; set; }
public IEnumerable<BatchProductViewModel> BatchProducts { get; set; }
}
But I get this in FormCollection form var:
But I want to get an IEnumerable<BatchProductViewModel> model:
public ActionResult Save(int productId, IEnumerable<BatchProductViewModel> model);
If I use the above method signature both parameters are null.
I want an IEnumerable because user is going to add more rows dynamically using jQuery.
This is jQuery script:
jQuery(document).ready(function ($) {
var counter = 0;
$("#addrow").on("click", function () {
counter = $('#batchTable tr').length - 2;
var newRow = $("<tr>");
var cols = "";
var quantity = 'ConnectBatchProductViewModel.BatchProducts[0].Quantity'.replace(/\[.{1}\]/, '[' + counter + ']');
var batchName = 'ConnectBatchProductViewModel.BatchProducts[0].BatchName'.replace(/\[.{1}\]/, '[' + counter + ']');
cols += '<td><input type="text" name="' + quantity + '"/></td>';
cols += '<td><input type="text" name="' + batchName + '"/></td>';
cols += '<td><input type="button" class="ibtnDel" value="Delete"></td>';
newRow.append(cols);
$("table.order-list").append(newRow);
counter++;
});
$("table.order-list").on("click", ".ibtnDel", function (event) {
$(this).closest("tr").remove();
counter -= 1
$('#addrow').attr('disabled', false).prop('value', "Add Row");
});
});
Any idea?
I have checked this SO answer, and this article but I don't get my code working.
You need to generate the controls for the collection in a for loop so they are correctly named with indexers (note that property BatchProducts needs to be IList<BatchProductViewModel>
#using (Html.BeginForm("Save", "ConnectBatchProduct", FormMethod.Post))
{
....
<table>
....
#for(int i = 0; i < Model.BatchProducts.Count; i++)
{
<tr>
<td>#Html.TextBoxFor(m => m.BatchProducts[i].Quantity)</td>
<td>#Html.TextBoxFor(m => m.BatchProducts[i].BatchName)</td>
<td>
// add the following to allow for dynamically deleting items in the view
<input type="hidden" name="BatchProducts.Index" value="#i" />
<a class="deleteRow"></a>
</td>
</tr>
}
....
</table>
....
}
Then the POST method needs to be
public ActionResult Save(ConnectBatchProductViewModel model)
{
....
}
Edit
Note: Further to your edit, if you want to dynamically add and remove BatchProductViewModel items in he view, you will need to use the BeginCollectionItem helper or a html template as discussed in this answer
The template to dynamically add new items would be
<div id="NewBatchProduct" style="display:none">
<tr>
<td><input type="text" name="BatchProducts[#].Quantity" value /></td>
<td><input type="text" name="BatchProducts[#].BatchName" value /></td>
<td>
<input type="hidden" name="BatchProducts.Index" value ="%"/>
<a class="deleteRow"></a>
</td>
</tr>
</div>
Note the dummy indexers and the non-matching value for the hidden input prevents this template posting back.
Then the script to add a new BatchProducts would be
$("#addrow").click(function() {
var index = (new Date()).getTime(); // unique indexer
var clone = $('#NewBatchProduct').clone(); // clone the BatchProducts item
// Update the index of the clone
clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
clone.html($(clone).html().replace(/"%"/g, '"' + index + '"'));
$("table.order-list").append(clone.html());
});
In your Post Methode you receive "MyProduct.Web.API.Models.ConnectBatchProductViewModel" as Parameter.
Use the existing model for the Post methode.
Why do you want a IEnumerable from your model? there is only one available including the id in the model.
you can visit this article for complete source code with a video tutorial.
you have to create an action first, from where we can pass the list of object
[HttpGet]
public ActionResult Index()
{
List<Contact> model = new List<Contact>();
using (MyDatabaseEntities dc = new MyDatabaseEntities())
{
model = dc.Contacts.ToList();
}
return View(model);
}
then we need to create a view for that action
#model List<UpdateMultiRecord.Contact>
#{
ViewBag.Title = "Update multiple row at once Using MVC 4 and EF ";
}
#using (#Html.BeginForm("Index","Home", FormMethod.Post))
{
<table>
<tr>
<th></th>
<th>Contact Person</th>
<th>Contact No</th>
<th>Email ID</th>
</tr>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td> #Html.HiddenFor(model => model[i].ContactID)</td>
<td>#Html.EditorFor(model => model[i].ContactPerson)</td>
<td>#Html.EditorFor(model => model[i].Contactno)</td>
<td>#Html.EditorFor(model => model[i].EmailID)</td>
</tr>
}
</table>
<p><input type="submit" value="Save" /></p>
<p style="color:green; font-size:12px;">
#ViewBag.Message
</p>
}
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
}
and then we have to write code for save the list of object to the database
[HttpPost]
public ActionResult Index(List<Contact> list)
{
if (ModelState.IsValid)
{
using (MyDatabaseEntities dc = new MyDatabaseEntities())
{
foreach (var i in list)
{
var c = dc.Contacts.Where(a =>a.ContactID.Equals(i.ContactID)).FirstOrDefault();
if (c != null)
{
c.ContactPerson = i.ContactPerson;
c.Contactno = i.Contactno;
c.EmailID = i.EmailID;
}
}
dc.SaveChanges();
}
ViewBag.Message = "Successfully Updated.";
return View(list);
}
else
{
ViewBag.Message = "Failed ! Please try again.";
return View(list);
}
}
using(Html.BeginForm())
{
// code here
}
While to Post form Data all tags must be included form tag.
Following the principle of DRY, you can create one EditorTemplate for that purpose.
Steps:
1- In Views > Shared > Create new folder named (EditorTemplates)
2- Create a view inside your newly created EditorTemplates folder , the view's model should be BatchProductViewModel according to the OP example. Place your code inside the Editor view. No loop or index is required.
An EditorTemplate will act similar to a PartialView for every child entity but in a more generic way.
3- In your parent entity's view, call your Editor :
#Html.EditorFor(m => m.BatchProducts)
Not only this provides a more organized views, but also let's you re-use the same editor in other views as well.
I got this error when I am trying to remove the item from the Cart table.
HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Panier/RemoveFromCart/1. This URL seems to be fine with me. It should branch to the PanierController at RemoveCart. I don't understand why it is not branching.
Thanks
Index.cshtml
#model Tp1WebStore3.ViewModels.ShoppingCartViewModel
#{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.4.4.min.js"
type="text/javascript"></script>
<script type="text/javascript">
$(function () {
// Document.ready -> link up remove event handler
$(".RemoveLink").click(function () {
// Get the id from the link
var recordToDelete = $(this).attr("data-id");
if (recordToDelete != '') {
// Perform the ajax post
$.post("/ShoppingCart/RemoveFromCart", {"id": recordToDelete },
function (data) {
// Successful requests get here
// Update the page elements
if (data.ItemCount == 0) {
$('#row-' + data.DeleteId).fadeOut('slow');
} else {
$('#item-count-' + data.DeleteId).text(data.ItemCount);
}
$('#cart-total').text(data.CartTotal);
$('#update-message').text(data.Message);
$('#cart-status').text('Cart (' + data.CartCount + ')');
});
}
});
});
</script>
<h3>
<em>Details</em> du panier:
</h3>
<p class="button">
#Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Produit
</th>
<th>
Prix (unitaire)
</th>
<th>
Quantite
</th>
<th></th>
</tr>
#foreach (var item in Model.CartItems)
{
<tr id="row-#item.ProduitId">
<td>
#Html.ActionLink(item.Produit.Description,"Details", "Store", new { id =
item.ProduitId }, null)
</td>
<td>
#item.Produit.Prix
</td>
<td id="item-count-#item.ProduitId">
#item.Quantite
</td>
<td>
#Html.ActionLink("Enlever du panier", "RemoveFromCart", "Panier", new { id =
item.ProduitId }, null)
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
#Model.CartTotal
</td>
</tr>
</table>
PanierController.cs
namespace Tp1WebStore3.Controllers
{
public class PanierController : Controller
{
Tp1WebStoreDBEntities dbProduit = new Tp1WebStoreDBEntities();
[HttpPost]
public ActionResult RemoveFromCart(int id)
{
// Remove the item from the cart
var cart = ShoppingCart.GetCart(this.HttpContext);
// Get the name of the product to display confirmation
string produitDescription = dbProduit.Paniers
.Single(item => item.PanierId == id).Produit.Description;
// Remove from cart
int itemCount = cart.RemoveFromCart(id);
// Display the confirmation message
var results = new ShoppingCartRemoveViewModel
{
Message = Server.HtmlEncode(produitDescription) +
" has been removed from your shopping cart.",
CartTotal = cart.GetTotal(),
CartCount = cart.GetCount(),
ItemCount = itemCount,
DeleteId = id
};
return View("Details");
}
Your RemoveFromCart controller action is decorated with the [HttpPost] attribute meaning that it is ONLY accessible by POST verbs. But in your view you seem to have generated some action link to it:
#Html.ActionLink(
"Enlever du panier",
"RemoveFromCart",
"Panier",
new { id = item.ProduitId },
null
)
But as you are well aware, an Html.ActionLink translates into an <a> tag in your markup which obviously is sending a GET request to the server when clicked.
So basically you have 3 possibilities here:
Use an Html.BeginForm instead of an ActionLink to refer to this action which would allow you to send a POST request
Get rid of the [HttpPost] attribute from your RemoveFromCart action
AJAXify the anchor which would allow you to use a POST request.