Model validation with Razor Pages - validation

I have a form that is at the bottom of the page.
When model validation failes on server side return Page() gets me back to the top of the page and that is very inconvenient because the user has to scroll down to the form to see the validation errors.
My questions are:
1. Can I redirect to contact form div ID?
2. The best scenario would be if model validation can be done asynchronously so there would be only partial page refresh. Is that possible? (that was done easily in Web Forms with UpdatePanel).
I appreciate any information you might share.
Jacob

First of all try to validate on the client first to prevent unnecessary postbacks. You can use attributes to set validation:
using System.ComponentModel.DataAnnotations;
public class ForgotPasswordViewModel()
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
In the view check the Modelstate:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
Of course client side isn't enough, so in case the client side validation is skipped the server makes sure that the model validates.
One way to scroll to a position is to use an anchor. The anchor is a client side way to bookmark parts in the document. Normally you would see something like this:
<a href"home#contact">Contact</a>
By clicking the link you would scroll to the contact bookmark in the home document. You can do the same for the post:
<div id="contact">
<form method="post" action="home#contact">
#Html.AntiForgeryToken()
</form>
</div>
In case of an error the page will automatically scroll to the form, since on the client the #contact hash was set. The assumption is that in case of success you redirect to another view. This is afaik the only way to scroll without the use of javascript. And since javascript validation didn't work...
Please note that with .Net Core AntiForgery is added automatically if you use the tag helper. But since I didn't use it I have to add this myself.
There are other options that involve javascript or some server side redirection, but I think this is an easy solution.
I do not know if partial page refresh is the best solution. I think it depends. There are plenty of examples available on how you can post asynchronous. Check this link: https://www.w3schools.com/jquery/ajax_ajax.asp

Maybe remote validation?
"Remote validation is a great feature to use when you need to validate data on the client against data on the server. For example, your app may need to verify whether an email or user name is already in use..."
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation

I have found solution that works fine for me:
#if (Model.validationError)
{
<text>
document.getElementById('contact').scrollIntoView();
</text>
}

Related

Clarification needed in using Ajax forms and Partial Page

I am newbie to MVC and Web App.
Recently I have went through the article
http://www.c-sharpcorner.com/UploadFile/pmfawas/Asp-Net-mvc-how-to-post-a-collection/
It uses the Ajax Form, to do the partial update towards a particular region alone..
But I have a doubt in that example...
I have seen the partial Page inside the Div with Id "AllTweets"....
<div id="AllTweets">
#Html.Partial("_AllTweets", Model) ***** (XXX)
</div>
And also in the controller action,
try
{
viewModel.Tweets.Add(viewModel.Tweet);
return PartialView("_AllTweets", viewModel); **** (YYYYY)
}
Now my question is,
They are returning the partial view along with the data from the action in the controller.
Whatever the data returned from the controller, the engine will place that data, inside the target div with id "AllTweets"...
But still, why I have to have the statement, #Html.Partial("_AllTweets", Model) inside the Div, since already I am returning the data from the controller...
And also in some of the examples, i have seen the same kind of the code..
But, even if I have removed the code "#Html.Partial("_AllTweets", Model)" inside the div, the code still works fine, and without any problem and i can able to post the data to the action in the controller.
I got totally stuck at this point.
May I kindly know, what is the reason behind it and why so.... So I can understand it more better.
Thanks in advance...
But, even if I have removed the code #Html.Partial("_AllTweets",
Model) inside the div, the code still works fine, and without any
problem and i can able to post the data to the action in the
controller.
Yes it will work fine. The Html.Partial("_AllTweets",Model) renders the partial with the specified model on every page load. After page is loaded, then ajax is used to fill the div with id AllTweets.
Html.Partial("_AllTweets",Model) is usefull when you want to display, for example, already saved tweets from your database to user when the page first loads. And then ajax takes care of later updates.

Update template inside a view rendered from another controller

