I am currently building a ASP.NET C# form. This form had many fields and many validations.
Which included:
Validate when the required checkbox is checked
Validate a dynamic form (e.g. additional address form generate dynamically when add address button click)
At first, I was planning to use ASP.NET form control to create all the fields and validations. But later on I found there is a plugin call jqueryvalidation, which simply provided what I need through Jquery.
Validate when the required checkbox is checked (http://jquery.bassistance.de/validate/demo/index.html)
Dynamic form (http://jquery.bassistance.de/validate/demo/dynamic-totals.html)
and my question is, if I am going to use this, would it be easier for me to create the form using standard HTML form tag instead of .NET control? Or can I still use .NET control?
I am quite struggle as I want to use the .NET control because I can obtain the value easily in code behind instead of Request.Form["fieldName"] but on the other hand, I feel not convenience to use the validation that .NET provided and I am not sure whether .net can create a dynamic form as easy as Jquery either.
Please advise. Thanks!
with validation plugin you can use "when required" case like this
$('#formSubmit').validate({
rules: {
ControlAspNetorSmtin: {
required: {
depends: function (element) {
if ($('#chkglobal').is(':checked')) {
return false;
} else {
return true;
}
}
}
}.... etc
If you are using ASP.NET MVC (which you probably should be) then your best bet would be to use auto-magic validation using model validation attributes and unobtrusive-validation. This would take care of client- and server-side validation with minimal effort (apart from defining the attributes).
Related
Suppose I have a model with some string property.
Imagine also that this string property is actually a comma delimited list of values.
If I want to make a form to update values on my model it would be easy enough to call:
#Html.TextBoxFor(model => model.myCommaDelimitedProp, new { #class = "form-control", placeholder = "CommaDelimitedPropValue" })
However, that is not good enough for the intended application.
I would like to have a custom EditorFor() that could somehow take my property, use string parsing and next generate an array of text boxes to display the pre-existing values.
That would also be relatively trivial.
However, what I cannot seem to solve, mainly because I lack client side experience (js, jquery, angular, ...):
How could I make my editor such that there would be a small button so that I could dynamically add rows, fill them such that, upon form submission, I could string the new values onto the pre-existing string.
So specifically, what would any of you use to achieve this client side behaviour?
I just need some help to be put on the way...
You can achieve this with editor templates. There's a quick intro I threw together on my blog. The only additional thing you'll need is UIHint. Since you won't be able to rely on a specific C# type or DataType annotation to determine that this should be treated as a comma-delimited property. You can just explicitly tell Razor what template it should use. For example:
[UIHint("CommaDelimited")]
public string MyCommaDelimitedProperty { get; set; }
Which would correspond to the editor template: Views\Shared\EditorTemplates\CommaDelimited.cshtml. Once you set up that view how you like it. Then in your form you just call:
#Html.EditorFor(m => m.MyCommaDelimitedProperty)
EDIT
I'll leave my previous answer because it could still be helpful in terms of being able to generate a control for a specific type of thing. You actually may still need to use it to get the right set up on your field to make the JS work properly.
However, when it comes to the client-side handling of this, I figured there had to be something out there already to solve this problem. (Never do more work than you have to.) A cursory search turned up a little script called Tokenfield for Bootstrap. I'm not sure if you're using Bootstrap or not. If not, I also found jQuery Tokeninput and jquery.token-field. I'm sure there's others, as well.
I am having problems trying to invoke just one validator on it own, I know how to call on all validators to perform checks on buttons click events, by using Page.Validate() but how can I invoke lets say mySingledOutValidator I tried mySingledOutValidator.Validate() but that's not gonna work individual controls don't have .validate()
I need the following to be true:
Get a single validation to happen
In C# Asp.Net
.net 2.0 framework
If the above is not possible I do not mind looking into javascript alternatives.
If you can help it would be greatly appreciated.
You can use Group Validation. You can assign a validator a validationgroup value, and then explicitly validate that group, which can contain 1 or more validators.
Page.Validate("MyGroup");
You can also check the validation status of each validator explicitly using IsValid property, assuming validation has already taken place.
According this article:
function ValidatorValidate(val, validationGroup, event)
With jquery validators:
And in case I wanted to force the validation I should have written:
ValidatorValidate($("#<%= valEncOtherMimeTypeRequired.ClientID %>")[0]);
It seems that ASP.NET validators do not validate hidden fields. I get messages like this:
Control 'hiddenField' referenced by the ControlToValidate property of 'hiddenFieldValidator' cannot be validated.
I have an <asp:HiddenField> in my page which gets filled client side with some value. I need this to be present once on the server so I added a RequiredFieldValidator to it.
And it does not work!
As I see it, as a workaround, I can:
1. use a custom validator and not tie it to the hidden field, just call a method on OnServerValidate;
2. Use a <asp:TextBox> with a CSS style display:none and it should work.
But I want to make sure I am not missing something here. Is it possible or not to validate a hidden field in the same way as the other text fields? O maybe a third, more elegant option?
TIA!
#Peter's answer got me thinking, what does ControlPropertiesValid actually check??
Looking at the MSDN topic it looks for, among other things, the ValidationPropertyAttribute.. Hhmm, so if we just derive from HiddenField and decorate the new class with ValidationPropertyAttribute set to Value (for my purposes) then 'everything just works'. And it does.
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Partner.UserControls {
[ValidationProperty("Value")]
public class HiddenField2 : HiddenField {
} // nothing else required other than ValidationProperty
}
Usage - make sure you register the assembly containing the control:
<%# Register Assembly="MyApp" Namespace="MyApp.Controls" TagPrefix="sw" %>
And in your Page/UserControl content:
<sw:HiddenField2 ID="hidSomeImportantID" runat="server" />
All validators will work with this. The added benefit is that if you (like me) are using a custom validation function you can easily evaluate the HiddenField2.Value because it is contained in the args.Value field (on server side this is ServerValidateEventArgs).
Just as the exception message you're getting says, it seems HiddenField controls can't be targeted by the standard validation controls directly. I would go with the CustomValidator workaround.
Here is the workaround I came up with, because unfortunately I couldn't find any reliable way to validate using the RequiredFieldValidator OR the CustomValidator out of the box. If you leave the ControlToValidate property empty it yells at you. All you have to do is create a custom control like the one below:
public class HiddenFieldValidator : RequiredFieldValidator
{
protected override bool ControlPropertiesValid()
{
return true;
}
}
By overriding the properties valid check so that it always returns true it no longer cares that you are using a HiddenField and it will pull the value out of it and verify without issue.
This is a response to the solution by Scotty.NET. I just don't have enough reputation to reply.
+1 to Scotty.NET!
For those of us who don't know enough about .NET and compiling and such, this may help simplify usage of his answer for someone else.
I wanted to make use of it in a website using Visual Web Developer 2010 Express:
1) I saved the derived HiddenField2 in /App_Code as HiddenField2.cs, with one change --> namespace Controls
2) Then, to register the control:
a) On the page, <%# Register Assembly="App_Code" Namespace="Controls" TagPrefix="local" %>
b) In web.config, within system.web > pages > controls, <add tagPrefix="local" namespace="Controls" assembly="App_Code" />
3) And, finally, of course, refer to it as <local:HiddenField2 ...>.
It does make for funky code coloring. Probably fairly easy to improve the namespace to handle that. Works wonderfully for me in my local environment; guess I don't know it won't have problems on a live server.
Additional reference:
extending asp.net control in the website project
To expand on #Anders' solution, with a CustomValidator approach, you can very easily grab the value of a standard HiddenField control by first finding the control, casting it, and then using its UniqueID to look its value up in the Page.Request.Form[].
Example 1: Improving the Compare Validator
This example may be a bit more local to your implementation. The below is an improved version of the CompareValidator.EvaluateIsValid() method call, in order to add support for validating HiddenField controls. Note that this technique can be applied to any validator, instead of wrapping the HiddenField in a custom control, but that the ControlPropertiesValid method should also be overriden to recognize and return true in the presence of a HiddenField.
...
private new string GetControlValidationValue(string id)
{
var control = this.NamingContainer.FindControl(id);
if (control != null)
{
if (control is HiddenField)
{
return Page.Request.Form[((HiddenField)control).UniqueID];
}
else
{
return base.GetControlValidationValue(id);
}
}
}
protected override bool EvaluateIsValid()
{
// removed 'base.' from the call to 'GetControlValidationValue'
string controlValidationValue = GetControlValidationValue(base.ControlToValidate);
if (controlValidationValue.Trim().Length == 0)
{
return true;
}
bool flag = (base.Type == ValidationDataType.Date) && !this.DetermineRenderUplevel();
if (flag && !base.IsInStandardDateFormat(controlValidationValue))
{
controlValidationValue = base.ConvertToShortDateString(controlValidationValue);
}
bool cultureInvariantRightText = false;
string date = string.Empty;
if (this.ControlToCompare.Length > 0)
{
//same as above
date = GetControlValidationValue(this.ControlToCompare);
if (flag && !base.IsInStandardDateFormat(date))
{
date = base.ConvertToShortDateString(date);
}
}
else
{
date = this.ValueToCompare;
cultureInvariantRightText = base.CultureInvariantValues;
}
return BaseCompareValidator.Compare(controlValidationValue, false, date, cultureInvariantRightText, this.Operator, base.Type);
}
...
Example 2: Custom Dynamic Validator
This example is a bit more complicated than the first one. I regularly use custom dynamic validators that are enabled or disabled based on the value of another control on the page (e.g., if that box is checked then this textbox is required; otherwise it does not need to be validated). One such validator is my DynamicRequiredFieldValidator, which inherits from the built-in RequiredFieldValidator. The dynamic validator has two custom attributes, ControlThatEnables and ControlValueThatEnables, that are used to decide whether or not the validator should be turned on. The below is a snippet from the method that determines whether or not the validator should be enabled, but note that, as above, this same technique can be applied to validating a HiddenField without the need to wrap it in a custom control.
...
var enablingControl = this.NamingContainer.FindControl(ControlThatEnables);
if (enablingControl != null)
{
if (enablingControl is HiddenField)
{
var hfValue = Page.Request.Form[((HiddenField)enablingControl).UniqueID];
isValidatorEnabled = hfValue == ControlValueThatEnables;
}
}
...
Final Thoughts
The implementation decision is ultimately up to you, as the developer, but my preference is to wrap existing validators in custom controls, rather than to wrap things like HiddenFields, TextBoxes, DropDownLists, etc. in custom controls. I have two main reason for preferring this solution: (1) wrapping the validators take only a few minutes more than just adding the ValidationProperty, but provides significantly more flexibility and opportunity for further improvement of .NET validaton, e.g. one could point the FindControl calls to some custom method that searches for the desired control ID in the current NamingContainer (default) and then expands the search to the outer Page or the NamingContainer's parent if the control was not found; (2) IMHO if one is trying to improve validation, it is cleaner to make improvements to validation, and, contrarily, if one is trying to improve a WebControl, it is cleaner to make improvements to the WebControl.
I completely respect #Scotty's solution, and will be the first to admit that if it is the only change to be made, then his solution will save you 5 minutes more than this one. IMHO however, #Anders' is likely to be a better choice, in the long run.
I'd go with a CustomValidator client side
<script type="text/javascript">
function myMethod(source, args) {
args.IsValid = document.getElementById("<%= myValue.ClientID %>").value != '';
}
</script>
<asp:HiddenField ID="myValue" runat="server" />
<asp:CustomValidator runat="server" ClientValidationFunction="myMethod"
ErrorMessage="Value missing!" />
Is there away to add and remove DataAnnotations, in particular the [requried], from the code side of things? My problem is that I want to give the user the ability to save an incomplete form in our CRUD applications but at the same time use the power of the DataAnnotations validation.
If this is not possible, what is the best way I can go about this?
You can keep the DataAnnotation attributes on your model and then just manually clear the validation errors as needed from code. It might look something like this:
if (certainCondition == true) {
ModelState["someKey"].Errors.Clear();
ModelState["anotherKey"].Errors.Clear();
}
It is impossible to add, remove or modify DataAnnotations dynamically since they are Attributes. Attributes are part of the type and can't be changed during runtime.
You could use ModelState as Larsenal suggested provided that:
you use it After validation has executed. (prior to that, ModelState will be empty. It doesn't provide access to all validators, it only stores validator-errors after they've occurred)
you don't have any clientside validation that's based on the DataAnnotationValidators and fires errors that prevent you from even reaching the serverside validation.
In our new product we have a few data entry fields that require you to search for the correct value to place in this field.
When you enter this data entry field I would like to provide a search option via something on the view (perhaps an Ajax implementation) and have it allow searching of the database for the value, but when the result returns I want to keep the existing values in place for other fields not affected by the search.
But I have no idea how to do this with MVC. Does anyone have any suggestions on how this should be done?
Write your data entry page in the
usual way for an ASP.NET MVC view.
Get it working without the Ajax
(e.g., submit works correctly when
you just type in the values, without
auto complete).
Write the prototype for a JavaScript method you'll called when the user performs a certain action (e.g. presses a key inside of a certain control). But this inside a script tag in your aspx page. Unfortunately, stack overflow seems to "sanitize" script tags in my example, so I can't demonstrate that part. But you're JavaScript prototype will look something like this:
function startAutoComplete() {
}
Now hook up the event handlers on the user interface control. You need to call the function you've just prototyped an appropriate event handlers for your application. From your description, it sounds like you might want to use onkeydown, but there are lots of events to choose from. You probably need to handle more than one event, as appropriate for your application.
So far, everything that we've done has been standard aspx and JavaScript. In this step, we'll do the only part of the whole process which is really different for ASP.NET MVC. You need to add an action to your controller which will be called (indirectly) by the JavaScript prototype you've just written. The action should accept appropriate input (e.g., a string representing the text from control, or something like that, as appropriate for your application) and return its results in JSON format. I'm going to show a really simple example here; feel free to substitute more complex code in your real application.
public ActionResult GetSuggestions(string searchText)
{
return Json(new {SearchText = searchText});
}
This example just returns a JavaScript object containing one property, which contains the value passed to the function. Like you said, you can write something more useful for your application.
Now you need to call this function in JavaScript. The URI will look something like:
http://localhost/mycontroller/GetSuggestions?searchText=Foo
It is possible to make Ajax calls without a JavaScript library, but much easier if you use jQuery or some other library which handles cross-browser compatibility issues for you. Since I happen to like jQuery, I'll demonstrate that. Let's update the startAutoComplete method we prototyped earlier:
function startAutoComplete() {
var searchText = $("#myeditorid").text();
$.getJSON("/mycontroller/GetSuggestions?searchText=" + searchText,
null,
autoCompleteResponse);
}
The first line uses jQuery to get the text in the control with the ID myeditorid. We'll pass this to the ASP.NET MVC action as the searchText argument, by appending it as a query string parameter.
The next line, which starts with $.getJSON calls a jQuery function which makes an Ajax call to the URI you specify. We pass an argument, autoCompleteResponse, which is the name of a JavaScript method to be called if the response from the Ajax call is successful. Now we have to write autoCompleteResponse.
function autoCompleteResponse(data) {
if (data.SearchText)
{
$("#myeditorid").text(data.SearchText);
}
}
This says, "If the data returned has a SearchText property, set the text of the control to that value." Again, do whatever is appropriate for your application with the data returned.