MVC normal html form binding - asp.net-mvc

I've seen thousands of examples using the razor BeginForm and I know that it auto binds the controller input to the submitted info... anyway I want to know if the same auto bind exists in a normal
<form method="get" action="#Url.Action("Index","Home")">
<input type="text" name="foo">
</form>
and if it doesn't ... how can I bind it... and please don't tell me to use html helpers...

yes you can bind model with normal html but the value of the name attribute has to be same as name of the property of the model e.g
public class viewmodel
{
public string FirstName {get; set;}
public string LastName {get; set;}
}
so your html will be
#model viewmodel
<form method="get" action="#Url.Action("Index","Home")">
<input type="text" name="FirstName" value="#model.FirstName"> //name should be of same name as property name
<input type="text" name="LastName" value="#model.LastName">
<input type='submit' value='Submit'/>
</form>
and finally your action will be
public ActionResult Index(viewmodel model)
{
return View(model);
}

Related

Can't prepopulate a form with html tags

I want to show a prepopulated form in jsp.
TestAction.java
import com.opensymphony.xwork2.ActionSupport;
public class TestAction extends ActionSupport {
private String firstName;
private String lastName;
public String execute(){
setFirstName("John");
setLastName("Doe");
return SUCCESS;
}
/** Getters & Setters **/
}
When I use html tags, it fails to do so,
Test.jsp
<!DOCTYPE html>
<html>
<head></head>
<body>
<form>
First Name <input type="text" name="firstName" > <br/>
Last Name <input type="text" name="lastName">
</form>
</body>
</html>
when instead I use struts2 tags, It works fine.
<s:form>
<s:textfield name="firstName"></s:textfield>
<s:textfield name="lastName"></s:textfield>
</s:form>
Can this be achieved using non struts2 tags ?
You can use JSP EL
<form>
First Name <input type="text" name="firstName" value="${fn:escapeXml(firstName)}"><br/>
Last Name <input type="text" name="lastName" value="${fn:escapeXml(lastName)}">
</form>
The values are strings, so better to escape them for safety.
If this jsp returned as a result of the action the variables along with standard scopes also searched the value stack. The action properties should be available from the value stack.

Html Helper HiddenFor Name broken, Id missing