I am looking for the way to refresh a template inside a view rendered from another controller than the template's controller, I mean:
I got two controllers AdminController & UserController. And two gsps /admin/listUsers & /user/_searchResult.
Then a want to render view listUsers who have inside the template _searchResult and all right.
Now, i want to refresh the template _searchResult, but cant find how. I tryed calling render(view:"/admin/listUsers", template:"/user/_searchResult", model:[searchResult:result])
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers(){
//...
}
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search(){
//search users for the givven params and send result by chain if there's an action or update a template if it's needed
//in my case this method need to update the template _searchResult
}
#Secured(['ROLE_ADMIN'])
def searchResult(){
//...
[searchResult:result]
}
listUsers.gsp
//...
<formRemote name="searchForm" url="[action:"search", controller:"user"]">
//Some fields for the search
//I need to place here some hidden inputs to send which
//template i want to update or action to redirect
</formRemote>
<g:render template="/user/_searchResult"/>
//...
_searchResult.gsp
//Just itterate and print the search result in a table
I hope I have explained the problem correctly, thanks!
I don't think I entirely understand your question, but I think the source of your confusion is that the way you are naming things doesn't follow regular conventions and you're not using the right tools for the job. Let me explain...
The methods on Controllers are called Actions. They send some data (the Model) to a View to be rendered into HTML. Views can be composed from smaller, reusable fragments called Templates. (sorry if I sound like I'm being condescending here, but I'm just trying to make sure we're all on the same page).
Now, what you've called templateA is actually a View, not a Template. You're correct that templateA (your View) can call templateB to render some markup, but then having the templateB try to call a method on another Controller doesn't make sense. That's not how things flow.
If you have some logic that needs to be executed after you've sent your Model to the View, you want to use a Tag Library (http://grails.org/doc/latest/guide/theWebLayer.html#taglibs).
To summarise, here's a quick recap.
A request should only call one Action, which sends the model to only one view.
If you need to reuse logic between Controllers, move that code to a Service.
If you need to reuse markup between Views, move that markup to a Template.
If you have logic that you want to have executed after you've sent the Model to the View, use a Tag Library.
Hopefully this will point you in the right direction.
--- UPDATE ---
OK, with the real code I can see better what you're trying to achieve. Firstly, as you're using the <g:formRemote> tag, you should have a good read of the docs at http://grails.org/doc/latest/ref/Tags/formRemote.html to understand what it does.
What you will have here is 2 separate requests. The first will be a regular page load by your browser, which is handled by the listUsers() action. Once the page is then finished loading, the user will enter a search term and hit the submit button. This will fire off a second ajax request, which will be handled by the search() action. This action could use the _searchResult.gsp template to render a HTML table to display the search results. When the browser get this, it will insert it into the DOM where you've told it to put it using the "update" attribute of the <g:formRemote> tag.
The important thing here is that from the server's perspective, these are 2 separate requests that are completely independent. They both first call an action, then send a model (a Map containing some data) to a view, which renders/merges the data with HTML and sends it back to the browser.
The difference between the 2 is that the first is a complete page load by the browser, whereas for the second request, the browser only loads a small chunk of HTML (the search results table) and updates the page content without reloading it.
So your code would look more like this...
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers() {
render(view:"/admin/listUsers")
}
listUsers.gsp
<g:formRemote name="searchForm" update="insertSearchResultsHere"
url="[controller: 'user', action:'search']">
<input name="searchTerm" type="text" />
</g:formRemote>
<div id="insertSearchResultsHere"></div>
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search() {
// use the search term to get a List<User>
render(template: "/user/searchResult", model: [users: users])
}
_searchResult.gsp
<table>
<g:each var="user" in="${users}">
%{-- Iterate through your search results --}%
</g:each>
</table>
I solved it by placing the attribute update and rendering the template alone:
gsp:
<formRemote name="searchForm" url="[action:"search", controller:"user"]" update="divToUpdate">
//Some fields for the search
</formRemote>
<div id="divToUpdate">
<g:render template="/user/_searchResult"/>
</div>
Controller:
def search(){
render(template:"/user/_searchResult", model:[searchResult:result])
}
When i asked this question, i was new on Grails community and i was confused with the use of remoteFunction and tags that use it like remoteForm. But i had this confusion because of i had not read the documentation. So in my case, the solution was search for documentation about how to use remote tags and render. Thanks to #AndrewW for show me the way.

MVC 3 post model and additional parameter to HttpPost action method using Ajax form

Using ASP.NET MVC 3 and Razor, I have a strongly typed view against MyViewModel class. Within the view I have an AJAX form that consists of a group of radio buttons. Below it, I have a normal HTML form that collects data for MyViewModel. Depending on which radio button is selected in the AJAX form, I want to update the HTML form with one set of default values or another. In the AJAX form, I'm trying to post two pieces of data: 1) a value that represents the option chosen (basedon the radio button value parameter), and 2) the Model from the view. I want the controller action to update the model based on the option received, and then return a partial view with the updated model object as parameter. How do I do this? Here's the code for the AJAX form for my attempt:
#using (Ajax.BeginForm("MyAction", "MyController",
new AjaxOptions {
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "createForm"
}))
{
<div id="formOptions">
#foreach (Option op in Model.GetOptions()) {
<div class="editor-field">
#Html.RadioButton("option", op.OptionType, false, new { #id = op.ID, #name = op.ID, #title = #op.Description, #onfocus = "javascript:$(this).closest('form').find(':submit').first().click()" })
<label for="#op.ID">#op.Name</label>
</div>
}
</div>
#Html.Hidden("model", Model)
<input type="submit" value="Select" style="display:none;" />
}
My problem is that the model parameter in the HttPost action method is null. However, the option parameter seems to get passed correctly. I'm not sure if I'm using the Html.Hidden input in a way it's not supposed to be used or what the problem is. I can post more code if needed.
This is my first attempt at doing something like this, so after reading a lot of (seemingly) similar questions I still cannot decipher the solution for what I want to do. I see a lot of different things, like JSON encoding, using JQuery, etc., but I'm not sure if I need those things, or if I can accomplish this using MVC features (I'd rather not recode things that are already built into MVC 3). If anyone can point me in the right direction or possibly give a little code example, it would be appreciated. And, given what my end goal is, if there's a better way to asynchronously update a form based on option controls, I'd be very interested to hear about it. Thanks!
EDIT:
I also noticed that the request using HttpPost does not make it to the controller, but a HttpGet does. Anyone out there? This is driving me nuts!
ADDED CONTROLLER METHOD:
public PartialViewResult CreateForm(OptionType opType, MyViewModel model) {
model.ApplyOptionValues(opType);
return PartialView("_CreateForm", model);
}
I would not post the entire model back to the controller which you are attempting to do with #Html.Hidden("model", Model) simply place the specific items you need in the form with names/types that match your controller. You can use the selected radio button's value as well as a hidden input's values to pass identifying information to the controller and perform whatever logic you need there.
That being said, I think the best solution going forward would be to use some javascript framework like JQuery to handle all AJAX requests. Asp.net MVC makes it really easy to do simple operations with the built in pieces, but once you need to perform more complicated operations, it definitely falls short. You end up putting in more effort to work within the limitations than if you just used the correct tool (JQuery).
Make sure that you annotate your POST action methods with [HttpPost] to differentiate from GET methods.
Also use a detailed web debugger to examine exactly what is being sent to your application. I like Fiddler, which is extremely popular.
http://www.fiddler2.com/fiddler2/
I would agree with Mattbo: posting the whole model round in a circle is unnecessary overhead. You don't say why you are but I suspect it's so you can compare 'old' and 'new' values. Given the model originates in the controller, you could include a unique identifier for the model (e.g. GUID) in the ViewModel, put that in a hidden field to include in your POST data, then on the return POST your 'new' data will be auto mapped to the strongly typed ViewModel. You can then re-get the original model and do whatever you need to with them both.
Dealing with the AJAX form is a separate issue/form then: you have your radio buttons which fill out default values in the (view model) form (including a hidden field to record which radio was selected), the user fills out the other data and the whole of the (non ajax) form gets posted to the MyController.MyAction method and the default binders will automatically map the form values to the MyViewModel, if they follow the right naming convention. So the AJAX has nothing to do with the form that is actually posted. Alternatively you could do the whole thing with AJAX as Mattbo also suggests.
[Aside] Forgive me if you already know but you can use the razor Html helpers to create your fields like:
#Html.EditorForModel()
#Html.EditorFor(model => model.[field name])
In the Controller you would create the actions like:
public ActionResult MyAction()
{
MyViewModel
}
[HttpPost]
public ActionResult MyAction(MyViewModel myModel)

