Form-
#using IEnumerable<Myapplication.Models.CardModel>
#foreach(var item in Model)
{
<form method="post" action="/Upload/EditCard/?cardID=#item.cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => item.cardTitle)
#Html.TextBoxFor(cardTitle => item.cardTitle)
</div>
<img src="#item.cardFilePath" />
<input type="submit">
</form>
}
Method-
[HttpPost]
public void EditCard(CardModel card, HttpPostedFileBase file) {}
Where in form I am sending values through this form, and cardID is sent in form's url parameter.
For other value like cardTitle is coming null in EditCard Method.
How do I get this value using repeater?
However when data is not IEnumerable type , then I was able to send value through form directly as-
#using Myapplication.Models.CardModel
<form method="post" action="/Upload/EditCard/?cardID=#Model.cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => m.cardTitle)
#Html.TextBoxFor(m=> m.cardTitle)
</div>
<img src="#Model.cardFilePath" />
<input type="submit">
</form>
}
but In case of repeater values don't come at method. As soon as i change values of title, or anything else, The values comes old one.
From the pictures-
And server code-
As you can see from 1st picture that, Form is editable for one record from the list. As soon as I change something in i.e. Title to --> 2nd Upload to 2nd Uploadsssss
Then this values is null at server side. I mean this form don't send values of it.
Note-
However I can send values in URL through parameters. But if I do change in something like Title or aboutCard model value. The form keeps sending only those values which has come by default while the form was rendered.
Rather than using foreach use for loop. To apply indexing you would need to convert Model to List
#{ var list=Model.ToList();)
#for(var i = 1;i <= list.Count();i++)
{
<form method="post" action="/Upload/EditCard/?cardID=#list[i].cardID" enctype="multipart/form-data">
<h3>
Change Title-
</h3>
<div class="display-field">
#Html.HiddenFor(m => list[i].cardTitle)
#Html.TextBoxFor(m=> list[i].cardTitle)
</div>
<img src="#list[i].cardFilePath" />
<input type="submit">
</form>
}
Update..
I have tested same but doesnt work. I have created workaround check if that helps.
In controller get title using cardId
var title=Request["[" + (model.cardTitle)+ "].cardTitle"];
Same thing can be done for other properties for model.
Note that i have changed for loop, index now starts with 1
You need to change IEnumerable to IList, and then you'll be able to bind Model correctly by index.
See this working exaple.
View Page
#model IList<MvcApplication3.Models.CardModel>
#using (Html.BeginForm("EditCard", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
for (int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => Model[i].CardID)
#Html.TextBoxFor(cardTitle => Model[i].CardTitle)
<img src="#Model[i].CardFilePath" />
<input type="file" name="files">
}
<br>
<input type="submit" value="Upload File to Server">
}
Controller
[HttpPost]
public void EditCard(IList<CardModel> cm, IEnumerable<HttpPostedFileBase> files)
{
string strfile = string.Empty;
string cardTitle = string.Empty;
if (files != null)
{
foreach (var file in files) //loop through to get posted file
{
strfile = file.FileName;
}
}
if (cm != null)
{
foreach (var item in cm) //loop through to get CardModel fields
{
cardTitle = item.CardTitle;
}
}
}
I dont know if this helps in solving your problem. I tried this and it works really well.
The Model
public class CardFileModel
{
public int CardId { get; set; }
public string Name { get; set; }
public HttpPostedFileBase File { get; set; }
}
Index Action
public ActionResult Index()
{
List<CardFileModel> cards = new List<CardFileModel>
{
new CardFileModel{ CardId =1 , Name="Card1" },
new CardFileModel{ CardId =2 , Name="Card2" }
};
return View(cards);
}
Home View
#model List<MVC3Stack.Models.CardFileModel>
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
#for (int i = 0; i < Model.Count; i++)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
<div>
#Html.TextBoxFor(x => x[i].CardId)
</div>
<div>
#Html.TextBoxFor(x => x[i].Name)
</div>
#Html.TextBoxFor(x => x[i].File, new { type = "file" })
<input type="submit" value="submit" id="submit" />
</div>
}
}
index post action
[HttpPost]
public ActionResult Index(List<CardFileModel> card)
{
//Access your card file from the list.
var name = card.FirstOrDefault().Name;
return View();
}
And here are the results in the quick watch
Hope this helps.
Related
I'm still learning MVC and I don't know if it's possible or not, In my application, I'm doing an excel upload task.
So here Excel uploaded and I'm adding to those excel data to view bag and shows in the view.
for (int i = 2; i <= range.Rows.Count; i++)
{
try
{
M_Employee emp = new M_Employee();
string comName = ((Microsoft.Office.Interop.Excel.Range)range.Cells[i, 1]).Text;
var tempCompanyId = (from c in db.CreateCompany where c.CompanyName == comName select c.Id).First();
emp.CompanyId = tempCompanyId;
emp.EmpNo = int.Parse(((Microsoft.Office.Interop.Excel.Range)range.Cells[i, 2]).Text);
emp.EmpName = ((Microsoft.Office.Interop.Excel.Range)range.Cells[i, 3]).Text;
string dep = ((Microsoft.Office.Interop.Excel.Range)range.Cells[i, 4]).Text;
var tempDepId = (from d in db.CreateDepartment where d.Department == dep select d.Id).First();
emp.DepId = tempDepId;
string dessig = ((Microsoft.Office.Interop.Excel.Range)range.Cells[i, 5]).Text;
var tempDessId = (from h in db.CreateDesignation where h.Designation == dessig select h.Id).First();
emp.DesignId = tempDessId;
employees.Add(emp);
}
catch (Exception ex)
{
ViewBag.Error = "Error in " + i + " record";
return View("Import");
}
}
if (employees !=null)
{
ViewBag.EmpList = employees;
return View("Import");
}
In the view, It shows the excel imported data the user.
So to upload these data to the database table, I have created a button with mapping the upload action result in the view
<input type="button" value="Upload" class="btn btn-success" onclick="location.href='#Url.Action("UploadEmployees", "M_Employee")'" />
In that Action I tried to call those ViewBag.EmpList to get the same data and pass to the table.
foreach (var item in ViewBag.EmpList)
{
int ComId = item.CompanyId;
int EmpNo = item.EmpNo;
string EmpName = item.EmpName;
int DepId = item.DepId;
int DesId = item.DesignId;
}
But there I'm getting an error viewbag value is null. So is there any other way to do this?
Thanks
Editing--
This is my view
#{
ViewBag.Title = "Import";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
#using (Html.BeginForm("Import", "M_Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="card card-primary">
<div class="card-header">
<h1 class="card-title"><b>Upload Employees from Excel</b></h1>
</div>
<!-- /.card-header -->
<div>
<br />
#Html.Raw(ViewBag.Error)
<h4><span>Select Excel File</span></h4>
<input type="file" name="excelFile" class="btn btn-warning" />
<br />
</div>
<div class="row">
<div class="col-md-1">
<br />
<br />
<input type="submit" value="Import" class="btn btn-info" />
</div>
<div class="col-md-1">
<br />
<br />
<input type="button" value="Upload" class="btn btn-success" onclick="location.href='#Url.Action("UploadEmployees", "M_Employee")'" />
</div>
</div>
<div class="card-body p-0">
<table class="table table-striped">
<tr>
<th>Company</th>
<th>EmpId</th>
<th>EmpName</th>
<th>Department</th>
<th>Dessignation</th>
</tr>
#if (ViewBag.EmpList != null)
{
foreach (var item in ViewBag.EmpList)
{
<tr>
<td>
#item.CompanyId
</td>
<td>
#item.EmpNo
</td>
<td>
#item.EmpName
</td>
<td>
#item.DepId
</td>
<td>
#item.DesignId
</td>
</tr>
}
}
</table>
</div>
<!-- /.card-body -->
</div>
}
</div>
This is the view model I have created.
[NotMapped]
public class EmpExcelUploadViewModel
{
public int CompanyId { get; set; }
public int EmpNo { get; set; }
public string EmpName { get; set; }
public int EmpDep { get; set; }
public int EmpDes { get; set; }
}
You can use ViewBag or ViewData for transferring data only one-way from Controller to View.
You should resend data from client's browser to your back-end with form.
Or if user can not edit data you can use any of:
Save file on the first step, then use the identifier of uploaded earlier file, re-read it for saving
Parse file and save parsed data into storage as draft on the first step, then just remove draft mark from data on the second step
You can not use ViewBag to move data from a client computer to a server. You can use Session or TempData (if the data is small) to keep data in the server, but I don' t recommend to use it since it affects app scalability.
You have 2 ways
Repeat downloading in your upload action and save data to a database
or you have to fix the action, using model instead of viewbag
....
if (employees !=null)
{
return View("Import", employees);
}
else ... you error code
in Import view add form and replace an ancor by submit button
#model List<Employee>
#using (Html.BeginForm("UploadEmployees", "M_Employee", FormMethod.Post))
{
.... emloyee input controls
<button type="submit" value="Upload" class="btn btn-success"> </>
}
in UploadEmployees action you can get data from an input parameter and save to database.
I want to create a view where I select "checkbox" an Item and then click the button "Next" which will send a post request with the Id of the selected Item so I can use its Id to redirect to an action that requires an Id
This is the View
#model IEnumerable<Game>;
#{
ViewBag.Title = "Game Select List";
}
<form method="post">
<div class="card-body sm">
<div class="card-deck">
#foreach (var game in Model)
{
var photoPath = "~/image/" + (game.PhotoUrl ?? "noImage.png");
<div id="crta" class="card m-3" style="min-width: 18rem; max-width:30%;">
<div class="card-header">
<h3>#game.Name</h3>
<h1 hidden>#game.Id</h1>
</div>
<img class="card-img-top " height="400" title="#game.Name"
src="#photoPath" asp-append-version="true">
<div class="card-footer">
<label asp-for="#game.IsSelected"></label>
<input type="checkbox" value="#game.IsSelected" asp-for="#game.IsSelected"/>
</div>
</div>
}
</div>
<button type="submit">Next</button>
</div>
</form>
And this is the action
[HttpGet]
public IActionResult SelectGame()
{
var model = gameRepository.GetAllGames();
return View(model);
}
[HttpPost]
public IActionResult SelectGame(int id)
{
var game = gameRepository.GetById(id);
if(game==null)
{
return View("NotFound");
}
if(ModelState.IsValid)
{
if(game.IsSelected==true)
{
return RedirectToAction("details", new { id = game.Id });
}
}
return View(game);
}
It returns null.
I tried
<a asp-controller="home" asp-action="details" asp-route-id="#game.id">Select</a>
But I don't like how each item will get its "select button" I don't know how to call the game.id outside the foreach loop to use it instead of the post request!
The final result would be as this: You click a button then a modal with the game list will get call then you select a game from it and then you click next which will redirect you to the next modal(<= this view needs an id)
I want to create a view where I select "checkbox" an Item and then
click the button "Next" which will send a post request with the Id of
the selected Item so I can use its Id to redirect to an action that
requires an Id
For this situation, you can trigger a js event when you click the submit button. In this event, you can add a hidden input control, assign the name to the id(the same as the parameter name in SelectGame action), and assign the value to the id of the currently selected picture Id.
I don't know how to call the game.id outside the foreach loop to use
it instead of the post request!
You can add a custom attribute data-id to each checkbox and assign it to #game.Id, so that in jquery, you can cycle through all the checkboxes to determine which one is selected, and get id value from the selected checkbox data-id attribute to hidden input control value.
And it should be noted that you should ensure that the user can only select one of the checkboxes, not multiple selections, otherwise the last id in the selected picture will always be passed.
In your post SelectGame action, the last sentence of return View(game); will be an error, because the game is currently a single data of Game object, and the view received by the SelectGame corresponding model is a list object:IEnumerable<Game>.
Just try the following code, which solve all these issues:
[HttpPost]
public IActionResult SelectGame(int id)
{
var game = gameRepository.GetById(id);
if(game==null)
{
return View("NotFound");
}
if(ModelState.IsValid)
{
if(game.IsSelected==true)
{
return RedirectToAction("details", new { id = game.Id });
}
}
List<Game> games = new List<Game>() { game };
return View(games);
}
View:
#model IEnumerable<Game>;
#{
ViewBag.Title = "Game Select List";
}
<form method="post">
<div class="card-body sm">
<div class="card-deck">
#foreach (var game in Model)
{
var photoPath = "~/OrderImage/" + (game.PhotoUrl ?? "noImage.png");
<div id="crta" class="card m-3" style="min-width: 18rem; max-width:30%;">
<div class="card-header">
<h3>#game.Name</h3>
<h1 hidden>#game.Id</h1>
</div>
<img class="card-img-top " height="400" title="#game.Name"
src="#photoPath" asp-append-version="true">
<div class="card-footer">
<label asp-for="#game.IsSelected"></label>
<input type="checkbox" asp-for="#game.IsSelected" data-id="#game.Id" />
</div>
</div>
}
</div>
<button type="submit" onclick='submitform()'>Next</button>
</div>
</form>
#section Scripts{
<script>
$('input[type="checkbox"]').on('change', function () {
if ($(this).is(':checked')) {
$('input[type="checkbox"]').not(this).prop('checked', false);//allow only one checkbox can be selected.
}
});
function submitform() {
var id = 0;
$('input[type="checkbox"]').each(function () {
if ($(this).is(':checked')) {
id = $(this).attr("data-id");// get selected image Id to variable id.
}
});
$('<input type="hidden" name="id"/>').val(id).appendTo('form'); // add hidden input to form to pass selected image Id.
$("form").submit();
}
</script>
}
Here is the test result:
I am looping through an IEnumerable of my model:
#model IEnumerable<Testing.Models.ProductItem>
#{
ViewBag.Title = "Buy Products";
}
<div class="row">
#foreach (var product in Model)
{
using (Html.BeginForm())
{
#Html.HiddenFor(Model => product)
... More Controls and stuff...
<input type="submit" value="Add To Kart" class="btn btn-info">
}
}
</div>
and on submit I want to pass the selected instance of my model back to my controller:
[HttpPost]
public ActionResult Index(ProductItem product)
{
... Do Stuff ...
return View();
}
However I have tried a few things but always seem to be getting null passed into the controller... Please could someone please help point me in the right direction?
EDIT
I dont actually need to the full model instance as I can get this within the controller from the ID - so I have tried the following:
#model IEnumerable<Testing.Models.ProductItem>
#{
ViewBag.Title = "Buy Products";
}
<div class="row">
#foreach (var product in Model)
{
using (Html.BeginForm())
{
#Html.HiddenFor(Model => product.ID)
#Html.TextBox("qty", "1", htmlAttributes: new { #style = "width: 30px;" })
... More Controls and stuff...
<input type="submit" value="Add To Kart" class="btn btn-info">
}
}
</div>
which posts to the controller:
[HttpPost]
public ActionResult Index([Bind(Include = "ID")] int? ID, [Bind(Include = "qty")] int? qty)
{
return null;
}
The textbox is not part of the model as it is user input - this value is passed nicely into the actions parameter, however I am still getting a null for the ID in the HiddenFor control. Is this to do with the naming of the control? I dont seem to be able to add a name to the HiddenFor control.
I know this puts a different light on the original question but I am hoping you may still be able to help.
I take the note about the BeginForm being inside the loop - creating for each item in the list... Is there an easy alternative to this (note I haven't tried anything yet).
It sounds like you're trying to use HiddenFor on a complex type and that won't work. You'll need to use a property of ProductItem like ProductId or something like that, which will most likely be an int or Guid.
Now that you have cleared up the complex binding to a simple field, you'll notice that your name is being set to product.id and that is why it is always null in your controller. You can't override the name attribute with Hidden for, so you'll want to change your code to:
#foreach (var product in Model)
{
using (Html.BeginForm())
{
#Html.Hidden("ID", product.ID)
#Html.TextBox("qty", "1", htmlAttributes: new { #style = "width: 30px;" })
<input type="submit" value = "Add To Kart" class="btn btn-info">
}
}
I have managed to arrive at my desired functionality (rightly or wrongly) with the following:
#model List<ShoppingKartTest.Models.ProductItem>
#{
ViewBag.Title = "Buy Products";
}
#foreach (var item in Model)
{
using (Html.BeginForm())
{
<input type="hidden" value="#item.ID" name="ID" />
#Html.TextBox("qty", "1", new { #style = "width: 30px;" })
<input type="submit" value="Add To Kart" class="btn btn-info">
}
}
Which correctly submits the Hidden ID and the contents of the Textbox to the Controller Action:
[HttpPost]
public ActionResult Index(int ID, int qty)
{
//... Do stuff with parameters...
return View();
}
I would be interested to hear any comments on this. I know that I was told above that I shouldn't have my BeginForm within the loop... But it just works for me.
Instead of Model => product.Id, try p=> product.Id
#model IEnumerable<Testing.Models.ProductItem>
#{
ViewBag.Title = "Buy Products";
}
<div class="row">
using (Html.BeginForm())
{
#foreach (var product in Model)
{
#Html.HiddenFor(p => product.ID)
#Html.TextBox("qty", "1", htmlAttributes: new { #style = "width:
30px;" })
... More Controls and stuff...
}
<input type="submit" value="Add To Kart" class="btn btn-info">
}
</div>
After many years of getting a lot of great advice here, I finally have hit a wall teaching myself MVC4 ASP.net.
I used this post this post to pass a List of Type Class from my controller, to my view, and back to the controller..
public ActionResult SelectProducts()
{
displayProductsList = db.Products.ToList();
displayProductsList.ForEach(delegate(Product p)
{
//get list of recievables for the product
GetReceivablesByProductId(p.ProductID).ForEach(delegate(Receivable r)
{
//Get count of items in inventory for each recievable
p.CurrentInventory += this.CountItemsByReceivableID(r.RecievableID);
});
});
return View(FilterProductInventoryList(displayProductsList));
}
And here is my view code..
#model List<CarePac2.Models.Product>
#{
ViewBag.Title = "SelectProducts";
}
<h2>SelectProducts</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
#*row values*#
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.DisplayFor(m => m[i].Brand)</td>
<td>#Html.DisplayFor(m => m[i].ProductName)</td>
<td>#Html.DisplayFor(m => m[i].UnitType)</td>
<td>#Html.DisplayFor(m => m[i].SalePrice)</td>
<td>#Html.DisplayFor(m => m[i].CurrentInventory)</td>
<td>
#Html.EditorFor(m => m[i].OrderQuantity)
#Html.ValidationMessageFor(m => m[i].OrderQuantity)
</td>
<td></td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
#*<input type="submit" value="Cancel" />*#
</p>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
Here the view show it has values for the List that was passed from controller to view..
Visually the view displays the data correctly (apparently i can't post an image of it until i have 10 reputation to post images)
when i hit submit and return to the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectProducts(List<Product> selectedProducts)
{
if (ModelState.IsValid)
{
}
}
The variable selectedProducts Is NOT NULL. The list has 3 Product items in it, however, as you can see in the image below in the debugger, even though i have 3 product items, none of the values exist from when the List of Product was originally passed to the view...
for example (since i can't post images yet):
selectedProducts[0].ProductID=0
selectedProducts[0].ProductName=null
selectedProducts[1].ProductID=0
selectedProducts[1].ProductName=null
You need to use #Html.HiddenFor():
#Html.HiddenFor(m => m[i].ProductID)
#Html.HiddenFor(m => m[i].ProductName)
This will send the data back to the controller. This creates an <input type="hidden"> that will be part of the form POST.
I have a parameterless Index for the HttpGet which works. But when I post it the HttpPost version of Index is invoked and the viewmodel object is passed in, but there is only the value of the dropdown in it. The rest is null (products, title)
[HttpPost]
public ActionResult Index(ProductsViewModel pvm)
{
// breakpoint on line 36, shows that pvm.Title is null and Products too.
return View(pvm);
}
My compilable and running example can be downloaded from my OneDrive http://1drv.ms/1zSsMkr
My view:
#model KleinKloteProductOverzicht.Models.ProductsViewModel
#using (Html.BeginForm("Index", "Products"))
{
<h2>#Html.DisplayFor(m => m.Title)</h2>
<input type="submit" value="post dit" /><br/>
<div class="row">
<div class="col-lg-2 col-md-2">
#Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { #class = "multiselect"})
</div>
</div>
if (Model.Products.Count() > 0)
{
<div class="row">
#foreach (var item in Model.Products)
{
#Html.DisplayFor(i => item.Name);
}
</div>
}
}
If I have this view model:
public class ViewModel
{
public string Name {get;set;}
public string SelectedLocation {get;set;}
public IEnumerable<SelectListItem> Locations {get;set;}
}
And your actions look like this:
public ActionResult MyForm()
{
var vm = new ViewModel
{
Locations = context.Locations.ToList() // Some database call
}
return View(vm);
}
[HttpPost]
public ActionResult MyForm(ViewModel vm)
{
vm.Locations // this is null
}
It is null because the model binder can't find a form control that is setting its data.
The <form> must set some data in the view for the model binder to pick it up.
<form>
Name: <input type="text" id="name" />
</form>
This will set the Name property on the view model, because the model bind can see the id of the form control and uses that to know what to bind to.
So in terms of your view, you need to make sure you wrap any content that you want to post back to the server with #using(Html.BeginForm())
Anyway this is my guess.
Well, you seem to be confused as to how [HttpPost] and form tags interact with eachother.
You see, when .NET MVC binds your parameters in your controller actions, it tries to derive that data from the request. For [HttpGet] it does this by looking at the query string.
For [HttpPost] calls, it also looks at the Request.Form. This variable is populated with the values of all input fields that were inside the form you submitted.
Now, this is your view:
#using (Html.BeginForm("Index", "Products"))
{
<h2>#Html.DisplayFor(m => m.Title)</h2>
<input type="submit" value="post dit" /><br/>
<div class="row">
<div class="col-lg-2 col-md-2">
#Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { #class = "multiselect" })
</div>
</div>
if (Model.Products.Count() > 0)
{
<div class="row">
#foreach (var item in Model.Products)
{
#Html.DisplayFor(i => item.Name);
}
</div>
}
}
You only have one select tag (generated by Dropdownlistfor) but no other inputs. That's why .NET MVC cannot infer any other data for your view model.
If you change your view to this:
#model KleinKloteProductOverzicht.Models.ProductsViewModel
#using (Html.BeginForm("Index", "Products"))
{
<h2>#Html.DisplayFor(m => m.Title)</h2>
<input type="submit" value="post dit" /><br/>
<div class="row">
<div class="col-lg-2 col-md-2">
#Html.DropDownListFor(x => x.CurrentSort, EnumHelper.GetSelectList(typeof(SortOptions)), new { #class = "multiselect" })
</div>
</div>
if (Model.Products.Count() > 0)
{
<div class="row">
#for (var i = 0; i < Model.Products.Count; i++)
{
#Html.DisplayFor(model => model.Products[i].Name)
#Html.HiddenFor(model => model.Products[i].ID)
}
</div>
}
}
You'll see I've added a hidden input (<input type="hidden">) for the product id. Note that the product name still will be null.
I would suggest you follow a tutorial on .NET MVC and read up on some of the concepts behind it, because the very fact that you ask this question reveals that you have much to learn.
Best of luck!
P.S. One last tip: #Html.Blablabla writes directly to your view. You usually don't need that ";" at the end, because it will be inside your generated html.
Your property is not associated with a "postable" control, therefore it will not be submitted along with the form data. If your really want to get the value in your Title property, just set it as a hidden input.
#Html.HiddenFor(m => m.Title)
A label will not be posted when submitting a form but an input will. This is exactly what HiddenFor does; it creates a hidden input element which will be picked up by the form submit.