I am using RazorGenerator to embed a view into a shared DLL. I have a HiddenFor that is generating an invalid name attribute and a missing id attribute.
I have a view model:
public class InsuredPartiesViewModel
{
public List<OrganisationViewModel> OrganisationWithBranches { get; set; }
...
public class OrganisationViewModel : IInsuredPartyViewModel
{
public bool CanQueryIVTRForBranches { get; set; }
...
In the Razor view I am using a #helper to iterate through:
#helper RenderHiddenFieldsForInsuredParty(int insuredPartyIndex, bool branchesAreVisible)
{
#Html.HiddenFor(x => Model.OrganisationWithBranches[insuredPartyIndex].CanQueryIVTRForBranches)
...
The output is:
<input data-val="true" data-val-required="The HasQueryIVTRForBranches field is required." name="<>4__this.Model.OrganisationWithBranches[0].HasQueryIVTRForBranches" type="hidden" value="False" />
The expected output is (I can see this from an older code branch):
<input data-val="true" data-val-required="The HasQueryIVTRForBranches field is required." name="<>4__this.Model.OrganisationWithBranches[0].HasQueryIVTRForBranches" type="hidden" value="False" />
The id attribute is missing and the name attribute of <>4__this.Model.OrganisationWithBranches[0].HasQueryIVTRForBranches looks like Razor's parser is getting stuck.
Have you seen this before? How do I debug the Razor output?
Identical behaviour in VS2013 and VS2015, ASP.NET MVC 5. The data is correct going into the View.
Update
The helper method NameFor also produces the error result.
#Html.NameFor(x => Model.OrganisationWithBranches[insuredPartyIndex].CanQueryIVTRForBranches)

Fields marked HiddenFor not binding to Model in MVC4

I have implemented an image upload child action form for an application. I have a strongly typed partial view.
public class ImageViewModel{
public long ImageId{get;set;}
public long OwnerId{get;set;}
public string ImageName{get;set;}
public string ImageDescription{get;set;}
public IEnumerable<HttpPostedFileBase> Files { get; set; }
}
Razor code looks something like this:
<form action="UploadImage" method="post" enctype="multipart/form-data">
#Html.ValidationSummary()
#Html.HiddenFor(m => m.OwnerId)
#Html.HiddenFor(m => m.ImageId)
#HtmlEditorFor(m=>m.ImageName)
<input type="file" name="Files" id="file0" />
<input type="submit" value="Upload" />
</form>
Here is the problem. When form is posted back, the model has uploaded file and ImageName value in it. But values that were bound using HiddenFor are missing.
[HttpPost]
public ActionResult UploadImage(ImageViewModel model)
{ ...}
I have checked HTML source. Hidden fields are rendered corrected with Id and names matching to property named of model. On post back I checked the raw request. Both hidden fields are carried in Form collection. But model binding is not setting the values of these fields in properties.
Is there something that I am missing about these hidden fields?
Thanks

MVC File upload validation

I have a simple situation where I have a page that uploads Files, for some importing. At the moment, all I have is a file upload input on my page.
this is what my get controller looks like
public ActionResult FileUpload()
{
return View();
}
This is what my view looks like
#{
ViewBag.Title = "FileUpload";
}
<h2>FileUpload</h2>
<form action="/Home/FileUpload" method="post" enctype="multipart/form-data">
<input type="file" id="newFile" name="newFile" />
<input type="submit" id="submitButton" value="Submit" />
</form>
and this is what my post action looks like
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase newFile)
{
if (newFile.ContentLength > 0)
{
//do stuff here
}
return View("Index");
}
You will of course notice there is no mention of a model here as I cannot find a way to create a model for this situation. I would like to have some very basic validation, along the lines of 'please choose a file before you upload', thats all.
Is there a way to achieve this?!
Thanks in advance
Will
Create model class with string property newFile and put a Required on it.
In controller accept not HttpPostedFile but your model class.
You should add the client side validation manually:
<input type="file" data-val="true" data-val-required="please select a file" name="file" />
#Html.ValidationMessage("file")

asp.net mvc default model binding problem

I have some problems with ASP.NET MVC’s default model binder. The View contains HTML like this:
<input name="SubDTO[0].Id" value="1" type="checkbox">
<input name="SubDTO[1].Id" value="2" type="checkbox">
This is my simplified ‘model’:
public class SubDTO
{
public virtual string Id { get; set; }
}
public class DTO
{
public List<SubDTO> SubDTOs { get; set; }
public DTO()
{
SubDTOs = new List< SubDTO>();
}
}
All this works fine if the user selects at least the first checkbox (SubDTO[0].Id). The controller ‘receives’ a nicely initialised/bound DTO. However, if the first check box is not selected but only, for example, SubDTO[1].Id the object SubDTOs is null. Can someone please explain this ‘strange’ behaviour and how to overcome it? Thanks.
Best wishes,
Christian
PS:
The controller looks like this:
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult Create(DTO DTO)
{
...
}
PPS:
My problem is that if I select checkbox SubDTO[0].Id, SubDTO[1].Id, SubDTO[2].Id SubDTOs is initialised. But if I just select checkbox SubDTO[1].Id, SubDTO[2].Id (NOT the first one!!!) SubDTOs remains null. I inspected the posted values (using firebug) and they are posted!!! This must be a bug in the default model binder or might be missing something.
This behavior is "by design" in html. If a check-box is checked its value is sent to the server, if it is not checked nothing is sent. That's why you get null in your action and you'll not find value in the posted form either. The way to workaround this is to add a hidden field with the same name and some value AFTER the check-box like this:
<input name="SubDTO[0].Id" value="true" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="true" type="checkbox">
<input name="SubDTO[1].Id" value="false" type="hidden">
In this way if you check the check-box both values will be sent but the model binder will take only the first. If the check-box is not checked only the hidden field value will be sent and you\ll get it in the action instead of null.
I think this post on Scott Hanselman's blog will explain why. The relevant line is:
The index must be zero-based and unbroken. In the above example, because there was no people[2], we stop after Abraham Lincoln and don’t continue to Thomas Jefferson.
So, in your case because the first element is not returned (as explained by others as the default behaviour for checkboxes) the entire collection is not being initialized.
Change the markup as follows:
<input name="SubDTOs" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTOs" value="<%= SubDTO[1].Id %>" type="checkbox">
What's being returned by your original markup is an unrelated set of parameters, i.e. like calling RedirectToRouteResult Create(SubDTO[0].id, SubDTO[1].id, ..., SubDTO[n].id) which is clearly not what you want, you want an array returned into your DTO object so by giving all the checkboxes the same name the return value to your function will be an array of ids.
EDIT
Try this:
<input name="SubDTO[0].Id" value="<%= SubDTO[0].Id %>" type="checkbox">
<input name="SubDTO[0].Id" value="false" type="hidden">
<input name="SubDTO[1].Id" value="<%= SubDTO[1].Id %>" type="checkbox">
<input name="SubDTO[1].Id" value="false" type="hidden">
You have to return something to make sure there is an element for each index, I suspect that any gap will cause a problem so I'd suggest using a 'null' ID, for example 0 or -1 and then process that out later in your code. Another answer would be a custom model binder.
There is always the alternate option of adding a property to your class that takes an array of strings and creates the SubDTO array from that.
public List<string> SubDTOIds
{
get { return SubDTO.Select(s=>s.Id).ToList(); }
set
{
SubDTOs = new List< SubDTO>();
foreach (string id in value)
{
SubDTOs.Add(new SubDTO { Id = id });
}
}
}
or something like that

Resources