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
Related
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" })
I need to send a List back to my controller and update the values on my repository.
But after load the view with the values, update it and click the submit button, I don't know how to get the list with the update values and call the update method from the repository.
I'm using .Net 4.7.2.
HomeController:
[HttpGet]
public ActionResult Nota(string Concurso)
{
List<InscricoesModel> model = new List<InscricoesModel>();
InscricoesRepository repository = new InscricoesRepository();
model = repository.GetAprovadosPrimeiraFase(new Guid(Concurso));
return View("Nota",model);
}
[HttpPost]
public void UdateNotas(List<InscricoesModel> model)
{
InscricoesRepository repository = new InscricoesRepository();
foreach(InscricoesModel item in model)
{
repository.Update(item);
}
}
Nota.cshtml:
#model List<ConcursoBolsaSegundaFase.Model.InscricoesModel>
<h1>Classificados 2ª Fase</h1>
<hr />
<p>Exportado em #DateTime.Now</p>
<div style="margin-top:15px">
#* TABELA RESULTADO *#
<div id="notasAprovadosSegundaFase" style="margin-top:10px">
#using (Html.BeginForm("UdateNotas", "Home", Model, FormMethod.Post))
{
<table class="table table-bordered" id="tblNotaAprovadosSegundaFase">
<thead>
<tr>
<th>Inscrição</th>
<th>Nome</th>
<th>Nota Primeira Fase</th>
<th>Fez Carta</th>
<th>Nota Segunda Fase</th>
</tr>
</thead>
<tbody>
#if (Model != null)
{
foreach (var linha in Model)
{
<tr>
<td>#linha.Inscricao</td>
<td>#linha.Nome</td>
<td>#linha.NotaPrimeiraFase</td>
<td>
<select>
<option value="false">Não</option>
<option value="true">Sim</option>
</select>
</td>
<td><input type="text" value="#linha.NotaSegundaFase"></td>
</tr>
}
}
</tbody>
</table>
<button type="submit" class="btn btn-success">Salvar</button>
}
</div>
</div>
The UpdateNotas method in my controller never recive a value, i don't know how to send the list from the view to my controller.
In MVC, the name of the input will be binded to the variable in the controller. In your case, your input has no name. I suggest you look at the html helpers.
This would bind your values properly.
for (int i = 0;i<Model.Count;i++)
{
Html.TextBoxFor(model => Model[i].NotaSegundaFase)
}
In this case, only NotaSegundaFase would be sent back to the controller.
You can use #Html.HiddenFor() to hold the data on the view and bind to controller on Post.
#using (Html.BeginForm("UdateNotas", "Home", Model, FormMethod.Post))
{
<table class="table table-striped table-bordered table-sm table-responsive">
<thead>
<tr>
<th>Inscrição</th>
<th>Nome</th>
<th>Nota Primeira Fase</th>
<th>Fez Carta</th>
<th>Nota Segunda Fase</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(model => Model[i].Inscrição)
#Html.HiddenFor(model => Model[i].Nome)
#Html.HiddenFor(model => Model[i].NotaPrimeiraFase)
<tr>
<td>#Model[i].Inscrição</td>
<td>#Model[i].Nome</td>
<td>#Model[i].NotaPrimeiraFase</td>
#*do this similary for other property *#
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-success">Salvar</button>
}
As far as I understood,you want to post DropDownList value only.
if you decide to update other fields just add the Html.Editor into the loop like following.
#Html.Editor("[" + i + "].Inscricao")
#Html.Editor("[" + i + "].Nome")
I hope this will help.
#using (Html.BeginForm("UdateNotas", "Home", Model, FormMethod.Post))
{
<table class="table table-bordered" id="tblNotaAprovadosSegundaFase">
<thead>
<tr>
<th>Inscrição</th>
<th>Nome</th>
<th>Nota Primeira Fase</th>
<th>Fez Carta</th>
<th>Nota Segunda Fase</th>
</tr>
</thead>
<tbody>
#if (Model != null)
{
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>#Model[i].Inscrição</td>
<td>#Model[i].Nome</td>
<td>#Model[i].NotaPrimeiraFase</td>
<td>
<select name="[#i].NotaSegundaFase">
<option value="false">Não</option>
<option value="true">Sim</option>
</select>
</td>
<td><input type="text" value="#linha.NotaSegundaFase"></td>
</tr>
}
}
</tbody>
</table>
<button type="submit" class="btn btn-success">Salvar</button>
}
Note : don't change anything in the controller. model binder should resolve everything from the request.
I have a View whose model is a List of custom types and I want to POST changes for only a single element of the List (model[i]). This POST itself works, except the value is what was originally in the model and not the updated value from the input
View's Model Declaration
#model List<Translation2>
Translation2's type (F#)
type Translation2 = {
Key: string;
RowKey: string;
Value: string;
English: string;
}
The View with a single entity submit
#model List<Translation2>
<form asp-controller="Home" asp-action="Translate" method="POST" >
<table>
<thead>
<th>
<h2>Key</h2>
</th>
<th>
<h2>English</h2>
</th>
<th>
<h2>Translated</h2>
</th>
</thead>
<tbody>
#for(var i = 0; i < Model.Count(); i++)
{
<tr>
<div>
<td class="key-col">
<p style="font-size:large">#Model[i].Key</p>
#Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].Value" />
</td>
<td>
<a href="#Url.Action("Translate", "Home", new {RowKey=#Model[i].RowKey, Key=#Model[i].Key, Value=#Model[i].Value })" >Save Translation</a>
</td>
</div>
</tr>
}
</tbody>
</table>
</form>
I have also tried to just POST the entire list per
ASP.NET Core 1.0 POST IEnumerable<T> to controller
but will get
ArgumentNullException: Value cannot be null.
Parameter name: source
Count
MoveNext in Translate.cshtml
#for(var i = 0; i < Model.Count(); i++)
The View with submitting the entire list
#model List<Translation2>
<form asp-controller="Home" asp-action="Translate" method="POST" >
<table>
<thead>
<th>
<h2>Key</h2>
</th>
<th>
<h2>English</h2>
</th>
<th>
<h2>Translated</h2>
</th>
</thead>
<tbody>
#for(var i = 0; i < Model.Count(); i++)
{
<tr>
<div>
<td class="key-col">
<p style="font-size:large">#Model[i].Key</p>
#Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].Value" />
</td>
<td>
<button type="submit">Save Translation</button>
</td>
</div>
</tr>
}
</tbody>
</table>
</form>
I would really like to know how to solve both ways, if possible, but a solution for either will do at this point.
#Nkosi 's comment on the OP is the correct answer
"That action is doing a GET and not a POST. the value in the link does not change after render when you update the input field. Suggestion. wrap each tr in it's own form that submits to an action expecting a single model and not a collection"
Corrected Code:
#for(var i = 0; i < Model.Count(); i++)
{
<form asp-controller="Home" asp-action="Translate" method="POST" >
<tr>
<div>
<td class="key-col">
<p style="font-size:large">#Model[i].Key</p>
#Html.HiddenFor(m => m[i].RowKey)
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].English" readonly />
</td>
<td class="val-col">
<input class="fill-void" type="text" asp-for="#Model[i].Value" />
</td>
<td>
<button type="submit">Save Translation</button>
</td>
</div>
</tr>
</form>
}
Still getting an error
ArgumentException: Type 'Translation2' does not have a default constructor
Parameter name: type, but the scope of this question has been resolved.
Update: Partial Fix ---
Have added the constructors, however it always uses the default constructor so when I look at the property values after the POST, they all say "DEFAULT"
type Translation2(key:string, rowKey:string, value:string, english:string) =
public new () = Translation2("DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT")
member this.Key = key
member this.RowKey = rowKey
member this.Value = value
member this.English = English
Update: For the record --- complicating the constructor doesn't help either... it seems the values aren't being lifted from the view....
type Translation2(key:string, rowKey:string, value:string, english:string) =
let mutable k = key
let mutable r = rowKey
let mutable v = value
let mutable e = english
member this.Key with get() = k and set(value) = k <- value
member this.RowKey with get() = r and set(value) = r <- value
member this.Value with get() = v and set(value) = v <- value
member this.English with get() = e and set(value) = e <- value
public new () = Translation2("DEFAULT", "DEFAULT", "DEFAULT", "DEFAULT")
This question already has answers here:
Multiple checkboxes in razor (using foreach)
(3 answers)
Closed 7 years ago.
I would like to edit a list of items and save them all together in the same submit. Is it possible? If so, how?
I have the following piece of code, but it does not give the wanted result. Or otherwise I don't know what to write for the counterpart in the controller.
#using (Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<fieldset>
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Datum</th>
<th>NewValue</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.Id)
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Value)
</td>
<td>
#Html.TextBoxFor(modelItem => item.Value)
</td>
</tr>
}
</tbody>
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Update Thanks to #Jonesopolis I came up with this working solution
#using (Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<fieldset>
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Datum</th>
<th>NewValue</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.HiddenFor(modelItem => modelItem[i].Id)
#Html.DisplayFor(modelItem => modelItem[i].Name)
</td>
<td>
#Html.DisplayFor(modelItem => modelItem[i].Value)
</td>
<td>
#Html.TextBoxFor(modelItem => modelItem[i].Value)
</td>
</tr>
}
</tbody>
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
For MyController
public class MyController : Controller
{
[HttpPost]
public ActionResult Save(IEnumerable<NameDoesNotMatter> newValues)
{
...
}
}
public class NameDoesNotMatter
{
public int Id { get; set; }
public decimal? Value { get; set; }
}
Now see if i can work out the thing with the templates. The link of #StephenMuecke should be sufficient
Update 2
Well that's wasn't that hard the code is now
#using (Html.BeginForm("Save", "MyController", FormMethod.Post))
{
<fieldset>
<table class="table table-striped table-hover ">
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Datum</th>
<th>NewValue</th>
</tr>
</thead>
<tbody>
#Html.EditorForModel()
</tbody>
</table>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
And for Views/Shared/EditorTemplates/TypeOfModel.cshtml
#model TypeOfModel
<tr>
<td>
#Html.HiddenFor(item => item.Id)
#Html.DisplayFor(item => item.Name)
</td>
<td>
#Html.DisplayFor(item => item.Value)
</td>
<td>
#Html.TextBoxFor(item => item.Value)
</td>
</tr>
The controller remains the same
When you just show items using a for loop then the naming convention used in the resulting html tag doesn't match up with what MVC is expecting when it binds the model upon form submit. The easiest way to fix this is to use #Html.EditorFor and custom editor templates. Here are a couple of examples:
ASP.NET MVC DisplayTemplate and EditorTemplates for Entity Framework DbGeography Spatial Types
Extending Editor Templates for ASP.NET MVC
I want to use the Check box for selecting multiple users and sending the result to my controller.
At first I was only sending the number of mobile users to the controller but it became necessary to send more than the number, I need number and name user, my controller and my view are as follows:
Would somehow send the number and name for example?
#using (Html.BeginForm("Enviar", "Home")) {
<table id="myTable">
<thead>
<tr>
<th>
<input type="checkbox" />
</th>
<th>#Html.DisplayName("Nome")</th>
<th>#Html.DisplayName("CANCELADO")</th>
<th>#Html.DisplayName("Numero")</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
<input type="checkbox" name="CELULAR" value="#item.CELULAR" />
</td>
<td name="Nome">#Html.DisplayFor(modelItem => item.NOME)</td>
<td name="Email">#Html.DisplayFor(modelItem => item.CANCELADO)</td>
<td name="Celular" value="#item.CELULAR">#Html.DisplayFor(modelItem => item.CELULAR)</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Selecionar"/>
}
The controller that receives:
[HttpPost]
public ActionResult Enviar(String[] celular) {
.....
return View();
}
When posting collections, you must index them correctly. Therfore, you must use a for loop instead of a foreach.
Also, why does your HttpPost take a String[] and not your Model? First change that to be your model type.
Assuming your model is: #model List<YourType>
Change your HttpPost to take that:
[HttpPost]
public ActionResult Enviar(List<YourType> model) {
.....
return View();
}
Now we'll rewrite your foreach into a for and use the CheckBoxFor helper. Also, add HiddenFor fields for any properties you want to see on post:
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.CheckBoxFor(m => m[i].CELULAR)
</td>
<td name="Nome">
#Html.HiddenFor(m => m[i].NOME)
#Html.DisplayFor(m => m[i].NOME)
</td>
<td name="Email">
#Html.HiddenFor(m => m[i].CANCELADO)
#Html.DisplayFor(m => m[i].CANCELADO)
</td>
<td name="Celular" value="#m[i].CELULAR">
#Html.DisplayFor(m => m[i].CELULAR)
</td>
</tr>
}