I have the following textbox on an MVC view:
#Html.TextBoxFor(x => x.Captcha, new { #value = "" })
I am trying the textbox to always be empty when the form show after being submited with errors ... But this is not working. I always see the last value.
And this is my controller:
[Route("signup"), HttpGet]
public virtual ActionResult SignUp() {
UserSignUpModel model = new UserSignUpModel();
model.Captcha = String.Empty;
model.Email = "";
return View(model);
} // SignUp
[Route("signup"), HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult SignUp(UserSignUpModel model) {
if (ModelState.IsValid) {
// Create account code
return View(MVC.Shared.Views._Note, new NoteModel("Account created"));
} else {
model.Captcha = String.Empty;
model.Email = "";
return View(Views.SignUp, model);
}
}
Thank You,
Miguel
If your form is submitted with errors, you can simply clear the ViewData and explicitly clear your property in the controller before returning the view with errors.
[HttpPost]
public ActionResult MyController(Model myModel)
{
if (!ModelState.IsValid)
{
myModel.Captcha = String.Empty;
ViewData = null;
return View(myModel);
}
return View(myModel);
}
I was able to solve this. The correct way is to use the model state:
ModelState["Captcha"].Value = new ValueProviderResult("", "", Thread.CurrentThread.CurrentCulture);
This way there is no need to clear other data in ViewData.
And by changing the ModelState, and not removing it, it becomes possible to still display the error associated with that property.
In your action method in your controller set this parameter manually:
// ...
model.Captcha = String.Empty;
return View(model);
And I recommend to add autocomplete=off html attribute to your captcha field:
#Html.TextBoxFor(x => x.Captcha, new { autocomplete = "off" })
Related
I am new to MVC. I am using a DropDownListFor to populate a number of Customer fields when a Company is selected. I am using the following code for the DropDownListFor:
#Html.DropDownListFor(model => model.CustomerId, new SelectList(ViewBag.Customers, "CustomerId", "Company"), "---Select one---", new { htmlAttributes = new { #class = "company" } });
#Html.HiddenFor(model => model.Company)
This code retrieves the Customer data:
[HttpPost]
public ActionResult GetCustomer(int custId)
{
var data = db.Customers.Find(custId);
return Json(data);
}
The relevant fields in the ViewModel (from the Customer table) are:
public int CustomerId { get; set; }
public string Company { get; set; }
The code in the Create method that creates the ViewBag:
public ActionResult Create()
{
QuoteViewModel qvm = new QuoteViewModel();
qvm.QuoteDetail = new List<QuoteDetail>();
var customers = db.Customers.ToList();
ViewBag.Customers = customers;
return View(qvm);
}
And here is the code for the POST:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(QuoteViewModel qvm)
{
if (ModelState.IsValid)
{
Quote quote1 = new Quote();
quote1.CustomerId = qvm.CustomerId;
...
db.Quotes.Add(quote1);
customer.CustomerId = qvm.CustomerId;
...
db.Entry(customer).State = EntityState.Modified;
bool saveFailed;
do
{
saveFailed = false;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
saveFailed = true;
var objContext = ((IObjectContextAdapter)db).ObjectContext;
// Get failed entry
var entry = ex.Entries.Single();
// Now call refresh on ObjectContext
objContext.Refresh(RefreshMode.ClientWins, entry.Entity);
}
} while (saveFailed);
return RedirectToAction("Index");
}
return View(qvm);
}
The population of the fields works fine, but when I attempt to Create the view model I get an error "Value cannot be null" on the DropDownListFor. I have researched others having this issue but cannot find an answer that applies to this case. Any help would be much appreciated.
The error is because in the POST method you return the view (ModelState is invalid), but have not set the value of ViewBag.Customers as you did in the GET method, so it null and you cannot create a SelectList from a null collection.
Your need assign ViewBag.Customers as you did in the GET method before your return View(qvm); statement.
As a side note, since you using a view model, that view model should contain a property (say) public IEnumerable<SelectListItem> CustomerList { get; set; } and you set that in the controller methods, and in the view
#Html.DropDownListFor(model => model.CustomerId, Model.CustomerList, "---Select one---", new { #class = "company" });
Are you making a full page POST request when a Company is selected?
If you are, you need to fill ViewBag.Customers because of ViewBag's lifetime.
http://www.dotnettricks.com/learn/mvc/viewdata-vs-viewbag-vs-tempdata-vs-session
(MVC)How to RedirectToAction and keep the content of a Html.Textbox in MVC4? This is my controller how do I fix it and what goes in the view?
[HttpPost]
public ActionResult Index(string ssn)
{
var exist = false;
var record = _db.Citations.Where(u => u.SSN == ssn).FirstOrDefault();
if (record != null)
{
exist = true;
return RedirectToAction("EditDetails", new { id = record.CitationID });
}
else
{
return RedirectToAction("Index", "SubmitAward", ssn); // wiped out ssn! I need to keep the ssn
// so that the user can fill out the form.
}
If your get action is like this:
public ActionResult Index(string ssn)
{
.........
..........
.........
}
then do like this:
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
but if it is the same index view of post action which is posted in question, you can pass the object back to view if your view is strongly typed to this class:
return View(record);
Try below code
return RedirectToAction("Index", "SubmitAward", new { ssn = ssn});
And your redirect action will be
public ActionResult Index(string ssn)
{
ViewBag.SSN=ssn;
return View(record);
}
And your view will contain textbox like
#Html.TextBox("SSN",ViewBag.SSN)
It may helps you..
I am using MVC4 Razor
Controller--
[HttpPost]
public ActionResult FillLogin(LoginModel model)
{
if (ModelState.IsValid)
{
if (model.username == "password")
{
string x = model.getdata();
model.field1= "Hello";
return View(model);
}
}
return View(model);
}
In view i am not getting the Data Displayed when i tried like
#Html.TextBoxFor(m => m.field1)
But working Fine if Given like
#if (Model != null )
{
#Html.TextBoxFor(m => m.field1)
}
Can anyone help me why this happens....I am new to MVC
Model should never be null. And I suspect that the problem is in the GET action not in the POST one. ALWAYS return a new instance of the model
public ActionResult FillLogin()
{
return View(new LoginModel());
}
I'd like show a form with some field (one in the example), submit it, save and display the same page with a reset of all fields. The probelm when I submit, I go the "Save" action but when I display the view the form is still filled in.
The model :
public class TestingModel
{
public string FirstName { get; set; }
}
The controller :
public class ChildController : Controller
{
public ActionResult Index()
{
TestingModel model = new TestingModel();
return View(model);
}
public ActionResult Save(TestingModel model)
{
Console.WriteLine(model.FirstName); //OK
//Save data to DB here ...
TestingModel testingModel = new TestingModel() { FirstName = string.Empty };
return View("Index", testingModel);
}
}
The view :
#using (Html.BeginForm("Save", "Child",FormMethod.Post))
{
#Html.TextBoxFor( m => m.FirstName)
<input type="submit" id="btSave" />
}
When Id debug to the view, in "Immediat window" Model.FirstName = "" but when the page is show I still have the value posted. I tried a ReditrectionToAction("Index") at the end of the Save method but same result.
Do you have an idea ?
Thanks,
If you want to do this you need to clear everything that's in the ModelState. Otherwise HTML helpers will completely ignore your model and use data from ModelState when binding their values.
Like this:
[HttpPost]
public ActionResult Save(TestingModel model)
{
//Save data to DB here ...
ModelState.Clear();
TestingModel testingModel = new TestingModel() { FirstName = string.Empty };
return View("Index", testingModel);
}
or simply redirect to the Index GET action in case of success:
[HttpPost]
public ActionResult Save(TestingModel model)
{
//Save data to DB here ...
return RedirectToAction("Index");
}
Try to return Index view without any model
return View("Index");
You should be posting your form back to the same ActionResult
public ActionResult Index()
{
TestingModel model = new TestingModel();
return View(model);
}
[HttpPost]
public ActionResult Index(TestingModel model)
{
Console.WriteLine(model.FirstName); //OK
//Save data to DB here ...
return RedirectToAction("Index");
}
You would be able to use the parameterless overload for BeginForm too
#using(Html.BeginForm())
{
//form
}
My idea is to pass a string data to a strongly-typed view as follows:
Controller:
public ActionResult Confirmation()
{
string message = TempData["message"] as string;
if (message != null)
return View(message);//it does not work
else
return RedirectToAction("Index");
}
View:
#Model System.String
#{
ViewBag.Title = "Confirmation";
}
<h2>
Confirmation</h2>
#Model
However, it does not work.
How to make it work?
EDIT 1
I can make it work by downcast message to object as follows:
return View((object)message);
I think MVC is getting slightly confused here. It won't work because it will try to return a ViewName of whatever you have in Message at the time.
There are at least three overloads you can use:
return View(string viewName);
// or..
return View(object model); // this is the one you're trying to use
// or..
return View(string viewName, object model);
MVC in your case is trying to do the first one but is using your variable Message as the view name. Try changing it to this to force it to use the correct overload:
return View("Confirmation", message);
.. and see what happens then.
Edit: Didn't realise you were not using the Index action; updated the example, but the point remains the same.
Why dont you try a ViewBag property to pass the string to the view or create a ViewModel with a string property:
public class ConfimationModel
{
public string Message{get;set;}
}
public ActionResult Confirmation()
{
string message = TempData["message"] as string;
//Model Option
var model = new ConfirmationModel();
model.Message = message;
if (message != null)
return View(model);
else
return RedirectToAction("Index");
//ViewBag Option
ViewBag.Message = message;
if (message != null)
return View();
else
return RedirectToAction("Index");
}
View:
#Model ConfimationModel
#{
ViewBag.Title = "Confirmation";
}
<h2>#Model.Message</h2>
OR
<h2>#ViewBag.Message</h2>