Razor code like:
#Html.TextBoxFor(Model => Model.Name, new { #Value = student.t_Name })
and I using .NET MVC's model validation in Controller,
if (ModelState.IsValid)
{
return RedirectToAction("B");
}
else
{
return View(); // when validation failed
}
My situation is I have a edit function, for example:
original data:
birthday: 1992-05-26
after edited:
birthday: 1992-05-32
after I submit this to Controller and make model validation, it will validate fail, and return to previous view(the view before form submit),
I want it shows
birthday:1992-05-32
instead of
birthday:1992-05-26
You should set ViewModel values that come to your controller like this:
public ActionResult YourControllerMethod(YourViewModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("B");
}
else
{
ViewData.Model = model; //where model is your controller model
return View(); // when validation failed
}
}
You would need to pass the current posted model instance back to view when returning back View something like:
public ActionResult YourAction(SomeModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("B");
}
else
{
return View(model);
}
}
Related
This question already has answers here:
View not updating after post
(3 answers)
Closed 4 years ago.
I am doing something fundamentally wrong. I have created a simple example of my problem.
I have a simple class as follows:
public class Example
{
public string Text { get; set; }
}
I have created two methods on my controller
This is the view page you hit. It creates a new Example object.
public ActionResult Example()
{
var model = new Example {
Text = "test"
};
return View(model);
}
Then the post back when the form is submitted
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Example(Example model)
{
model.Text += "a";
return View(model);
}
The view is as follows:
#model Stackoverflow.Example
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h1>#Model.Text</h1>
#Html.EditorFor(model => model.Text);
<input type="submit" value="Save" />
}
When I first visit the page the heading and the text box have the same value
I press submit and the page loads again. The title has updated but the text box has the same value.
Why is the #Html.EditorFor(model => model.Text); not getting the updated value?
When you post a model back to an ActionResult and return the same View, the values for the model objects are contained in the ModelState. The ModelState is what contains information about valid/invalid fields as well as the actual POSTed values. If you want to update a model value, you can do one of the following two things:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Example(Example model)
{
ModelState.Clear();
model.Text += "a";
return View(model);
}
or
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Example(Example model)
{
var newValue = model.Text += "a";
ModelState["Text"].Value = new ValueProviderResult(newValue,newValue, CultureInfo.CurrentCulture)
return View(model);
}
You need to clear the model state on post method of controller
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Example(Example model)
{
ModelState.Clear();
model.Text += "a";
return View(model);
}
I have one problem.
This is short example.
This is model.
public class MyModel
{
string Title{get;set;}
}
In view I write
#Html.TextBoxFor(model => model.Title)
This is controller.
public ActionResult EditNews(int id)
{
var model = new MyModel;
MyModel.Title = "SomeTitle"
return View("News/Edit", model);
}
//for post
[HttpPost]
public ActionResult EditNews(MyModel model)
{
//There is problem.When I do postback and
// change Title in this place,Title doesn't change in view textbox
//Only when I reload page it change.
model.Title = "NEWTITLE"
return View("News/Edit", model);
}
It won't change because by default (many think this is a bug) MVC will ignore the changes you make to the model in a HttpPost when you're returning the same View. Instead, it looks in the ModelState for the value that was originally served to the view.
In order to prevent this, you need to clear the ModelState, which you can do at the top of your HttpPost by doing:
ModelState.Clear();
I have a problem with "return view()" that doesn't excute code in my controller.
I have a controller with this code:
public class BrokerController : BaseController
{
public ActionResult BestallMaklarBild()
{
return View(new BestallMaklarBildViewModel());
}
[HttpPost]
public ActionResult BestallMaklarBild(FormCollection collection)
{
try
{
//Some code
return View("MaklarBildBestalld",new MaklarBildBestalldViewModel());
}
catch
{
return View(new BestallMaklarBildViewModel());
}
}
public ActionResult MaklarBildBestalld()
{
//Some code
return View(new MaklarBildBestalldViewModel());
}
}
When I post to my controller "BestallMaklarBild" and then try to return the view("MaklarBildBestalld",new MaklarBildBestalldViewModel()), the code in "MaklarbildBestalld" doesn't execute. So when the model is returned to the view it doesn't contain any data, and cause my view leaving me with an error saying that the model.something = null when I try to output some data to the view.
Don't know what Im doing wrong.
That's normal. You need to redirect to this controller action if you want the code to execute:
try
{
//Some code
return RedirectToAction("MaklarBildBestalld", new { id = "some id" });
}
catch
{
return View(new BestallMaklarBildViewModel());
}
and now the action will execute:
public ActionResult MaklarBildBestalld(string id)
{
//Some code
return View(new MaklarBildBestalldViewModel());
}
Here's the correct workflow:
The BestallMaklarBild POST controller action is invoked and passed a view model
This controller action attempts to persist the model and redirects in case of success to the MaklarBildBestalld controller action passing it an unique identifier as query string of this model so that this action is able to retrieve the model back. In case of failure it simply redisplays the form so that the user can fix the errors he did, or see the error message that there was a problem processing his request.
You must ensure that your view has the model in your parameters as a generic type.
So I am having some trouble accessing my model errors within my Razor view.
In my controller, when either the ModelState is not valid or some other custom validation does not pass, I add model errors like this: ModelState.AddModelError("ModelState", "Please fill out all required fields.");
Then I return a redirect like so:
return RedirectToAction("Register", "Account");
Seems fairly simple, however, when I try and access the model state errors, loop through them, and add them each as a separate span to my view, I get nothing at all displayed. Here's the code in the view:
#foreach (var error in ViewData.ModelState.Values.SelectMany(modelState => modelState.Errors))
{
<span>#error.ErrorMessage</span>
<br />
}
Am I doing something wrong here, or not doing something I should be?
You should not redirect to action, just return same view:
///
/// Displays form to edit model
///
public ActionResult Edit(int id)
{
MyModelClass m = new MyModelClass();
return View(m);
}
[HttpPost]
public ActionResult Edit(MyModelClass m)
{
if( !ModelState.IsValid )
{
// Got error, return view
return View(m);
}
return RedirectToAction("/mymodel/success");
}
Updated: ModelState.IsValid - mistyped :)
Controller:
OnePersonAllInfoViewModel vModel = new OnePersonAllInfoViewModel();
vModel.PreferredContactType = new PreferredContactType();
ViewBag.PrefContactTypes = new SelectList(dbEntities.PreferredContactTypes
.OrderBy(pct => pct.PreferredContactTypeID),
"PreferredContactTypeID", "PreferredContactType1",
vModel.PreferredContactType.PreferredContactTypeID);
View:
<div class="editor-label">
#Html.LabelFor(model => model.PreferredContactType.PreferredContactTypex)
</div>
#Html.DropDownListFor(model => model.PreferredContactType.PreferredContactTypeID,
ViewBag.PrefContactTypes as SelectList)
And I get this error on post back... There is no ViewData item of type 'IEnumerable' that has the key 'PreferredContactType.PreferredContactTypeID'
Any thoughts? Thanks!
In your HttpPost controller action you must repopulate the ViewBag.PrefContactTypes property the same way you did in your GET action if you redisplay the same view:
[HttpPost]
public ActionResult Process(OnePersonAllInfoViewModel model)
{
ViewBag.PrefContactTypes = ...
return View(model);
}
Also you seem to have defined some class that is suffixed with ViewModel. This leaves the reader to believe that you are using view models in your application and in the very next line you use ViewBag. Why? Why not take full advantage of the view model and its strong typing?
Just like this:
public class OnePersonAllInfoViewModel
{
public int PreferredContactTypeID { get; set; }
public IEnumerable<PreferredContactType> PrefContactTypes { get; set; }
}
and then in your GET action:
public ActionResult Index()
{
var model = new OnePersonAllInfoViewModel();
model.PrefContactTypes = dbEntities
.PreferredContactTypes
.OrderBy(pct => pct.PreferredContactTypeID)
.ToList();
return View(model);
}
then the view:
#Html.DropDownListFor(
model => model.PreferredContactTypeID,
Model.PrefContactTypes
)
and the POST action:
[HttpPost]
public ActionResult Index(OnePersonAllInfoViewModel model)
{
if (!ModelState.IsValid)
{
// the model is invalid => we must redisplay the same view =>
// ensure that the PrefContactTypes property is populated
model.PrefContactTypes = dbEntities
.PreferredContactTypes
.OrderBy(pct => pct.PreferredContactTypeID)
.ToList();
return View(model);
}
// the model is valid => use the model.PreferredContactTypeID to do some
// processing and redirect
...
// Obviously if you need to stay on the same view then you must ensure that
// you have populated the PrefContactTypes property of your view model because
// the view requires it in order to successfully render the dropdown list.
// In this case you could simply move the code that populates this property
// outside of the if statement that tests the validity of the model
return RedirectToAction("Success");
}