I have this two lines in a Razor template:
#Html.Hidden("step", Model.Step)
<p>#Html.Label(Model.Step.ToString())</p>
And they produce two different values:
<input data-val="true"
data-val-number="The field Step must be a number."
data-val-required="The Step field is required."
id="step"
name="step"
type="hidden"
value="0">
<p>
<label for="">1
</label>
</p>
How is this possible?
Property Step is of a type Int32 and is incremented every POST action.
EDIT:
#model ***.WebUI.Models.OrderViewModel
#{
ViewBag.Title = "New order";
}
<h2>
New order</h2>
#using (Html.BeginForm())
{
#Html.Hidden("step", Model.Step)
<p>#Html.Label(Model.Step.ToString())</p>
<div>
//other inputs
</div>
}
You have not shown you POST method, but based on "Property Step is of a type Int32 and is incremented every POST action." I assume it looks something like
public ActionResult Edit(OrderViewModel model)
{
model.Step = model.Step + 1;
return View(model);
}
When you post a model, the models values are added to ModelState (along with any ModelState errors) so in the first post, the ModelState value of Step will be 0. Html helpers use ModelState values for binding (if one exists) so when you return the view #Html.Hidden("step", Model.Step) will bind to the value of 0 (not the models value of 1). The reason for this behavior is explained in this answer.
The correct approach is to follow the PRG pattern (redirect to the GET method, passing a parameter indicating the Step value and initialize a new OrderViewModel), however you can make this work by clearing ModelState so that the Html Helper will use the model value.
public ActionResult Edit(OrderViewModel model)
{
ModelState.Clear(); // clear all model state
model.Step = model.Step + 1;
return View();
}
However, use this with caution. ModelState.Clear() removes all errors as well.
Related
For example, On my Home/Index page I display the information in my database. I want to create a search bar that will let me search for all the values that match my search.
e.g. database has employee, salary, and ID. I select employee search button and search for "Bob". The search will show me all the employees named Bob.
I have it right now so that I can display everything on the database to my index.cshtml from my HomeController. I can do simple searches like
public ActionResult Index(string employeeName){
//If employeeName, I return employeeName
//else I return something else}
But I am not sure how to search for multiple fields and return them. I know I can't use overloaded ActionResults, so I tried using [ActionName] and create different Index methods with differing parameters, but the search wouldn't work. I'm also not using ADO.NET entity model because I'm trying to do this in an existing code that doesn't implement entity model.
edit- Home controller
public class HomeController : Controller{
public ActionResult NameSearch(string EmployeeName)
{ //code to display JUST employee's name that matches the Employee variable}
public ActionResult SalarySearch(double salary)
{ //code to display JUST employee's sthat matches the salary variable}
public ActionResult Index()
{
//return View(model); the model has all the data that will be displayed in index.cshtml
}
index.cshtml-
<h2>Employee</h2>
<form action="/" method="get">
<input type="text" name="EmployeeName" />
<input type="submit" value="Search" />
</form>
<h3>Search Salary</h3>
<form action="/" method="get">
<input type="text" name="salary" />
<input type="submit" value="Search" />
</form>
So there are multiple search boxes. If I search "bob" in the Employee search I want to return all the matching names. But I am not sure If I am going at this right,
final edit-
I got this done by using something like this in Index.cshtml
<p>
#using (Html.BeginForm("serialDisplay", "Home", FormMethod.Get))
{
<p>
serial Number: #Html.TextBox("serialNumber") <br />
<input type="submit" value="Search" />
</p>
}
</p>
Maybe I understand the question now. You're really concerned more with the parameters on the Controller method signature, not how to do the internal logic in the controller, correct?
Are you aware that parameters can be defaulted to null or some other sensible value if they're not passed in?
public ActionResult Index( int? id = null, string employeeName = null,double? salary = null){
// if id != null, add it to the where clause.
// if employeeName != null or white space, add it to the where clause (most browsers will send it as "" if the user doesn't enter anything).
// if salary != null, add it to the where clause, you probably actually want a salaryMin and salaryMax
}
This is the simplest way to approach optional parameters, there's also more you can do with custom model binders. You could also play around with Routes to send you to differently named methods based on parameters supplied. It also lets you construct things so that you can do salary AND name.
edit: link to MS documentation https://msdn.microsoft.com/en-us/library/dd264739.aspx#Optional Arguments
I want to give my TextAreaFor a default value from my database (a certain comment which they can edit). I use the #Value and I can see it in the html code (inspect element), but in the textarea itself it isn't visible.
My code:
#Html.TextAreaFor(a => a.description, new { Value = ViewBag.Description }
ViewBag.Description = adver.description;
textarea works differently then other input fields in HTML and because of this the value attribute doesn't actually do anything that you'd expect.
<textarea value="you won't see this">you will see this</textarea>
Versus a text field:
<input type="text" value="you will see this" />
Because of this you need to assign the text that you want to be shown in the textarea to the variable before creating the textarea.
Edit
Here's a more complete example for you:
public ActionResult MyAction()
{
var myDefaultDescription = ""; //Replace with whatever you initialize ViewBag.Description with
return View(new AdverModel{ description = myDefaultDescription });
}
This will cause the model to be initialized in the controller. The #Html.TextAreaFor() only uses fields and values from the model object that's passed into the view. The Model variable is read only in the view so you must initialize it in the controller and pass it to the view during the return from the controller.
This will cause that field to auto populate with the default value.
If a view is ment to allow editing of only one property but all other properties are being displayed (DisplayFor, non-editable) as well, what is a good way to design the handing-over of changed value to the controller?
Right now I have hidden-input-fields for all properties that are displayed with DisplayFor and the controller gets the full object passed.
This is pretty much ineffecient and I know it would suffice to post only the ID of that object and the changed value.
The user can input the value to be changed like this:
#Html.EditorFor(model => model.Verkaufspreis)
#Html.ValidationMessageFor(model => model.Verkaufspreis)
I could pass the ID of the object like this
#Html.ActionLink("Edit", "Edit", new { id=Model.ID })
But how would I pass the value that was changed? Thank you for your input.
if you want to get a value and you do not want to return the model knowing the name of the value you can use FormCollection
[HttpPost]
public ActionResult (FormCollectio collection)
{
string Verkaufspreis1=collection["Verkaufspreis"].ToString();
}
MVC allows all kinds of binding, for instance you could go
[HttpPost]
public ActionResult (int ID, String Verkaufspreis)
//Have to be the same propery name as your model
{
//Get original object with the ID
//change the "Sell of Stock" field
}
This would dynamically pass the ID and Verkaufspreis as parameters.
This would allow you to only have the ID and the value needing to be changed, as you would be getting the rest from your database(or wherever) on postback, only updating the value that is necessary.
You could do the entire model as a parameter, although this would mean you would have alot of empty values if you're not passing them to the client.
Instead of putting a lot of hidden inputs in your form, you can do this.
Simply post the changed values and the id to the action method. Read the full entity from your data source and update the new values and save it back.
[HttpPost]
public ActionResult Update(CustomerViewModel model)
{
Customer customer=repositary.GetCustomerFromID(model.ID)
customer.DisplayName=model.DisplayName;
repositary.SaveCustomer(customer);
return RedirectToAction("ProfileUpdated");
}
In this case, you need to post only the ID and DisplayName properties from the form
#model CustomerViewModel
<h2>Update Customer details</h2>
#using(Html.Beginform())
{
Display Name : #Html.TextBoxFor(x=>x.DisplayName)
#Html.HiddenFor(x=>x.ID)
<input type="submit" value="Save" />
}
I have the following Action to display a form with 3 items :
[HttpGet]
public ActionResult ReferAFriend()
{
List<ReferAFriendModel> friends = new List<ReferAFriendModel>();
ReferAFriendModel f1 = new ReferAFriendModel();
ReferAFriendModel f2 = new ReferAFriendModel();
ReferAFriendModel f3 = new ReferAFriendModel();
friends.Add(f1);
friends.Add(f2);
friends.Add(f3);
return View(friends);
}
and then a Post action
[HttpPost]
public ActionResult ReferAFriend(IEnumerable<ReferAFriendModel> friends)
{
if(ModelState.IsValid){
EDIT
My View looks like this:
#model IEnumerable<Models.ReferAFriendModel>
#for(int i=0;i<Model.Count();i++)
{
#Html.Partial("_ReferAFriend", Model.ElementAt(i));
}
The partial looks like this:
#model Models.ReferAFriendModel
<p>
#Html.LabelFor(i => i.FullName) #Html.TextBoxFor(i => i.FullName)<br />
#Html.LabelFor(i => i.EmailAddress) #Html.TextBoxFor(i => i.EmailAddress)
#Html.HiddenFor(i=>i.Id)
</p>
When I post, I can see the fields are posted in the Request.Form object e.g Request.Form["FullName"] will show: "David Beckham","Thierry Henry". "Chicharito Fergurson" which are the values I entered in the form. But, the in the Post action,the value for 'friends' is always null. The ReferAFriendModel has three public properties Id, EmailAddress and FullName.
What am I doing wrong?
You may take a look at the following blog post about the wire format for arrays and dictionaries. Personally I always use editor templates in my views which take care of generating proper names of the input fields so that the default model binder is able to bind the values correctly.
#model IEnumerable<ReferAFriendModel>
#using (Html.BEginForm())
{
#Html.EditorForModel()
<input type="submit" value="OK" />
}
and in the corresponding editor template (~/Views/Shared/EditorTemplates/ReferAFriendModel.cshtml):
#model ReferAFriendModel
#Html.EditorFor(x => x.Prop1)
#Html.EditorFor(x => x.Prop2)
...
Is this a bug or a feature?
All code below has been simplified for the sake of brevity and easy replication and does not actually do anything useful other than highlight the behavior.
I have a class that includes an int named ID:
public class FooterLink
{
public int ID { get; set; }
}
In my controller, I have an Edit actionresult that takes a parameter called 'id':
public ActionResult Edit(int id)
{
return View(new FooterLink() { ID = 5 }); //notice that I am explicitly setting the ID value here.
}
in my index view I have a link to the edit action that specifies the 'id' parameter:
<%= Html.ActionLink("Edit", "Edit", new { id = 1 })%>
In my view I have a couple of text boxes:
<%= Html.TextBox("ID", Model.ID)%>
<%= Html.TextBox("Blah", Model.ID) %>
which renders the following in HTML:
<input id="ID" name="ID" type="text" value="1">
<input id="Blah" name="Blah" type="text" value="5">
Notice that the input with an id of "ID" is getting its value not from the Model like I am telling it to...but from the parameter that was supplied to my ActionResult.
This behavior is the same with Html.TextBoxFor, Html.Hidden, Html.HiddenFor, etc.
What gives?
EDIT: I meant to update this a long time ago but never got around to it. The reason that this is happening is because the ModelState will have an "id" entry with the value of the "id" parameter in the method and the MVC ViewEngine first checks the ModelState when filling in Html helpers instead of the Model. In order to work around this, you can simply add the following line in your controller just before the return:
ModelState.Remove("id");
Now the <%= Html.TextBox("ID", Model.ID)%> will get the value from the Model and not the ModelState. Problem solved.
That's how html helpers work. They will first look if there's ID parameter in the request url and use that value instead of the one specified as second argument in the model.