I have a view as abcd.cshtml with below code
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.id)
#Html.HiddenFor(model => model.createtime)
<h3>Headline</h3>
<div class="editor-field">
#Html.EditorFor(model => model.general)
#Html.ValidationMessageFor(model => model.general)
</div>
<a class="anchor" id="keywords"></a>
<h3>Keywords</h3>
<div class="editor-field">
#Html.EditorFor(model => model.keywords)
#Html.ValidationMessageFor(model => model.keywords)
</div>
<a class="anchor" id="relatedcq"></a>
<h3>Related CQ</h3>
<div class="editor-field">
#Html.EditorFor(model => model.relatedcq)
#Html.ValidationMessageFor(model => model.relatedcq)
</div>
<p>
<input type="submit" value="Create" class="btn btn-primary" />
</p>
}
</div>
The controller is simple abcd.cs, I just put this into a DB
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(staging staging)
{
staging.modifiedby = User.Identity.Name;
staging.lastmodified = DateTime.Now;
staging.createtime = DateTime.Now;
try
{
db.stagings.Add(staging);
db.SaveChanges();
}
catch (InvalidOperationException e)
{
ViewData["error"] = "An error has occured: " + e.Message;
return View(staging);
}
return RedirectToAction("Details/" + staging.id);
}
What I want is to make sure that Keywords is filled. If Keywords is filled I need to have a pop up window saying "Please fill the Keywords".
I tried doing that using MessageBox.Show() but then for that I had to add System.Windows.Forms and that had some conflicts with System.Web.Mvc;
If you're using htmlhelper ValidationMessageFor would'nt you rather display a Validation Summary to the user the shows him/her all the fields that you require filled in?
e.g.
If you have a model and you have multiple fields that need to be filed in, which can be validated by decorating those fields/properties with the [Required] attribute, or any other that you see fit e.g. [StringLength] etc.
If you do that you can provide a validation summary, using the model binder to not post youre data if it doesnt meet the set validation.
Validation summary example:
#Html.ValidationSummary(false, "Please provide the details above and then click submit.")
That above will display all the validation errors of all fields marked with the following e.g. #Html.ValidationMessageFor(model => model.relatedcq)
Image of how the output, if there are validation errors, will be displayed.
Hope this helps :)
To achieve this you need to create a custom validation attribute on server side. So for e.g. Let's name it as MustBeFilled. Your new attribute would look like:
public class MustBeFilledAttribute : ValidationAttribute, IClientValidatable // IClientValidatable for client side Validation
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
{
return new ValidationResult(FormatErrorMessage(null));
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var modelClientValidationRule = new ModelClientValidationRule
{
ValidationType = "mustbefilled",
ErrorMessage = ErrorMessage //Added
};
modelClientValidationRule.ValidationParameters.Add("param", metadata.DisplayName); //Added
return new List<ModelClientValidationRule> { modelClientValidationRule };
}
}
Now you would need a client side script as well to take action if the rule fails. As in your case you want to show a popup. Add below to your site script and make sure it renders after the Jquery-validation-* scripts are rendered.
(function ($) {
$.validator.addMethod('mustbefilled', function (value, element, params) {
if ($(element).val() != '')
return true;
alert('Fill it first.');
// Here you need to Invoke the modal popup.
return false;
}, '');
$.validator.unobtrusive.adapters.add('mustbefilled', ['param'], function (options) {
options.rules["mustbefilled"] = '#' + options.params.requiredif;
options.messages['mustbefilled'] = options.message;
});
})(jQuery);
To apply this custom validation, first add the attribute on your Model property.
[MustBeFilled]
public string Keywords { get; set; }
Then add the custom javascript to bundle.config, only if you have kept the code in separate file named mustbefilled.js. Here I intentionally added the javascript file with validation plugin so you don't get exception if it rendered before the validation plugin.
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*",
"~/Scripts/mustbefilled.js"));
That's it you're all set.
Now all you have to do is create a model pop and call it in the mustbefilled.js where I placed the comment to invoke it. See this sample here which would help you create a bound modal popup to your keywords property.
Related
How to change the language for "The value 'some value' is not valid for 'some property'" validation error?
Can anyone help? I want to translate the error in the picture to Russian Error. I read much sites, try to use RegularExpression, but it doesn't help
may be I don't correctly understand how to do that?
I need only translate the error, not need to change the culture.
In web.config:
<globalization culture="en" uiCulture="en" />
My entity with data annotations attributes:
public class Player
{
/* Some other properties */
[Required(ErrorMessage = "Укажите среднее количество блокшотов")]
[Range(0, 10.0, ErrorMessage = "Недопустимое значение, до 10")]
public float BlockPerGame { get; set; }
/* Some other properties */
}
My View:
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.Id)
<div class="box-form">
/* Some other properties */
<div class="text-style-roboto form-group">
<label>Среднее количество блокшотов</label>
#Html.TextBoxFor(m => m.BlockPerGame, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.BlockPerGame)
</div>
/* Some other properties */
<div class="form-group">
<button type="submit" class="button button-create" id="button-create">Добавить</button>
#Html.ActionLink("Отмена", "Index", null, new { #class = "button button-cancel", id = "button-cancel" })
</div>
</div>
}
And my Controller:
public class AdminController : Controller
{
/*Some other methods*/
[HttpPost]
public async Task<ActionResult> Edit(Player player, string ChoosingTeam)
{
if (ModelState.IsValid)
{
if (ChoosingTeam != string.Empty)
{
try
{
player.TeamId = int.Parse(ChoosingTeam);
await repository.SavePlayerAsync(player);
TempData["message"] = string.Format("Игрок {0} {1} сохранены", player.Name, player.Surname);
return RedirectToAction("Index");
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
}
IEnumerable<SelectListItem> list = new SelectList(repository.Teams, "Id ", "Name");
ViewBag.ChoosingTeamName = list;
return View(player);
}
}
When you enter an invalid value for a property, if model binder cannot bind that value to the property, the model binder sets an error message for that property. It's different from data-annotations model validation. It's in fact model binder validation error.
Localizing or Changing Default Model Binding Error Messages
Model binding error messages are different from model validation messages. To customize or localize them, you need to create a global resource and register it in Application_Start for DefaultModelBinder.ResourceClassKey.
To do so, follow these steps:
Go to Solution Explorer
Right click on project → Add → ASP.NET Folder → Choose App_GlobalResources
Right click on App_GlobalResources → Choose Add New Item
Choose Resource File and set the name to ErrorMessages.resx
In the resource fields, add the following keys and values and save the file:
PropertyValueInvalid: The value '{0}' is not valid for {1}.
PropertyValueRequired: A value is required.
Note: If you want to just customize the messages, you don't need any language-specific resource, just write custom messages in the ErrorMessages.resx and skip next step.
If you want localization, for each culture, copy the resource file and paste it in the same folder and rename it to ErrorMessages.xx-XX.resx. Instead of xx-XX use the culture identifier, for example fa-IR for Persian language
and enter translation for those messages, for example for ErrorMessages.fa-IR.resx:
PropertyValueInvalid: مقدار '{0}' برای '{1}' معتبر نمی باشد.
PropertyValueRequired: وارد کردن مقدار الزامی است.
Open Global.asax and in Application_Start, paste the code:
DefaultModelBinder.ResourceClassKey = "ErrorMessages";
ASP.NET CORE
For ASP.NET Core read this post: ASP.NET Core Model Binding Error Messages Localization.
Imagine a simple form that takes an email input like this:
#using (Html.BeginForm("save", "email", FormMethod.Post, new { #id = "my__form" }))
{
<div class="field">
#Html.LabelFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
#Html.TextBoxFor(model => model.Email, new { #placeholder = "Enter your email", #type = "email" })
</div>
<button type="submit" class="btn">Save email</button>
<div class='spinner'></div>
}
The spinner is not displayed initially (CSS):
.spinner {
display: none;
}
On form submit I show a spinner on the page:
$('.btn').on("click", function (event) {
event.preventDefault();
$('#my__form').submit();
$('.spinner').show();
});
My action is as follows:
[HttpPost]
[Route("email")]
public ActionResult Save(EmailViewModel model)
{
if (ModelState.IsValid)
{
//Do stuff with email
return RedirectToAction("action", "contoller");
}
return View(model);
}
Think of the above as pseudo-code that represents a more generic issue.
If a model state is invalid and the UI is updated in some way (in this case showing a spinner), what's the pattern or mechanism to reset the form?
For clarity, I am not talking here about standard data validation etc. I've tried having a hidden input on the form that I can populate using ModelState.AddModelError("spinner", false) and then acts as a 'switch' that javascript can read and then hide the spinner. This feels like a hack.
It feels like this is a common problem to which there is a common solution?
The hack you mentioned is really how it would be done using normal ASP.NET MVC.
There can be different implementations, such as storing the flag in a ViewBag instead. But the idea is the same.
You might be better off posting the form via AJAX, whose result might include a success flag and/or a list of validation errors. You can then manipulate the DOM in the submit handler via JavaScript based on this result.
So I have file uploading input which is strongly typed and below is the model class
public class UploadImageAlbum
{
[CustomFileValidator]
public HttpPostedFileBase Images { get; set; }
}
and my CustomFileValidator class is as below:
[AttributeUsage(AttributeTargets.Property,AllowMultiple =true,Inherited =false)]
public class CustomFileValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext context)
{
const int maxContent = 1024 * 1024 * 50;//50 MB
var sAllowedExt = new string[] { ".jpg", ".png" };
var file = value as HttpPostedFileBase;
//Check for null
if (file == null)
{
return new ValidationResult("Please select an image to upload");
}
//Check for File Extension
if (sAllowedExt.ToList().Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
{
return new ValidationResult("Please Upload a valid file of type : " + string.Join(",", sAllowedExt));
}
//Check for length of file
if(file.ContentLength>maxContent)
{
return new ValidationResult("File is too large, maximum allowed size is :" + (maxContent / 1024) + "MB");
}
return ValidationResult.Success;
}
}
and my partialview is as below:
#using (Html.BeginForm("UploadImages", "Admin", FormMethod.Post, htmlAttributes: new { id = "frmUploadImages", novalidate = "novalidate", autocomplete = "off", enctype = "multipart/form-data" }))
{
<div class="form-group">
<span class="btn btn-default btn-file-img">
Browse #Html.TextBoxFor(m => m.UIAModel.Images, new { type = "file", multiple = "multiple", data_charset = "file" })
</span>
<span class="text-muted" id="filePlaceHolder">No files selected</span>
#Html.ValidationMessageFor(m=>m.UIAModel.Images, null, htmlAttributes: new { #class = "invalid" })
</div>
<div class="form-group">
<button class="btn btn-primary addImage pull-right">
<i class="fa fa-upload"></i> Upload
</button>
</div>
}
and below is how I load partialview on click of a link:
$('#page-inner').empty().load('/Admin/GetMediaUploadView', function () {
$.validator.unobtrusive.parse($('form#frmUploadImages'));
//Apply client validation for partialviews
})
But even after following all the steps, it isn't displaying any message and point to note is, if I add [Required] attribute for the same, it will work well, but custom validation what I have never displays any message. What else I have to add to make this CustomValidator to work? I followed this post but still could not be of much help. Also if anyone let me know how to update this model so as to accept multiple images, it will be of great help.
In order to get client side validation, your attribute must
implement IClientValidatable which will add the associated
data-val-* attributes to you html, and
you must include scripts to add methods to the jQuery validator.
This article is a good guide to creating custom client and server side validation attributes.
Note also your current attribute is rather limited in that the file types and size are fixed, and it would be more flexible to include properties to specify the file types and maximum file size so that you could use it as (say)
[FileValidation(MaxSize="1024", FileType="jpg|png")]
public HttpPostedFileBase Images { get; set; }
This article provide an example of an attribute that validates the file type, but could be adapted to include the MaxSize property.
Side note: If your loading dynamic content, then you should first set the validator to null
var form = $('form#frmUploadImages');
form.data('validator', null);
$.validator.unobtrusive.parse(form);
I have read many posts on this subject matter, but I am still battling with my issue. I have a form that has a 14 properties and 5 complex types with custom template editors. Client side validation works for all properties and custom template editors, but the property below. If I enter text, it erases the entire contents of the text box with no message. However if I enter 2., I receive the error message saying it must be an number. Has anyone experienced this behavior? This happens on a few of my other forms as well.
As a side note: Should client side validate the nullable int range? Seems like it does not unless I add a range validator. Thank you.
UPDATE
This is actually happening for all my int? properties
Model
[Display(Name = "Lifetime")]
public int? Life { get; set; }
View
#using (Html.BeginForm("EditPerson", "Maintenance", FormMethod.Post, new { #class = "operation-form" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.PersonId)
#Html.Hidden("ModifiedBy", User.Identity.Name)
<div class="form-horizontal">
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
<div class="col-md-4">
<div class="row person-field">
<div class="col-md-6 field-name">
#Html.LabelFor(model => model.Life)
</div>
<div class="col-md-6">
#Html.EditorFor(model => model.Life, new { htmlAttributes = new { #class = "to-center routebox" } })
#Html.ValidationMessageFor(model => model.Life, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
If your using a modern browser, the problem may be the use of #Html.EditorFor() By default this will add type="number" to the input and as a result will generate the browsers implementation of a number control. I have only tested this using Chrome, but it appears that if you enter text that not a valid number, the the browser intercepts it and prevents the value attribute being set. Now when you post back, Life is null and therefore valid and when you return the view, the ModelState value is null explaining why it appears to "erase the entire contents of the text box with no message".
You can test this by changing it to #Html.TextBoxFor(m => m.Life) which will render type="text". Now when you enter text and try to submit, unobtrusive validation will prevent submission and display "The field Life must be a number". As for validating the range, if you do not add an appropriate attribute to the property (e.g [Range(0, int.MaxValue)]) then there is nothing for jquery.validate.unobtrusive to test so it posts back, however its validated on the server and when you return the view, a validation error will be displayed such as "The value '999999999999999999999999999999999999999999' is invalid".
Once I figured out that int? was the problem, I found a solution here:
Nullable int validation not showing message for non-numeric values
All I did was add the data type annotation to all int?. Not sure why this works yet.
[Display(Name = "Lifetime")]
[DataType(DataType.Text)]
public int? Life { get; set; }
There are such options:
Use [Range(0, int.MaxValue)]
Use [RegularExpression("([0-9]+)")]
Use [Integer] from DataAnnotationExtensions
Use your own custom ValidationAttribute with registering on client-side
I have created a custom html helper in MVC for MailTo functionality.
But I got an requirement to set the subject of the mail to the value user have entered in another textbox field.
I am not sure how to achieve this, Can some body please help?
Thanks
Html Helper
public static MvcHtmlString SendMailTo(this HtmlHelper helper, string emailAddress, string subject, string displayText)
{
var sb = string.Format("{3}",
CharEncode("mailto:"), CharEncode(emailAddress),CharEncode("?subject=" +subject), CharEncode(displayText));
return new MvcHtmlString(sb);
}
public static string CharEncode(string value)
{
var enc = System.Text.Encoding.Default;
var retval = "";
for (var i = 0; i < value.Length; i++)
{
retval += "&#" + enc.GetBytes(new[] { Convert.ToChar(value.Substring(i, 1)) })[0] + ";";
}
return retval;
}
View:
<div class="form-group">
#Html.LabelFor(m => m.ApplicationId, new { #class = "col-sm-3 control-label" })
<div class="col-sm-8">
#Html.TextBoxFor(m => m.ApplicationId, new {#class = "form-control"})
</div>
</div>
<div class="form-group">
<div class="col-sm-11" style="text-align:right">
#Html.SendMailTo("info#test.com", "Password Request: ", "Request Password")
<button type="submit" class="button">Sign in</button>
</div>
</div>
You can not get that value without any jquery code.
You should make an event on keyup ( for example ) on your texbox ( this is the one which is used as an user mail input )
Put your email form in a partial view and update that partial when that event is triggered.
INFO :
A) To render your ParialView use can Html.Partial helper -> Example here
B) To get textbox value you can use following jquery code
`$('.class of your textbox').val()' //will return a string
C) To update your partial view
c.1 Place your partial view in a `div element`
c.2 Make an `ajax` call from `jquery` to an action which returns your partial view filled with data
Example for c.2:
*AJAX*
$.ajax({
type:"GET",
data:{
mail:$('.class of your textbox').val()
},
success: function(response){
$(".class of your div").html(response.Html);
}
error: function(response){
// whatever you want to do
}
});
*Controller Action*
public JsonResult(string mail)
{
var model = new CustomModel(){ Mail=mail }; // custom class to your as model for your partial view
var html = RenderPartial(...) // method you can find in the link posted below
return Json(
{
Html=html
},JsonRequestBehavior.AllowGet)
}
Link I was writing about few lines above - follow this link
You can call that ajax on whatever event you want for your textbox.