How to prevent redirection on form submission in ASP.Net MVC 3, and just stay on the page?

I have two forms in one View. One of them does the job of uploading pictures to the database.
I need the whole page -and the data the user has typed into the "other form"- to remain untouched, meanwhile the user could also upload pictures. But it doesn't work.
The problem is that when the user submits the photos, the whole page changes. And worse than that, the new page only contains the "photo uploading" form !! Because upon Return View(); of the "upload pictures" Action method, it's View is rendered. :/
Look at the action method:
public ActionResult Upload(IEnumerable<HttpPostedFileBase> files)
{
//Upload the pictures .
return View();
}
Is it possible to achieve the result I need only by changing the return type of the Action method, (maybe ?) in order not to render anything and say just show a message to the user like "Files have been uploaded!" ??
Or should I use Ajax instead ?
Thanks for the advice, in advance ;)
You can't upload files using AJAX but you could use some third-party components that will upload files using hidden iframe which mimics like AJAX. You can google jquery ajax upload plugin.
For the other form you can use Ajax.BeginForm/PartialView to avoid complete refresh.
If the views are strongly typed against a model then you can always pass the model back to the user to "refill" the constant form (probably worst option). Another option (probably best) would be ajax of course.

View that hides/shows controls

I am in the process of porting a site I wrote from ASP.NET webforms to MVC3 and need some guidance as outlined below. I'm new to MVC3.
In my existing ASP.NET web forms project I have a simple page where the user enters a username, they then click a button which causes a postback, on postback there is some basic code that checks if the entered username exists in a user repository - if it does, a textbox containing the users e-mail is shown and the username textbox is made invisible. This happens with ajax and so when the username is entered, the textbox containing the e-mail along with an "Update" button is shown without a full page refresh.
I created a model such as:
public class ChangeEmailModel
{
[Required]
public string Username { get; set; }
[Required]
public string Email { get; set; }
}
Problem is that when the user first enters the page, they should only see a textbox prompting them to enter a username. Once the username is entered and an update button clicked, only then their e-mail is shown (retrieved from the database). Once the e-mail is shown, they can edit the e-mail and click update, which then will need to post to a controller action that saves the updated e-mail. I'm not yet fully used to thinking in the MVC way, so I'm not sure if I've started on the wrong foot with the model above...
Can someone give me some guidance on how this can be accomplished in MVC3 so I can give it a try?
I will start off by suggesting that you start using JQuery for your javascript/ajax functions. ASP.Net MVC3 supports JQuery nicely. I will ignore validation of the email for now as it will be much easier to get you started without it. A high level overview will be:
Add the JQuery script to your page
Add the JQuery vsdoc script to your page so you have some intellisense
Create a partial view to show the email and submit button
Create a controller action that performs the email lookup you mentioned
Create a div to accept the newly returned Email Update form
Use JQuery to override the submit on your username lookup to perform an ajax update instead (and populate the Email Update form div)
1. Add the JQuery script to your page
This should be pretty easy - just drag it from your scripts folder. I think mvc3 comes with jquery-1.5.1.js. Use the min (minified) version when you release to production.
2. Add the JQuery vsdoc script to your page so you have some intellisense
Not quite as easy here - you will want to use an if statement that always evaluates to false so the script is not actually included in your content. Having it on the page though, will cause VS to use it for intellisense. Put this near the top of your view:
#if (false) { <script src="../../Scripts/jquery-1.5.1-vsdoc.js" type="text/javascript"></script> }
Hopefully you are using Razor. If not, start using it. It seemed a little foreign to me at first, but it requires much less markup.
3. Create a partial view to show the email and submit button
You could use the ViewBag to pass the Email address and UserName (for now as we are ignoring validation), but go ahead and make it strongly typed to your Model from above. Your view may look something like this:
#model ChangeEmailModel
#{using (Html.BeginForm("UpdateEmail", "Home", FormMethod.Post, new { id = "UpdateEmailForm" }))
{
<input type="hidden" name="userName" value="#Model.UserName" />
#Html.EditorFor(m => m.Email)
<button id="submitEmailUpdate" type="submit">Submit</button>
}
}
Note that we have given Ids to the form and the submit button. JQuery will find the form and button based on these ids. (if we need to, which we will if we want to "ajaxify" the action of updating the email. I did not go into that detail here, but it will be the same process to get that working as it is for the original username lookup)
4. Create a controller action that performs the email lookup you mentioned
I won't go into controllers much here (as you are asking about ajax type updates) but it might look like:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LookupEmail(string userName)
{
//connect to db and lookup email based on passed in username
//create a new instance of your model
var changeEmailModel = new ChangeEmailModel(.....)
//return a partial view
return PartialView("EmailUpdateForm", changeEmailModel);
}
Make sure to return a PartialView here rather than a View.
5. Create a div to accept the newly returned Email Update form
Make sure this div is not contained in your Username lookup form (as you want to hide it). We will be working with two separate forms. This div could be hidden if you prefer (but will start out empty anyway) I am calling it emailFormDiv
6. Use JQuery to override the submit on your username lookup to perform an ajax update instead
JQuery will allow you to attach functions to... well a lot of things, but we will be using it to override the submit button on your username lookup form. Assume that your original username lookup form with an id of "formUserNameLookup" that has a submit button with an id of "submitUserNameLookup". You would then create a script tag that looks something like this:
<script type="text/javascript" language="javascript">
$(document).ready(function () { //The document.ready function will fire when the html document is... ready
$('#submitUserNameLookup').click(function (ev) { //fires when the submit button is clicked
ev.preventDefault(); //prevent the normal action of the button click
$.post($('#formUserNameLookup').attr('action'), //get the url from the form's action attribute. Could be hard coded for simplicity
$('#formUserNameLookup').serialize(), //serialize the data in the form
function (response, status) {
$('#emailFormDiv').html(response); //replace the html of your div with the response
$('#formUserNameLookup').hide(); //hide the original form
}, 'html'); //states that we are expecting html back from the post
});
});
</script>
The code above is attaching a function to be run when the submit button is clicked. It won't run, of course, until the button is actually clicked. Using JQuery/Javascript to attach functions to html elements, rather than embedding them directly inside the element is definitely preferred, and is referred to as unobtrusive javascript. If you continue with ajaxifying more of your page, you will want to look into JQuery's live and/or delegate functions. Note that there are plenty of things that can be changed once you start looking toward performance and/or best practices. The above should get you going though. I hope I haven't made too many assumptions on your current level of familiarity with ASP.Net MVC (like controllers and posting to controllers) but by all means, ask if you need further help.

Resources