I have this weird thing happening.
I have a PartialView with 3 fields on it. I do a jQuery ajax post to my action result and if the model passes validation i save the record. I also then set the model to empty and pass it back to the view as a partial view.
public ActionResult jQueryAddComment(Comment comment)
{
if (ModelState.IsValid)
{
//do stuff here
comment = new Comment();
}
return PartialView("AddNewComment", comment);
}
When I get back to the page my JS replaces the contents of the comments div with the html from the new partial view.
function submitComment() {
$.post('/Home/jQueryAddComment', { forumItemId: $('#id').val(), owner: $('#owner').val(), text: tinyMCE.get('text').getContent(), emailAddress: $('#emailAddress').val() }, function (result) {
alert(result);
$('.AddNewComment').html(result);
});
}
However, when the page renders the values are back in place. I can see that an empty model is being passed to the view so why are my previous values still there?
Even the alert shows the values in place even though I'm passing an empty object to the partial view in the controller.
edit
I should mention that I can't clear the fields within the JS of the page as I want to use the same code to render errors as well as successful requests.
Use ModelState.Clear() before returning the new blank model as a partial view, like:
if (ModelState.IsValid)
{
//your save logic
ModelState.Clear();
comment = new Comment();
}
return PartialView("AddNewComment", comment);
The standard HTML helpers look into ModelState and ViewData for values before using the values you passed to the helper.
This may help:
How to clear textboxes defined with MVC HTML helpers
Related
What is the most effective method in order to make all the fields on an MVC4 Razor empty when loading it (for example first loading or after backing to the page again)? If it is possible could you please suggest me a way with the help of Razor properties instead of using Javascript/jQuery.
It's a little difficult to make out what you're trying to do, but let's see if I can help.
Firstly, if you simply wanted to clear out a form's values after it's been posted, you can do that like so:
[HttpPost]
public ActionResult Index(ViewModel model)
{
ModelState.Clear();
model = new ViewModel();
return View(model);
}
Simply creating a new ViewModel isn't enough, as the ModelState dictionary will try to repopulate the form with the old values. This does what you want, but isn't really leveraging MVC to do what you want.
The better way to do it would be to redirect back to the action you use to display your form. Something like this:
public ActionResult Create()
{
var model = new ViewModel();
return View(model);
}
This is simply passing in an empty model to your form. Once the user fills out the form, and it's posted back to the server, you can handle it like so:
[HttpPost]
public ActionResult Create(ViewModel model)
{
if (ModelState.IsValid)
{
// Form data is valid so redirect back to display the form again
return RedirectToAction("Create");
}
// If we get here, redisplay the form with the fields filled in
// and errors shown
return View(model);
}
Simply calling a ModelState.Clear() will do the trick. You shouldn't have to instantiate the view model again.
A view displays (or collect) information about a Model.
So, if you pass an Empty model (that is: properties in null or blank or default values) it will "clear all fields".
All you have to do is invoking again the Action that displays the view, now passing an empty model.
EDIT:
You can do it in javascript, but then you have to duplicate and maintain the logic of what are default values.
I have the following model:
public class PersonListModel
{
....
[Required(ErrorMessage=AppConstants.MustSelectRecordToAttachMessage)]
public String SelectedPersonId { get; set; }
}
and the following view:
#using (Html.BeginForm("Attach", "Person", FormMethod.Post, new { #id = attachRecordFormId, targetDivId = personListId, #class = "inlineForm" }))
{
.....
#Html.HiddenFor(x => x.SelectedPersonId);
.....
<br />#Html.ValidationMessageFor(x => x.SelectedPersonId)
}
The hidden SelectedPersonId field is populated via some javascript hooked to the keyup event of one of the elements on my page.
My problem is that the required validation message shows immediately this partial view is displayed, not just when the form is submitted. It also displays again after the partial view is rendered again via an Ajax post.
I have very similar views that do not exhibit this problem, but 2 views (including the one above) that do exhibit this problem. I have been through a process of elimination to try to work out what is different between the views that work correctly and the 2 that exhibit this incorrect behavior, however I have not been able to locate the cause of the problem.
I presume that something is causing the unobtrusive validation to fire when the problem views are loaded. How can I track this down?
My problem is that the required validation message shows immediately this partial view is displayed
This could happen if the controller action that is displaying the view (containing the partial) takes the view model as argument:
public ActionResult Display(MyViewModel model)
{
... if this action is called with a GET request and you have missed
to pass a value for the "SelectedPersonId" query string parameter
you will get a validation error in the corresponding view
return View(model);
}
The reason for this happening is because your action is taking a model => the default model binder is kicking in attempting to populate your view model and when it attempts to set a value for the SelectedPersonId property it will automatically add a validation error to the model state if there's no corresponding value in the request because your model property is decorated with the [Required] attribute.
It also displays again after the partial view is rendered again via an Ajax post.
That's normal and could happen if the target POST action is taking your view model as argument and rendering a partial:
[HttpPost]
public ActionResult Process(MyViewModel model)
{
... if this action is called with a POST request and you have missed
to pass a value for the "SelectedPersonId" form parameter
you will get a validation error in the corresponding partial view
return PartialView(model);
}
I have a view with the following code:
#using (Html.BeginForm("GenerateQrCode", "QrCodeGenerator", FormMethod.Post ))
{
<input type="submit" value="Generate" />
}
It's just a submit button, which calls the code in my controller:
public void GenerateQrCode()
{
}
Is it possible for a method in my controller to return a value from the form, but without going to a different page? Because I notice that currently, on pressing the form button it tries to navigate to a non-existing 'GenerateQrCode' page (the same name as the controller method).
UPDATE:
Something I've tried is making the controller method return an ActionResult, and return a 'RedirectToAction', and simply calling the same view. However, I also had code in this method 'ViewBag.Message = "myMessage"; and then in my view I had the code '#ViewBag.Message', so I hoped that the view would update with the ViewBag message property, but it doesn't appear so.
The version of Html.BeginForm you're using tells the submit button to post to the GenerateQrCode action. Perhaps you could try another overload of Html.BeginForm that better suits your purposes?
Using javascript:
Handle the click event.
In the handler, prevent the default action and stop the event propagation.
Make and AJAX call to the server with the form data.
Get the response and take further actions.
So if I have this right, you want to submit an action without actually taking into account the response from the server. Sounds like you need jQuery post:
$.post(url, $("form selector").serialize(), function () {
// This is where you put a callback function.
});
That is all you need. This will post the data. What you can do is call this from a button click event instead of a form submit button. Or, you can override the submit event on the form and put this as your first line of code:
e.preventDefault();
where e is your event arguments. This will prevent the default action from occurring, which in this case is the submission of the form and the loading of the response.
The simplest method of doing this was simply to use the RedirectToAction method, specifying the name of the controller in the parameters. I also used the TempData variable to pass the results (in this case just a string value) back to the view, and into a ViewBag variable.
public ActionResult QrCodeGenerator()
{
ViewBag.Message = TempData["Message"];
return View();
}
public ActionResult GenerateQrCode()
{
TempData["Message"] = "myMessage";
return RedirectToAction("QrCodeGenerator");
}
I'm loading a partial view with an AJAX call:
public ActionResult LoadServerForm()
{
//data stuff
ViewData["ApplicationID"] = appID.ToString();
ViewData["Servers"] = ServersList(appServerRep.Session, null, appServers);
return PartialView("Application_AddServer");
}
This works great, but I'm trying to get away from magic ViewData strings. I tried making the partial view inherit from the same ViewModel as the "hosting" page, but the Model object is null when I try to this in the partial view:
<%= Html.HiddenFor(model=>model.Application_Key, Model.Application_Key) %>
Is there a way to pass the main page ViewModel down into the AJAX-loaded PartialView or should I be looking for a different approach altogether?
When you return PartialView("Application_AddServer");, you have to pass the model:
return PartialView("Application_AddServer", model);
Since this is an AJAX request, it's a separate controller action invocation, and the new PartialView doesn't know about the model of the requesting page. You'll have to reconstruct it, either from whatever your original data source is or from data passed with the AJAX request.
Is it possible to disable a certain action parameter from retaining its value across requests?
[HttpPost]
public ActionResult MyAction(string value1, string value2)
{
if(value1=="hi")
ModelState.AddModelError("value1", "Can't have hi");
//do stuff
if(ModelState.IsValid)
return RedirectToAction("Finish");
else
return View()
}
[HttpGet]
public ActionResult MyAction()
{
return View()
}
The view consists of a simple form with two input boxes (value1 and value2). Once submitted and validation fails, the view is returned. I want to always have the value of the textbox in the view to be empty.
The value for the textbox "value1" is retained if the the model is invalidated.
I tried to declare the textbox as <%= Html.TextBox("value1", null) %> but the value is still retained. I also tried to use [Bind(Exclude="value1")] but that dosen't work on a single variable.
Update 2:
I'm doing this for a textbox that is used for Captcha (custom solution) input. I want the textbox to be cleared any time the page is loaded, but I want validation to remain.
Try calling
ModelState["value1"].Value
= new ValueProviderResult(null, string.Empty, CultureInfo.InvariantCulture);
before you return the view from within your controller action.
What this does is keep all the errors associated with the key "value1", but replaces the value with an empty value.
What are you doing that's causing it to be retained? There isn't anything like ViewState in MVC that will persist a value over multiple requests unless you're writing code or using form fields to make it do so.
What does the view look like? Is this action method being called via GET or POST? What's the "do stuff" contained in your method?
Edit: You're still showing //do stuff in your example code. Does that stuff contain any references to ViewData? Your question is about binding, but I don't see any binding happening. Maybe this is beyond my understanding.
Edit 2: Glad Phil saw this one! The original question didn't mention the ModelState.