pass updated value to controller from view [duplicate] - c#

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/

Related

MVC submit button is always submitting the first record details on POST

I have a foreach loop in MVC page. like below. But, when I am submitting the form using submit button, it is always submitting the first record. Unable to understand why it is doing that way. Appreciate the help.
#model IEnumerable<DeployModel>
#using (Html.BeginForm("Index", "Dep", FormMethod.Post))
{
<div class="col-md-11">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-body" id="modal-body" style="overflow-y: auto">
#if (Model != null && Model.Any())
{
<div>
<table class="table table-condensed table-hover table-bordered">
<thead>
<th>
S1 Name
</th>
<th>
S2 Name
</th>
<th>
Old Version
</th>
<th>
New Version
</th>
<th>
Status
</th>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(o => item.S1)
</td>
<td>
#Html.DisplayFor(o => item.S2)
</td>
<td>
#Html.DisplayFor(o => item.OldVersion)
</td>
<td>
#Html.DisplayFor(o => item.NewVersion)
</td>
<td>
#Html.DisplayFor(o => item.Status)
</td>
<td>
<button name="SubmitButton" class="btn action-btn" type="submit" > Submit </button>
</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
</div>
</div>
</div>
}
My Controller action looks like as, but it is always receiving first record irrespective of button click.
[HttpPost]
public ActionResult Index(DeployModel deployModel)
{
//TODO code
}
Any idea how to resolve this?
There are a couple of problems here. The first is that Html.DisplayFor will just write the display string for the selected property's value with nothing telling the browser that it is form data to be submitted. The other is that all of your submit buttons are for the same form. There are a few ways to solve these problems. The one I would suggest is to create a separate form for each instance of DeployModel, and create hidden inputs for each property you are expecting to receive upon submission of the form:
// inside your foreach loop
#using (Html.BeginForm("Index", "Dep", FormMethod.Post))
{
<input type="hidden" name="S1" value="#item.S1" />
<input type="hidden" name="S2" value="#item.S2" />
...
<input type="submit" value="Submit" />
}
Also please note that if you use this method you should remove the outer form - you don't want nested forms!
You have to give a diffrent Name for each input.
exmaple
#Html.DisplayFor(o => item.S1, new { name = "input1" })

Passing model with list of checkboxes from view to controller

I am trying to pass model from View back to controller. I am passing NaborViewModel to View. It is a list of objects and every object has 4 checkboxes (some of them randomly checked).
Model:
public class NaborViewModel
{
public List<WowClass> WowClasses { get; set; }
}
Actions:
[HttpGet]
public ActionResult Nabor()
{
NaborViewModel viewModel = new NaborViewModel();
DatabaseDataContext context = new DatabaseDataContext();
viewModel.WowClasses = context.WowClasses.ToList();
return View(viewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Nabor(NaborViewModel model)
{
//DB actions
return RedirectToAction(Consts.ActionNabor);
}
In view i have 2 forms each with different approach. The first one is the one i have created with thought it might work.
The second form is approach i found online.
The first one is displaying passed data correctly (filled checkboxes). The second one is even displaying every checboxes unchecked.
When forms are submitted, they both returns null back to controller action.
View:
#using (Html.BeginForm(Consts.ActionNabor, Consts.ControllerAdmin, FormMethod.Post))
{
#Html.AntiForgeryToken()
<table class="admin-table">
<thead>
<tr>
<th>Class</th>
<th>Status</th>
<th colspan="3">Požadované talenty</th>
</tr>
</thead>
<tbody>
#foreach (var cls in Model.WowClasses)
{
<tr>
#Html.HiddenFor(x => cls.Id)
<td>#cls.ClassName</td>
<td>#Html.CheckBoxFor(x => cls.Open)</td>
<td style="text-align: left">#Html.CheckBoxFor(x => cls.NeedTalents1) <span>#cls.Talents1</span></td>
<td style="text-align: left">#Html.CheckBoxFor(x => cls.NeedTalents2) <span>#cls.Talents2</span></td>
<td style="text-align: left">#Html.CheckBoxFor(x => cls.NeedTalents3) <span>#cls.Talents3</span></td>
</tr>
}
</tbody>
</table>
<input type="submit" value="#Consts.Submit" />
}
<div class="horizontal-line-both"></div>
#using (Html.BeginForm(Consts.ActionNabor, Consts.ControllerAdmin, FormMethod.Post))
{
#Html.AntiForgeryToken()
<table class="admin-table">
<thead>
<tr>
<th>Class</th>
<th>Status</th>
<th colspan="3">Požadované talenty</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.WowClasses.Count; i++)
{
<tr>
<td>
<input type="text" value="#Model.WowClasses[i].ClassName" name="Expense[#i].Id">
</td>
<td>
<input type="checkbox" value="#Model.WowClasses[i].Open" name="Expense[#i].Id">
</td>
<td>
<input type="checkbox" value="#Model.WowClasses[i].NeedTalents1" name="Expense[#i].Id">
</td>
<td>
<input type="checkbox" value="#Model.WowClasses[i].NeedTalents2" name="Expense[#i].Id">
</td>
<td>
<input type="checkbox" value="#Model.WowClasses[i].NeedTalents3" name="Expense[#i].Id">
</td>
<td>
<input type="hidden" value="#i" name="Expense[#i].Id">
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="#Consts.Submit" />
}
I got this to work with a combination of your two approaches. See the following:
#for (int i = 0; i < Model.WowClasses.Count; i++)
{
...
<tr>
#Html.EditorFor(model => model.WowClasses[i].Open)
</tr>
...
}
Accessing each item in your List via its index is key. If you look at the HTML generated using this method, each item's name includes its index (in the example above, the generated input's name is this: name="WowClasses[0].Open"). This is how your controller action can distinguish between list items.
For your second form, you can modifying every input field like this,
for check box,
<input type="checkbox" id="WowClasses_#(i)_Open" name="WowClasses[#i].Open" value="true" />
for input filed,
<input type="checkbox" id="WowClasses_#(i)_ClassName" name="WowClasses[#i].ClassName" value="true" />
you just changes your every input filed by your class property.hopefully this your help

Submitting one of multiple forms from editor template to a controller action

I have an application that shows a checklist with a dynamic list of tasks. For now all the tasks have 2 radio buttons: one for Done and one for Not Done. I will be adding new task types (textboxes etc.) later.
The main view calls an editor template that creates each task. The checklist model keeps the tasks in a property "Tasks" of type List<Task>. This is fine for display, but has trouble on form submit.
I want to have each task save independently, so I have placed a <form> element around the controls in the editor template.
Controller
public class CheckController : Controller
{
[HttpGet]
public ActionResult Index()
{
var checklist = new Checklist();
GetData(checklist);
return View(checklist);
}
[HttpPost]
public ActionResult Index(Task model)
{
var task = (Task)model;
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
}
Models
public class Checklist
{
public List<Task> Tasks { get; set; }
public Checklist()
{
Tasks = new List<Task>();
}
}
public class Task
{
public int TaskId { get; set; }
public string TaskName { get; set; }
public bool IsDone { get; set; }
}
Views
#model Checkpoint.Models.Checklist
<table>
#Html.EditorFor(x => x.Tasks);
</table>
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
Rendered HTML
<tr>
<td>First thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_0__TaskId" name="Tasks[0].TaskId" type="hidden" value="1" />
<input checked="checked"id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_0__IsDone" name="Tasks[0].IsDone" type="radio" value="True"
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
<tr>
<td>Second thing</td>
<td>
<form action="/Checklist" method="post">
<input id="Tasks_1__TaskId" name="Tasks[1].TaskId" type="hidden" value="2" />
<input checked="checked" id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="False" />
<span>Incomplete</span>
<input id="Tasks_1__IsDone" name="Tasks[1].IsDone" type="radio" value="True" />
<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
</form>
</td>
</tr>
This does submit the request, but the data looks like this:
Tasks[1].TaskId: 1
Tasks[1].IsDone: True
When it reaches the controller action (which accepts type Task), the property values are null.
How can I get my task data correctly in the controller action?
Or am I going about this in the totally wrong way?
Bonus: what would be the best approach for adding the new task types?
Since you're not trying to post the collection all in one submission you'll need to lose the index on the model name.
Tasks[0].TaskId
Adjust your views. The variable name "task" needs to match the action parameter because the HtmlHelpers will generate name attributes based off this string.
#model Checkpoint.Models.Checklist
<table>
#foreach(Task task in Model.Tasks)
{
#Html.EditorFor(m => task)
}
</table>
The rendered html looks something like
<input id="task_TaskId" name="task.TaskId" type="hidden" value="1">
...
The action needs a "task" parameter to match to bind its values
[HttpPost]
public ActionResult Index(Task task)
{
return Content($"Save Task:{task.TaskId} Value:{task.IsDone}");
}
If we use a partial view instead of an editor template we can somewhat relax the name dependency on "task".
#model Checkpoint.Models.Checklist
<table>
#foreach(Task t in Model.Tasks)
{
#Html.PartialView("_TaskForm", t)
}
</table>
And your editor template content will work just the same.
_TaskForm
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#{
using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId)
#Html.RadioButtonFor(x => x.IsDone, false)<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true)<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
}
</td>
</tr>
And the rendered html
<input id="TaskId" name="TaskId" type="hidden" value="1">
...
The gotcha with all of the above is the html id attributes will not be unique. So if that's critical you'll need to manually iterate the collection to build each form manually so you can exactly specify the id values. That is, you'd lose the small modular editor templates.
Letting the framework auto-generated "unique" ids... we override the name attribute (mind the capitalization for "Name") we have:
#model Checkpoint.Models.Checklist
<table>
#for(int i = 0; i < Model.Tasks.Count; i++)
{
<tr>
<td>#Model.Tasks[i].TaskName</td>
<td data-ftid="#Model.Tasks[i].TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => Model.Tasks[i].TaskId, new { Name="TaskId" })
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, false, new { Name="IsDone" })<span>Incomplete</span>
#Html.RadioButtonFor(x => Model.Tasks[i].IsDone, true, new { Name="IsDone" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>
}
</table>
I was able to make this work with the Editor Template by dropping the helpers and creating the controls manually.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
<input name="TaskId" type="hidden" value="#Model.TaskId" />
<input name="IsDone" type="radio" value="True" #Html.Raw(Model.IsDone ? "checked=checked" : null) />
<span>Complete</span>
<input name="IsDone" type="radio" value="False" #Html.Raw(!Model.IsDone ? "checked=checked" : null) />
<span>Incomplete</span>
<button role="button" type="submit" name="taskAction" value="#Model.TaskId">Submit</button>
}
</td>
</tr>
I wasn't overly happy with this and opted instead for #Jasen's partial view solution.
I was able to obtain unique element IDs by overriding the 'id' attribute in the helper.
I used the TaskId since it's unique, but could otherwise have passed in a loop index from the main view.
#model Checkpoint.Models.Task
<tr>
<td>#Model.TaskName</td>
<td data-ftid="#Model.TaskId">
#using (Html.BeginForm("Index", "Check", FormMethod.Post))
{
#Html.HiddenFor(x => x.TaskId, new { id = "Task_" + Model.TaskId + "_hidIsDone" })
#Html.RadioButtonFor(x => x.IsDone, false, new { id = "Task_"+ Model.TaskId + "_radIsDoneF" })<span>Incomplete</span>
#Html.RadioButtonFor(x => x.IsDone, true, new { id = "Task_" + Model.TaskId + "_radIsDoneT" })<span>Complete</span>
<button role="button" type="submit" name="taskAction">Submit</button>
}
</td>
</tr>

Bind checkbox and textbox to viewmodel [duplicate]

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).

How to show/hide HTML Buttons via MVC Action Method

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

Categories