I added ValidationSummary Html helper for my View Model class which has 5 required fields. And it works got nice red words missing 1, missing 2 etc.
But I need to display just one message not five of them (something like: "Your input is not valid."). Can this be done with ValidationSummary?
You have two options (at least):
Either use the validation summary and exclude property errors:
#Html.ValidationSummary(true, "The input is not valid")
or associate a error message with a custom key in your action:
if (!ModelState.IsValid)
{
ModelState.AddModelError("myerrorsummary", "The input is not valid");
}
and display it on your page:
#Html.ValidationMessage("myerrorsummary")
You can try skipping the helpers if all you want to do is simply display a message if the ModelState is not valid. Simply check the ModelState within ViewData and that should work.
#if (!ViewData.ModelState.IsValid)
{
<p>Your input is not valid.</p>
}
If you look at MVC3 source code you'll see that, currently, if you use ValidationSummary with excludePropertyErrors=true while having UnobtrusiveJavaScriptEnabled, there won't be any validation summary rendered.
I was able to display just a single message with MVC3 with UnobtrusiveJavascript enabled, for client side validation. Don't use #Html.ValidationSummary at all, and render:
#{
//Show the message when there are server side errors
ViewBag.ValidationSummaryClass = ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors";
}
<div class="#ViewBag.ValidationSummaryClass" data-valmsg-summary="true">
<span>Before you can continue, please make sure you have completed the mandatory fields highlighted above.</span>
<ul style="display:none"/>
</div>
Notice the display:none, unobtrusive javascript still fills the list with error messages, but they are kept hidden.
One brute force approach I've used in MVC3:
if (!ModelState.IsValid)
{
ModelState.AddModelError("", "Some contextual error message");
}
and display it on your page:
<% if(!ViewData.ModelState.IsValid) { %>
<span class="error"><%=ViewData.ModelState[String.Empty].Errors[0].ErrorMessage %> </span>
<% } %>
Related
I want to send a message to userID=3 by going to /MyController/Message/3
This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.
At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.
Why is text area value not updated to empty string after post action?
Here are the actions:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
ViewData["ID"] = ID;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
// set the value of SomeText to empty and return to view
ViewData["SomeText"] = string.Empty;
return View();
}
And the corresponding view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("ID", ViewData["ID"])%>
<label for="SomeText">SomeText:</label>
<%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
The problem is that your ModelState is re-filled with the posted values.
What you can do is clear it on the Action that has the Post attribute :
ModelState.Clear();
The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
TempData["message"] = "Message sent";
return RedirectToAction("Message");
}
This seems to me like more correct behaviour.
The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.
But if you add this line after SaveToDB(ID, SomeText), it should work :
ModelState["SomeText"].Value =
new ValueProviderResult("", "", CultureInfo.CurrentCulture);
I tried everything, but only worked when I did something like this:
ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));
Hope this helps.
Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions.
They are designed to take the Value from ModelState instead of the Model (or viewdata).
That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:
<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>
I don't use Javascript anymore, but I believe in regular JS that it is like:
document.getElementById("SomeText").value = "";
(You would do this on one of the load events.
<body onload="...">
Hope this helps.
I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.
Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.
EDIT:
I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.
Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
if (modelState.Errors.Count > 0) {
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
// The first newline is always trimmed when a TextArea is rendered, so we add an extra one
// in case the value being rendered is something like "\r\nHello".
// The attempted value receives precedence over the explicitly supplied value parameter.
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
return tagBuilder.ToString(TagRenderMode.Normal);
Do s.th. like this:
add:
ModelState.Clear();
before the return statement of the submit buttons action method. Works for me. It could work for you.
I am using the code from the below link. It works fine . But though there are validation errors, and ValidationSummary(true/false) is enabled, I am not able to see the validation message.
ASP.NET MVC Partial view ajax post?
As a work around ,When I try to display error message explicitly using the below code, it still does not display .When in debug mode, the ModelState has the error message , but it does not display .
<div>
#{
foreach (var i in ViewData.ModelState.Values)
{
<ol>
#{
if(i.Errors != null && i.Errors.Count>0)
{
var error = i.Errors[0];
<li>error.ErrorMessage</li>
}
}
</ol>
}
}
</div>
Please help.
You can use #Html.ValidationMessage html helper to display property-level validation message in your partial view.
the source of LoginRegister view is like this :
#Html.Partial("authentication/_login")
#Html.Partial("authentication/_register")
and each child view has got a form with this syntax
#using (Html.BeginForm(**seperated-methods**, "Login"))
{
#Html.ValidationSummary(false)
}
I send error(s) in postback whit this code
ModelState.AddModelError("", "**any-error-message**");
return View("authentication/LoginRegister", customized-data);
The point is , error message shows in both partial views.
You need to tell the ModelState to which property this error refer to:
ModelState.AddModelError("PropertyName", "**any-error-message**");
Now it will be only in the
#Html.ValidationMessageFor(m => m.PropertyName)
If you don't specify the property name, the error will be considered global and get shown in every ValidationSummary.
Is there a function for ASP.NET MVC 2 built in data annotation javascript validation that performs the functionality of Jquery.Validate's isValid()?
I'd like to check if my fields are valid prior to using jquery ajax to send data to the server? Any suggestions?
Thank You.
i used the :
http://geekswithblogs.net/stun/archive/2010/02/27/asp.net-mvc-client-side-validation-summary-with-jquery-validation-plugin.aspx
and it worked great for me,
especially you don't need to change the original Mvc Validation way(I mean the validation field), you just make it client side
As basilmir and Dom Ribaut implies you should get this automatically if you EnableClientValidation(). However if you want to manually call client side MVC validation you can use:
if (!Sys.Mvc.FormContext.getValidationForForm($("#myform").get(0)).validate('submit').length) {
// is valid
}
You can replace $("#myform").get(0) with the DOM element for your form.
Seems that there is nothing special in MicrosoftMvcJQueryValidation.js except for registration of rules for jquery.validate.js plugin.
This worked for me:
<script type="text/javascript">
function validateForm(formId)
{
var valid = $("#" + formId).validate().form();
return valid;
}
</script>
Scott Guh describe simple js validation step by step in this post: http://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx (look for step3).
It is not JQuery but wouldn't that fit your needs?
--
Dom
Have a look at xval. It lets you define your validation rules either using data annotation attributes or castle validation attributes (I think nhibernate validation has also been added recently). Validation is then converted to client validation rules and you can validate a form using ajax so no postback to the server.
From the project page: xVal is a validation framework for ASP.NET MVC applications. It makes it easy to link up your choice of server-side validation mechanism with your choice of client-side validation library, neatly fitting both into ASP.NET MVC architecture and conventions.
If you are only after validation mechanisms for asp.net mvc then have a look at this and this
Jquery will be your best friend
check this http://bassistance.de/jquery-plugins/jquery-plugin-validation/
document link:http://docs.jquery.com/Plugins/Validation
You can enable client-side validation via <% Html.EnableClientValidation(); %>
It will automatically generate all the javascript code you need to the server-side validation to work on the client-side. Remember to still check on the server-side, since the client can bypass javascript and send bad data. Do not use client-side validation only.
<% Html.EnableClientValidation(); %>
<%= Html.ValidationSummary() %>
<% using (Html.BeginForm()) {%>
<%=Html.EditorForModel() %>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
here is a simple program will guide how to do client side validation of Form in JavaScript.
Name : <asp:TextBox ID="txtName" />
Email : <asp:TextBox ID="txtEmail" />
Web URL : <asp:TextBox ID="txtWebUrl" />
Zip : <asp:TextBox ID="txtZip" />
<asp:Button ID="btnSubmit" OnClientClick=" return validate()" runat="server" Text="Submit" />
Now on the source code of this form in script tag write the following code:
<script language="javascript" type="text/javascript">
function validate()
{
if (document.getElementById("<%=txtName.ClientID%>").value=="")
{
alert("Name Feild can not be blank");
document.getElementById("<%=txtName.ClientID%>").focus();
return false;
}
if(document.getElementById("<%=txtEmail.ClientID %>").value=="")
{
alert("Email id can not be blank");
document.getElementById("<%=txtEmail.ClientID %>").focus();
return false;
}
var emailPat = /^(\".*\"|[A-Za-z]\w*)#(\[\d{1,3}(\.\d{1,3}){3}]|[A-Za-z]\w*(\.[A-Za-z]\w*)+)$/;
var emailid=document.getElementById("<%=txtEmail.ClientID %>").value;
var matchArray = emailid.match(emailPat);
if (matchArray == null)
{
alert("Your email address seems incorrect. Please try again.");
document.getElementById("<%=txtEmail.ClientID %>").focus();
return false;
}
if(document.getElementById("<%=txtWebURL.ClientID %>").value=="")
{
alert("Web URL can not be blank");
document.getElementById("<%=txtWebURL.ClientID %>").value="http://"
document.getElementById("<%=txtWebURL.ClientID %>").focus();
return false;
}
var Url="^[A-Za-z]+://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+$"
var tempURL=document.getElementById("<%=txtWebURL.ClientID%>").value;
var matchURL=tempURL.match(Url);
if(matchURL==null)
{
alert("Web URL does not look valid");
document.getElementById("<%=txtWebURL.ClientID %>").focus();
return false;
}
if (document.getElementById("<%=txtZIP.ClientID%>").value=="")
{
alert("Zip Code is not valid");
document.getElementById("<%=txtZIP.ClientID%>").focus();
return false;
}
var digits="0123456789";
var temp;
for (var i=0;i<document.getElementById("<%=txtZIP.ClientID %>").value.length;i++)
{
temp=document.getElementById("<%=txtZIP.ClientID%>").value.substring(i,i+1);
if (digits.indexOf(temp)==-1)
{
alert("Please enter correct zip code");
document.getElementById("<%=txtZIP.ClientID%>").focus();
return false;
}
}
return true;
}
</script>
And in code behind file just write the below code.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
btnSubmit.Attributes.Add("onclick", "return validate()")
End Sub
Now you will get a form with proper validation.
I hope this is going to help you
I just started playing with MVC and I've run into a roadblock. I'm using a partial view as a User Login flyout on the header of each page using OpenID. When the user clicks on the provider (similar to stackoverflow) it authenticates and then either returns to the calling page or redirects to the signup page. The code works flawlessly under Firefox and Chrome but bombs out in IE. The "provider" parameter in the controller is always sent as null. Is there some sort of bug involving posting input names/values in IE or am I doing something wrong?
This is what my openid partial view looks like:
<% using (Html.BeginForm("Authenticate", "Membership", new { ReturnUrl = Request.Url }, FormMethod.Post))
{
if (!Page.User.Identity.IsAuthenticated)
{ %>
<div class="openidProviders">
Log in or join using one of these OpenID providers:
<div class="large buttons">
<div class="provider"><div><%= Html.SubmitImage("provider", "/Content/common/images/google.gif", new { value = "Google" })%></div></div>
<div class="provider"><div><%= Html.SubmitImage("provider", "/Content/common/images/Yahoo.gif", new { value = "Yahoo" })%></div></div>
<div class="provider"><div><%= Html.SubmitImage("provider", "/Content/common/images/AOL.gif", new { value = "AOL" })%></div></div>
<div class="provider"><div><%= Html.SubmitImage("provider", "/Content/common/images/OpenId.gif", new { value = "OpenId" })%></div></div>
</div>
</div>
<% }
}
%>
And the controller logic is here:
[AcceptVerbs(HttpVerbs.Post), ValidateInput(false)]
public void Authenticate(string provider, string ReturnUrl)
{
// Figure out provider endpoint
// Authentication function calls here
}
Well, it looks like IE, for once, is the only browser properly following the HTML spec according to this post.
The HTML specification only requires
that x, y coordinates where the image
submit button was clicked be sent to
the web server. IE follows the
specification. The browsers that send
the value="..." parameter are doing
their own thing outside of the HTML
specification.
Basically, I need to use a submit input instead of SubmitImage and then style the background of the button accordingly. Not the optimal solution but at least it works. This is what the final solution looks like. If anyone knows a way of getting the SubmitImage to work properly, let me know.
Replace the buttons above with ones that look like this:
<input type="submit" value="Google" class="google_OpenID" name="provider" />
And the CSS class:
.google_OpenID
{
background-image: url(/Content/common/images/google.gif);
width:75px;
cursor:pointer;
color:transparent;
height:35px;
border:none;
}