I have a view in my asp.net (Core) app, which displays a shopping cart. Typical shopping cart stuff - it lists the items in the cart. Each row has an editable field to allow changing the quantity, and an editable checkbox to allow the user to mark the row as "Delete".
I want two buttons at the bottom of the view, one for "Update Cart" (this will delete rows, and update quantities, etc). The other is for "Create Order", which will do the same as "Update Cart", but also create the order.
I have been able to create one button, and have it call the appropriate method in the controller, but I'm having trouble adding a second button, and have it call a different method.
At the moment, my view looks like this:
#model CustomerPortal.Models.StoreViewModels.CartViewModel
#{
ViewData["Title"] = "View";
}
<h2>Shopping Cart</h2>
<form asp-action="UpdateCart">
<table class="table">
<thead>
<tr>
<th>Item</th>
<th>Size</th>
<th>Colour</th>
<th>Quantity</th>
<th>Unit Price Inc. GST</th>
<th>Line Amount Inc. GST</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.CartLines.Count; i++)
{
<tr>
#Html.HiddenFor(modelItem => modelItem.CartLines[i].CartLine.ID)
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.Item.Description)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.ItemSize.Name)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].CartLine.ItemColour.Name)</td>
<td>#Html.EditorFor(modelItem => modelItem.CartLines[i].CartLine.Quantity)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].UnitPriceInecTax)</td>
<td>#Html.DisplayFor(modelItem => modelItem.CartLines[i].LineAmountIncTax)</td>
<td>#Html.EditorFor(modelItem => modelItem.CartLines[i].Delete)</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Update Cart" class="btn btn-default"/>
<input type="submit" value="Create Order" class="btn btn-default"/>
</div>
</form>
And the methods in the ShoppingCartController look like this:
[HttpPost, ActionName("UpdateCart")]
[Authorize]
public async Task<IActionResult> UpdateCart(CartViewModel cart)
{
// Need to do some stuff here
return RedirectToAction("Index");
}
[HttpPost, ActionName("CreateOrder")]
[Authorize]
public async Task<IActionResult> CreateOrder(CartViewModel cart)
{
// Need to do some stuff here
return RedirectToAction("Index");
}
I've tried using "#using(Html.BeginForm" without success. The current format (as above) is the only way that it "kind of" works (both buttons call one function).
So - how can I do this? How can I make both buttons call different methods? Or maybe call the same method with a different second parameter (indicating if I create order or not).
Thanks.
You can use html5 formaction attribute to submit to two different urls from the same form.
<form asp-action="UpdateCart">
<!-- your form elements -->
<div class="form-group">
<input type="submit" value="Update Cart" formaction="#Url.Action("UpdateCart")"/>
<input type="submit" value="Create Order" formaction="#Url.Action("CreateOrder")"/>
</div>
</form>
When you specify the formaction attribute on a submit button, it will overrides the parent form's action attribute value.
Another option is hijack the button click event in javascript and set the parent forms action attribute value to the one you want and trigger a submit event, as explained in this post
Related
Coffee shop is created with ASP.NET Core Razor page. Coffee Model created and all available coffee is stored in a db (ef core).
We have two pages. First page shows a table of all coffee (id, title, cost, ...)info. Each coffee has an Edit "button".
<tbody>
#foreach (var item in Model._coffeeItems)
{....
<td>
#item.Price €
</td>
<td>
<a asp-action= "GetCoffeeItem" >Edit</a>
<a asp-action="RemoveCoffeeItem" >Delete</a>
</td> ...
When clicked should be redirected to an Edit page with a form. All fields must be filled with coffee information for easier edit.
In First page CoffeeItemProvider.cs:
public async Task<FoodItem> GetCoffeeItem(int id)
{
var item = await _db.CoffeeItems
.FirstOrDefaultAsync(i => i.Id == id);
return item;
}
public async Task UpdateCoffeeItem(int id, CoffeeItem item)
{
_db.CoffeeItems.Update(item);
await _db.SaveChangesAsync();
}
And in the Edit page:
<form asp-action="UpdateCoffeeItem">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" value = ""/>
<span asp-validation-for="Name" class="text-danger"></span>
</div>
How can I fill in the input f.ex. Name with value = "#item.Name"?
Is there any way to make GetCoffeeItem to take in id from First page item when clicked - call GetCoffeeItem- get item - and then redirect to /Edit page with item and assign value = "#item.Smth"?
How about:
...
<td>
<a asp-action="GetCoffeeItem" asp-route-id="#item.Id">Edit</a>
<a asp-action="RemoveCoffeeItem" asp-route-id="#item.Id">Delete</a>
</td>
...
and in GetCoffeeItem return the Edit view instead, e.g.:
return View("Edit", coffeeModel);
I ended up creating an EditModel for /Edit page.
redoing a bit #balinta answer.
<a asp-page="./Edit" asp-route-id="#item.Id">Edit</a>
<button class="btn btn-primary" type="submit" asp-page-handler="delete"
asp-route-id="#item.Id">Delete
</button>
And in the Edit.cshtml.cs :
Just added #page "{id:int?}" on the top. and implemented
public async Task<IActionResult> OnGetAsync(int id) function.
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 5 years ago.
I have to bind checkbox value and textbox value with model.Here I am using model to retrive and to post data as well.
I have tried few options but it didnt work.
Below is my code:
#model IEnumerable<ALDS.Web.Areas.AR.Models.ReportViewModel>
#{
ViewBag.Title = "Standings";
}
<table class="table table-bordered">
<thead>
<tr>
<th>LR Date</th>
<th>LR Line No</th>
<th>Issue</th>
<th>Correction Response</th>
<th>Remarks</th>
<th>Submission</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#item.InsertDate
</td>
<td>
#item.LRLineID View
</td>
<td>Margin % incorrect</td>
<td><label for="cbox1">Corrected</label> <input type="checkbox" name="Corrected" value="#item.Status" /> <label for="cbox1">Neglected</label> <input type="checkbox" name="Neglected" value="#item.Status"/></td>
<td><input type="text" value="#item.Comments"/></td>
<td>Submit</td>
</tr>
}
</tbody>
</table>
I have to send the checkbox and textbox value to controller.
Please help.
Render the inputs using the HtmlHelpers provided by MVC. They will make sure that the id and name attributes of the generated <input/> are in a format that can be processed by the MVC ModelBinder.
Also, to post back lists of objects, use a for loop, so that the items get an index understood by the ModelBinder.
Wrap the inputs in a <form> to be posted to the Controller. With the following example, the model will be posted to the "Update" action in "ErrorController" when the user clicks the "Submit" button. myFormClass and myFormId are not neccessary, I just wanted to show how you could add them if needed.
#using(Html.BeginForm("Update", "Error", FormMethod.Post, new { #class = "myFormClass", id = myFormId })) {
for (var i = 0; i < Model.Length; i++) {
#Html.LabelFor(m => m[i].Status)
#Html.CheckBoxFor(m => m[i].Status)
#Html.LabelFor(m => m[i].Comments)
#Html.TextAreaFor(m => m[i].Comments) // multi line
#Html.TextBoxFor(m => m[i].Comments) // single line
}
<button type="submit">Submit</button>
}
LabelFor will try to find [Display(Name="some_resource_key", ResourceType = typeof(Resources))] attributes on the property in the ViewModel to look up the translated text to be used as label in the Resources.resx.
EDIT As Antoine mentioned, you have to provide inputs for ALL ViewModel properties that shall be posted back. You can render <input type="hidden"/> using #Html.HiddenFor(m => m[i].Id).
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
I am developing MVC 4 application in which I need to pass the updated value from the view to controller.
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
//Update Button
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
The values could be entered different for different rows.
I need to pass these values from quantity textbox to controller.
Try using a for loop
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#for(int idx = 0;idx < Model.Length;idx++)
{
<tr>
<td>#Model[idx].ProductId</td>
<td>#Model[idx].Product.ProductName</td>
<td>#Model[idx].Product.UnitPrice</td>
<td>
#Html.TextBoxFor(_ => Model[idx].Quantity)
</td>
</tr>
}
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
When you post the above back to the controller, the MVC model binder will see the textboxes for Model[0].Quantity, Model[1].Quantity, etc and try to bind them to the incoming model. Using a foreach loop will result in none of that data being passed back to the controller.
I do not know what #model you are using on your view, but I'm assuming the MVC model binder will be able to deal with this.
Write like this..
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#Html.AntiForgeryToken()
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>`enter code here`
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
<input type="submit" id="submit" name="Update" value="Update" />
}
I would move the entire Foreach Codeblock
#foreach (var item in Model)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBox("QuantityBox", item.Quantity)
</td>
</tr>
}
Into the Using statement : Otherwise your model back in the controller would not include the updated values that the user submmitted in the view.
In other words : the values that you want in your controller has to be in your Using statement where your submit button is located.
Your code should be like below
#using (Html.BeginForm("UpdateCart", "Cart", FormMethod.Post))
{
#for(i=0;i< Model.item.count ;i++)
{
<tr>
<td>#item.ProductId</td>
<td>#item.Product.ProductName</td>
<td>#item.Product.UnitPrice</td>
<td>
#Html.TextBoxFor(m=>m.item[i].Quantity)
</td>
</tr>
}
//Update Button
#Html.AntiForgeryToken()
<input type="submit" id="submit" name="Update" value="Update" />
}
Then you will get those values in controller through posting
Need to use form tag properly let me know if it works
If you want to know about url rewriting in MVC-4 please visit http://grandhah.blogspot.in/
i cant seem to pass the employee id value from a check box in the Employees.cshtml view to the Delete Post action method. The delete action method returns Delete.cshtml view which renders the Employees.cshtml as that is in an EditorTemplates folder under the Shared folder. When I click submit i cannot seem to pass the IEnumerable of checked #Model.Ids.
What I want to do is delete every entry that has been checked where the checked value is derived in the Employees.cshtml.
Obviously the issue is that the model binding (I think) will be done from the button submit from the Delete.cshtml page, how can I change this?
The Delete action method.
[HttpGet]
public ActionResult Delete()
{
return View(db2.Employees.ToList());
}
The Delete Post action method.
[HttpPost]
public ActionResult Delete(IEnumerable<int> EmployeeIDToDelete)
{
if (EmployeeIDToDelete != null)
{
var employeesToDelete = db2.Employees.Where(x => EmployeeIDToDelete.Contains(x.Id)).ToList();
foreach (var item in employeesToDelete)
{
db2.Employees.Remove(item);
}
db2.SaveChanges();
RedirectToAction("Delete");
}
return View(db2.Employees.ToList());
}
My Delete view
#model IEnumerable<MVC_Example2___ADO.Models.Employees>
#{
ViewBag.Title = "Delete";
}
<html>
<body>
#using (Html.BeginForm())
{
<table align="center">
<thead>
<tr>
<td>Check</td>
<td>Photo</td>
<td>Name</td>
<td>Gender</td>
</tr>
</thead>
<tbody>
#Html.EditorForModel()
</tbody>
</table>
<input type="submit" name="submit" value="Delete Entries" />
}
</body>
</html>
My Employees View
#model MVC_Example2___ADO.Models.Employees
<tr>
<td><input type="checkbox" name="employeeIdsToDelete" id="employeeIdsToDelete" value="#Model.Id" /></td>
<td>#Html.Image(#Model.Photo, #Model.AlternateText, 125, 130)</td>
<td>#Model.FullName</td>
<td>#Model.Gender</td>
</tr>
You have named your checkboxes name="employeeIdsToDelete" but the parameter of your POST method is IEnumerable<int> EmployeeIDToDelete (not plural). The names must match.
Note also you should remove id="employeeIdsToDelete" from the input since this is generating duplicate id attributes which is invalid html.
In my web page, I need to populate button according to parameter value called ButtonType.
let's say that If ButtonType == "Edit" then I need to hide every buttons but butUpdate.
I want to know how to show/hide html buttons via MVC Action method.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SupplierDetail(int SupplierID, string ButtonType)
{
var Supplier = supplierListRepository.Supplier_SelectByID(SupplierID);
return View(Supplier);
}
I am using Asp.net Mvc Razor form.
#using (Html.BeginForm("SupplierDetail_SubmitClick", "Supplier", FormMethod.Post, new { id = "frmSupplierDetail" }))
{
#Html.ValidationSummary(true)
<table cellpadding="0" cellspacing="0" border="0" style="width:450px; height:auto">
.....
<tr>
<td>#Html.LabelFor(model => model.Phone)</td>
<td>#Html.EditorFor(model => model.Phone)
#Html.ValidationMessageFor(model => model.Phone)</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td>
<input type="submit" id="butSave" name="butSave" value="Save" style="width:100px; height:auto" />
<input type="submit" id="butUpdate" name="butUpdate" value="Update" style="width:100px; height:auto" />
<input type="submit" id="butDelete" name="butDelete" value="Delete" style="width:100px; height:auto" />
<input type="submit" id="butReset" name="butReset" value="Reset" style="width:100px; height:auto" />
</td>
</tr>
</table>
</div>
<div id="content">
#Html.ActionLink("Back to List", "Index")
</div>
}
Every Suggestions will be appreciated.
It is not a controller action responsibility to show/hide buttons. A controller action doesn't/shouldn't even know what a button means. That's a concept that exists on the view. A controller action on the other hand is supposed to communicate with the model and prepare a view model that it passes to the view for displaying. So you could define a view model that will contain properties defining the visibility of the buttons and based on the value of the ButtonType parameter set those properties accordingly. Then the controller action will pas this view model to the view instead of the supplier object that you are currently passing. Obviously the view model will also have a property to hold this supplier. Now all that's left for the view is based on the values of the view model properties decide how to display the buttons.
in your controller add the buttontype to viewdata:
ViewData["ButtonType"] = ButtonType
Then, in the view itself, you can add if/else statements, or any other logic that suits all of ur cases, to decide what to render:
#if (ViewData["ButtonType"].ToString() == "Edit")
{
<input type="submit" id="butUpdate" name="butUpdate" value="Update"
style="width:100px; height:auto" />
}
Of course, this is but a demo of what can be done, Yuo should adapt the code to ur buisness logics