Expressiveannotations Cannot Read Property 'call' of Undefined
ExpressiveAnnotations [annotation-based conditional validation]
A small .NET and JavaScript library which provides full-stack, annotation-based, conditional validation mechanisms.
Given attributes, powered past expressions engine, let to forget about imperative way of step-past-step implementation of validation atmospheric condition in many cases. Since fields validation requirements are practical as metadata, domain-related code is more condensed.
Table of contents
- What is the context behind this work?
- RequiredIf vs. AssertThat - where is the deviation?
- Sample projects + demo
- What are a brief examples of usage?
- Declarative vs. imperative programming - what is it about?
- EA expressions specification
- Grammar definition
- Where syntax meets semantics
- Operators precedence and associativity
- Built-in functions (methods ready to exist used by expressions)
- How to construct conditional validation attributes?
- Signatures description
- Implementation details outline
- Traps (discrepancies between server- and client-side expressions evaluation)
- What about the back up of ASP.NET MVC client-side validation?
- Often asked questions
- Is it possible to compile all usages of annotations at once? (re server-side)
- What if there is no built-in function I demand? (re client and server-side)
- Can I have custom utility-like functions exterior of my models? (re server-side)
- How to cope with values of custom types? (re client-side)
- How to cope with dates given in non-standard formats? (re client-side)
- What if "ea" variable is already used past some other library? (re client-side)
- How to control frequency of dependent fields validation? (re client-side)
- Tin I increase spider web panel verbosity for debug purposes? (re client-side)
- I prefer enum values to be rendered equally numbers, is it allowed? (re client-side)
- How to access one method from another? (re client-side)
- How to access current command from inside a method? (re client-side)
- How to fetch field's value or its display proper name in error message? (re client and server-side)
- Is there any event raised when validation is done? (re customer-side)
- Tin I decorate conditionally required fields with asterisks? (re client-side)
- How to handle validation based on parent model field? (re customer and server-side)
- RequiredIf attribute is not working, what is wrong? (re client and server-side)
- Few fields seem to exist bypassed during validation, whatsoever clues? (re client-side)
- Client-side validation doesn't work, how to troubleshoot it? (re client-side)
- Is there a possibility to perform asynchronous validation? (re client-side, experimental)
- What if my question is not covered by FAQ section?
- Installation instructions
- Contributors
- License
What is the context behind this work?
There are number of cases where the concept of metadata is used for justified reasons. Attributes are one of the ways to associate complementary information with existing information. Such annotations may besides define the correctness of data.
Declarative validation when compared to imperative approach seems to be more user-friendly in many cases. Clean, compact lawmaking - all validation logic defined inside the model telescopic. Unproblematic to write, obvious to read.
RequiredIf vs. AssertThat - where is the difference?
-
RequiredIf
- if value is non yet provided, check whether information technology is required (annotated field is required to exist non-nothing, when given condition is satisfied), -
AssertThat
- if value is already provided, check whether the condition is met (non-null annotated field is considered as valid, when given condition is satisfied).
Sample projects + demo
- ASP.NET MVC web sample,
- WPF MVVM desktop sample.
ASP.NET MVC web sample is likewise hosted online - http://expressiveannotations.cyberspace/.
What are a brief examples of usage?
This department presents few exemplary lawmaking snippets. Sample projects in the section above contain much more comprehensive prepare of use cases.
using ExpressiveAnnotations.Attributes; [RequiredIf("GoAbroad == truthful")] public string PassportNumber { get; ready; }
To a higher place we are proverb, that annotated field is required when condition given in the logical expression is satisfied (passport number is required, if go abroad field has true boolean value).
Simple plenty, let's move to another variation:
[AssertThat("ReturnDate >= Today()")] public DateTime? ReturnDate { go; gear up; }
By the usage of this attribute type, we are non validating field requirement every bit before - its value is allowed to be null this time. Nevertheless, if some value is already given, provided restriction needs to be satisfied (return engagement needs to be greater than or equal to the date returned by Today()
built-in office).
Every bit shown below, both types of attributes may exist combined (moreover, the aforementioned blazon tin can be applied multiple times for a unmarried field):
[RequiredIf("Details.Email != cipher")] [RequiredIf("Details.Phone != nil")] [AssertThat("AgreeToContact == true")] public bool? AgreeToContact { get; set; }
Literal translation ways, that if either email or phone is provided, you lot are forced to authorize someone to contact with you (boolean value indicating contact permission has to be true). What is more, we can run into that nested properties are supported past the expressions parser.
The complexity of expressions may be arbitrarily increased, e.g. take a brief look at the following structure:
[RequiredIf(@"GoAbroad == true && ( (NextCountry != 'Other' && NextCountry == Country) || (Age > 24 && Historic period <= 55) )")] public string ReasonForTravel { become; set up; }
Restriction above, despite being more specific than its predecessors, even so can exist apace understood (reason for travel has to be provided if y'all plan to get away and, either want to visit the same definite country twice, or are between 25 and 55).
Conditional operations are supported (ternary operator defined). You can imply diverse assertions on specific field based on certain condition (or nested conditions), e.g.
[AssertThat("Switch == 'ON' ? Voltage1 == Voltage2 : true")] public int Voltage1 { become; set up; }
Hither, when switch is ON, voltages must be equal - otherwise everything is OK. Yous could express the same statement without conditional operator, i.eastward.
[AssertThat("Switch == 'ON' && (Voltage1 == Voltage2) || (Switch != 'ON')")]
but it is less verbose.
Declarative vs. imperative programming - what is it about?
With declarative programming you write logic that expresses what y'all want, but not necessarily how to reach information technology. Yous declare your desired results, but not pace-by-step.
In our case, this concept is materialized by attributes, e.thousand.
[RequiredIf("GoAbroad == true && NextCountry != 'Other' && NextCountry == Country", ErrorMessage = "If y'all plan to travel abroad, why visit the same country twice?")] public string ReasonForTravel { get; set; }
Hither, we're saying "ensure the field is required co-ordinate to given status".
With imperative programming you define the command flow of the computation which needs to exist done. You tell the compiler what you want, exactly step by step.
If we choose this way instead of model fields ornament, it has negative impact on the complication of the code. Logic responsible for validation is now implemented somewhere else in our application, e.thou. inside controllers actions instead of model class itself:
if (!model.GoAbroad) return View("Success"); if (model.NextCountry == "Other") return View("Success"); if (model.NextCountry != model.Country) return View("Success"); ModelState.AddModelError("ReasonForTravel", "If you plan to travel abroad, why visit the same state twice?"); return View("Dwelling", model); }
Here instead, we're saying "if condition is met, return some view; otherwise, add together error message to country container, render other view".
EA expressions specification
Grammar definition
Expressions handled past EA parser must comply with the following grammar:
exp => cond-exp cond- exp => l-or-exp ['?' exp ':' exp] // right associative (correct recursive) l-or- exp => l-and-exp ('||' l-and-exp)* // left associative (not-recursive alternative to left recursion) l-and- exp => b-and-exp ('&&' b-and-exp)* b-or- exp => xor-exp ('|' xor-exp)* xor- exp => b-and-exp ('^' b-and-exp)* b-and- exp => eq-exp ('&' eq-exp)* eq- exp => rel-exp (('==' | '!=') rel-exp)* rel- exp => shift-exp (('>' | '>=' | '<' | '<=') shift-exp)* shift- exp => add-exp (('<<' | '>>') add-exp)* add- exp => mul-exp (('+' | '-') mul-exp)* mul- exp => unary-exp (('*' | '/' | '%') unary-exp)* unary- exp => ('+' | '-' | '!' | '~') unary-exp | primary-exp primary- exp => nil-lit | bool-lit | num-lit | string-lit | arr-admission | id-admission | '(' exp ')' arr- access => arr-lit | arr-lit '[' exp ']' ('[' exp ']' | '.' identifier)* id- access => identifier | identifier ('[' exp ']' | '.' identifier)* | func-call ('[' exp ']' | '.' identifier)* func- call => identifier '(' [exp-listing] ')' null- lit => 'null' bool- lit => 'truthful' | 'false' num- lit => int-lit | bladder-lit int- lit => december-lit | bin-lit | hex-lit assortment- lit => '[' [exp-listing] ']' exp- list => exp (',' exp)*
Terminals are expressed in quotes. Each nonterminal is defined by a rule in the grammar except for dec-lit, bin-lit, hex-lit, bladder-lit, cord-lit and identifier, which are assumed to be implicitly defined (identifier specifies names of functions, properties, constants and enums).
Expressions are built of Unicode messages and numbers (i.due east. [L*]
and [N*]
categories respectively) with the usage of the post-obit components:
- logical operators:
!a
,a||b
,a&&b
, - comparison operators:
a==b
,a!=b
,a<b
,a<=b
,a>b
,a>=b
, - arithmetics operators:
+a
,-a
,a+b
,a-b
,a*b
,a/b
,a%b
,~a
,a&b
,a^b
,a|b
,a<<b
,a>>b
, - other operators:
a()
,a[]
,a.b
,a?b:c
, - literals:
- naught, i.eastward.
null
, - boolean, i.e.
true
andfalse
, - decimal integer, e.g.
123
, - binary integer (with
0b
prefix), e.chiliad.0b1010
, - hexadecimal integer (with
0x
prefix), eastward.g.0xFF
, - float, due east.g.
1.five
or0.3e-2
, - string, e.1000.
'in single quotes'
(internal quote escape sequence is\'
, character representing new line is\n
), - assortment (comma separated items within square brackets), e.g.
[1,2,3]
, - identifier, i.e. names of functions, backdrop, constants and enums.
- naught, i.eastward.
Where syntax meets semantics
EA expressions syntax is defined by the grammer shown above.
Valid expressions must follow not merely lexical and syntax level rules, but must have appropriate semantics as well.
Grammars, equally already mentioned, naturally define the language syntax - but not only. Grammars in full general contribute to the semantics a little, by defining the parse tree - thus cogent the precedence and associativity of operators. This being said, it is not just virtually the legal string existence produced - the structure of parse tree corresponds to the social club, in which various parts of the expression are to be evaluated.
Such contribution to semantics is non enough though. Grammar says naught nearly the types of operands. For the expressions to have valid semantics, all the requirements on the types of operands must exist realized also.
Prior to execution of an functioning, type checks and eventual type conversions are made. The result type, e.g. of a valid binary performance is, about of the time simply not always, the same every bit the most general of the input types. When a binary functioning is used and then a generalization of operands is performed, to make the two operands the same (nearly full general) blazon, earlier the operation is done. The order of generalization, from near general to almost specific, is briefly described equally follows: string
(generalization done using the current locale) -> double
-> int
. Also nullable types are more general than their non-nullable counterparts.
Operators precedence and associativity
The following table lists the precedence and associativity of operators (listed top to bottom, in descending precedence):
Precedence | Operator | Description | Associativity |
---|---|---|---|
1 | () | Office call (postfix) | Left to right |
[] | Subscript (postfix) | ||
. | Fellow member access (postfix) | ||
2 | + - | Unary plus and minus | Correct to left |
! ~ | Logical Non and bitwise NOT (ane's complement) | ||
3 | * / % | Multiplication, division, and rest | Left to right |
iv | + - | Add-on and subtraction | |
5 | << >> | Bitwise left shift and right shift | |
6 | < <= | Relational operators < and ≤ respectively | |
> >= | Relational operators > and ≥ respectively | ||
7 | == != | Equality operators = and ≠ respectively | |
viii | & | Bitwise AND | |
nine | ^ | Bitwise XOR (exclusive OR) | |
x | | | Bitwise OR (inclusive OR) | |
xi | && | Logical AND | |
12 | || | Logical OR | |
thirteen | ?: | Ternary conditional | Correct to left |
Built-in functions (methods set up to be used by expressions)
Every bit already noted, in that location is an option to reinforce expressions with functions, e.g.
[AssertThat("StartsWith(CodeName, 'abc.') || EndsWith(CodeName, '.xyz')")] public cord CodeName { get; set up; }
Toolchain functions bachelor out of the box at server- and client-side:
-
DateTime At present()
- Gets the current local date and time (client-side returns the number of milliseconds since Jan 1, 1970, 00:00:00 UTC).
-
DateTime Today()
- Gets the current date with the time component fix to 00:00:00 (customer-side returns the number of milliseconds since January 1, 1970, 00:00:00 UTC).
-
DateTime Date(int year, int month, int day)
- Initializes a new date to a specified twelvemonth, month (months are one-based), and twenty-four hour period, with the fourth dimension component ready to 00:00:00 (client-side returns the number of milliseconds since Jan ane, 1970, 00:00:00 UTC).
-
DateTime Date(int twelvemonth, int calendar month, int day, int hour, int minute, int 2nd)
- Initializes a new date to a specified year, month (months are 1-based), twenty-four hours, hour, infinitesimal, and second (client-side returns the number of milliseconds since January i, 1970, 00:00:00 UTC).
-
DateTime ToDate(cord dateString)
- Converts the specified cord representation of a date and time to its equivalents:
DateTime
at server-side - uses .NETDateTime.Parse(string dateString)
, and number of milliseconds since January 1, 1970, 00:00:00 UTC at client-side - uses JavaScriptDate.parse(dateString)
.
- Converts the specified cord representation of a date and time to its equivalents:
-
TimeSpan TimeSpan(int days, int hours, int minutes, int seconds)
- Initializes a new time period co-ordinate to specified days, hours, minutes, and seconds (client-side catamenia is expressed in milliseconds).
-
int Length(str)
- Gets the number of characters in a specified cord (nil-rubber).
-
cord Trim(string str)
- Removes all leading and trailing white-space characters from a specified string (goose egg-rubber).
-
string Concat(string strA, string strB)
- Concatenates two specified strings (null-safety).
-
string Concat(string strA, string strB, strC)
- Concatenates three specified strings (nix-rubber).
-
int CompareOrdinal(string strA, cord strB)
- Compares strings using ordinal sort rules. An integer that indicates the lexical relationship between the two comparands is returned (null-safe):
- -1 - strA is less than strB,
- 0 - strA and strB are equal,
- 1 - strA is greater than strB.
- Compares strings using ordinal sort rules. An integer that indicates the lexical relationship between the two comparands is returned (null-safe):
-
int CompareOrdinalIgnoreCase(cord strA, string strB)
- Compares strings using ordinal sort rules and ignoring the case of the strings existence compared (aught-safe).
-
bool StartsWith(string str, string prefix)
- Determines whether the beginning of specified cord matches a specified prefix (null-safe).
-
bool StartsWithIgnoreCase(cord str, string prefix)
- Determines whether the start of specified cord matches a specified prefix, ignoring the case of the strings (null-safe).
-
bool EndsWith(string str, cord suffix)
- Determines whether the end of specified string matches a specified suffix (naught-rubber).
-
bool EndsWithIgnoreCase(string str, string suffix)
- Determines whether the finish of specified string matches a specified suffix, ignoring the case of the strings (null-safe).
-
bool Contains(string str, cord substr)
- Returns a value indicating whether a specified substring occurs within a specified string (aught-prophylactic).
-
bool ContainsIgnoreCase(string str, string substr)
- Returns a value indicating whether a specified substring occurs inside a specified string, ignoring the case of the strings (null-safe).
-
bool IsNullOrWhiteSpace(cord str)
- Indicates whether a specified string is zip, empty, or consists only of white-space characters (null-safe).
-
bool IsDigitChain(cord str)
- Indicates whether a specified string represents a sequence of digits (ASCII characters just, null-prophylactic).
-
bool IsNumber(string str)
- Indicates whether a specified string represents integer or float number (ASCII characters only, null-safe).
-
bool IsEmail(string str)
- Indicates whether a specified string represents valid email address (nil-safety).
-
bool IsPhone(cord str)
- Indicates whether a specified string represents valid phone number (null-safe).
-
bool IsUrl(cord str)
- Indicates whether a specified string represents valid url (null-safe).
-
bool IsRegexMatch(cord str, string regex)
- Indicates whether the regular expression finds a match in the input string (null-safe).
-
Guid Guid(string str)
- Initializes a new instance of the Guid structure by using the value represented by a specified string.
-
double Min(params double[] values)
- Returns the minimum value in a sequence of numeric values.
-
double Max(params double[] values)
- Returns the maximum value in a sequence of numeric values.
-
double Sum(params double[] values)
- Computes the sum of the numeric values in a sequence.
-
double Average(params double[] values)
- Computes the average of the numeric values in a sequence.
How to construct conditional validation attributes?
Signatures description
RequiredIfAttribute( string expression, [bool AllowEmptyStrings], [int Priority] [cord ErrorMessage] ...) /* Validation attribute, executed for null-only annotated * field, which indicates that such a field is required * to exist not-null, when computed result of given logical * expression is true. */ AssertThatAttribute( string expression, [int Priority] [string ErrorMessage] ...) /* Validation aspect, executed for non-zip annotated * field, which indicates that assertion given in logical * expression has to be satisfied, for such a field to be * considered as valid. */
expression - The logical expression based on which specified status is computed. AllowEmptyStrings - Gets or sets a flag indicating whether the attribute should allow empty or whitespace strings. Simulated by default. Priority - Gets or sets the hint, available for any concerned external components, indicating the order in which this attribute should be executed amidst others of its kind. Value is optional and not set by default, which means that execution order is undefined. ErrorMessage - Gets or sets an explicit error bulletin cord. A difference to default behavior is awareness of new format items, i.e. {fieldPath[:indicator]}. Given in curly brackets, can be used to extract values of specified fields, e.g. {field}, {field.field}, inside current model context or display names of such fields, e.g. {field:n}. Braces tin can be escaped by double-braces, i.east. to output a { use {{ and to output a } utilise }}. The same logic works for messages provided in resources.
Note to a higher place covers most exhaustively what is really needed to work with EA. Notwithstanding, the full API documentation, generated with Sandcastle (with the back up of SHFB), can be downloaded (in the form of compiled HTML help file) from here (includes just C# API, no JavaScript role there).
Implementation details outline
Implementation cadre is based on expressions parser, which runs on the grammer shown in a higher place.
Firstly, at the lexical analysis stage, graphic symbol stream of the expression is converted into token stream (whitespaces ignored, characters grouped into tokens and associated with position in the text). Next, at the syntax analysis level, abstract syntax tree is constructed co-ordinate to the rules defined past the grammar. While the tree is being built, as well the tertiary phase, mainly semantic assay, is existence performed. This stage is directly related to operands blazon checking (and eventual type conversions co-ordinate to type generalization rules, when incompatible types are detected).
Based on valid expression string expression tree structure is finally beingness built. A delegate containing compiled version of the lambda expression (defined past the expression tree) is returned as a result of the parsersing mechanism. Such delegate tin be then invoked for specified model object.
When expression is provided to the attribute, it should be of a boolean type. The result of its evaluation indicates whether the assertion or requirement status is satisfied or not.
For the sake of functioning optimization, expressions provided to attributes are compiled simply one time. Such compiled lambdas are then cached inside attributes instances and invoked for any subsequent validation requests without recompilation.
When working with ASP.Internet MVC stack, unobtrusive customer-side validation mechanism is additionally available. Client receives unchanged expression cord from server. Such an expression is then evaluated using JavaScript eval()
method within the context of reflected model object. Such a model, analogously to the server-side 1, is basically deserialized DOM form (with some type-safety assurances and registered toolchain methods).
Traps (discrepancies betwixt server- and client-side expressions evaluation)
Because client-side handles expressions in its unchanged form (as provided to attribute), attention is needed when dealing with cipher
keyword - there are discrepancies between EA parser (mostly follows C# rules) and JavaScript, e.g.
-
aught + "text"
- in C#"text"
, in JS"nulltext"
, -
2 * null
- in C#null
, in JS0
, -
null > -1
- in C#false
, in JStruthful
, - and more...
What virtually the support of ASP.Internet MVC customer-side validation?
Client-side validation is fully supported. Enable it for your web project within the side by side few steps:
-
Reference both assemblies to your project: core ExpressiveAnnotations.dll (defines validation attributes driven by expressions) and subsidiary ExpressiveAnnotations.MvcUnobtrusive.dll (defines model validators for ASP.NET MVC).
-
In Global.asax register required validators (
IClientValidatable
interface is non straight implemented by the attributes, to avoid coupling of ExpressionAnnotations assembly with System.Spider web.Mvc dependency):using ExpressiveAnnotations.Attributes; using ExpressiveAnnotations.MvcUnobtrusive.Validators; protected void Application_Start() { DataAnnotationsModelValidatorProvider.RegisterAdapter( typeof (RequiredIfAttribute), typeof (RequiredIfValidator)); DataAnnotationsModelValidatorProvider.RegisterAdapter( typeof (AssertThatAttribute), typeof (AssertThatValidator));
Alternatively, employ predefined
ExpressiveAnnotationsModelValidatorProvider
(recommended):using ExpressiveAnnotations.MvcUnobtrusive.Providers; protected void Application_Start() { ModelValidatorProviders.Providers.Remove( ModelValidatorProviders.Providers .FirstOrDefault(x => 10 is DataAnnotationsModelValidatorProvider)); ModelValidatorProviders.Providers.Add( new ExpressiveAnnotationsModelValidatorProvider());
Despite the fact this provider automatically registers adapters for expressive validation attributes, information technology additionally respects their processing priorities when validation is performed (i.e. the
Priority
property actually means something in practise). -
Include expressive.annotations.validate.js script (makes customer-side validation to work out of the box) in your page. It should be included in packet below jQuery validation files:
<script src="/Scripts/jquery.validate.js"> </script> <script src="/Scripts/jquery.validate.unobtrusive.js"> </script> ... <script src="/Scripts/expressive.annotations.validate.js"> </script>
For supplementary reading visit the installation section.
Often asked questions
Is information technology possible to compile all usages of annotations at once?
Yes, a complete listing of types with annotations can be retrieved and compiled collectively. It tin can be useful, eastward.g. during unit of measurement testing stage, when without the necessity of your main application startup, all the compile-time errors (syntax errors, type checking errors) done to your expressions can be discovered. The following extension is helpful:
public static IEnumerable<ExpressiveAttribute> CompileExpressiveAttributes( this Blazon type) { var properties = type.GetProperties() .Where(p => Aspect.IsDefined(p, typeof (ExpressiveAttribute))); var attributes = new List<ExpressiveAttribute>(); foreach (var prop in properties) { var attribs = prop.GetCustomAttributes<ExpressiveAttribute>().ToList(); attribs.ForEach(x => x.Compile(prop.DeclaringType)); attributes.AddRange(attribs); } return attributes; }
with the succeeding usage fashion:
// compile all expressions for specified model: var compiled = typeof (SomeModel).CompileExpressiveAttributes().ToList(); // ... or for electric current assembly: compiled = Assembly.GetExecutingAssembly().GetTypes() .SelectMany(t => t.CompileExpressiveAttributes()).ToList(); // ... or for all assemblies within current domain: compiled = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => a.GetTypes() .SelectMany(t => t.CompileExpressiveAttributes())).ToList();
Find that such compiled lambdas will be buried inside attributes instances stored in compiled
list. That means that subsequent compilation requests:
compiled.ForEach(ten => 10.Compile(typeof (SomeModel));
practise nothing (due to optimization purposes), unless invoked with enabled recompilation switch:
compiled.ForEach(x => 10.Compile(typeof (SomeModel), force: true);
Finally, this solution reveals compile-time errors only, yous tin still can become runtime errors though, e.thousand.:
var parser = new Parser(); parser.AddFunction<object, bool>("CastToBool", obj => (bool) obj); parser.Parse<object>("CastToBool(null)"); // compilation succeeds parser.Parse<object>("CastToBool(null)").Invoke(null); // invocation fails (type casting err)
What if there is no built-in office I need?
Create information technology yourself. Any custom function defined within the model class telescopic at server-side is automatically recognized and can be used inside expressions, due east.g.
form Model { public bool IsBloodType( cord group ) { return Regex.IsMatch(group, @"^(A|B|AB|0)[\+-]$"); } [AssertThat("IsBloodType(BloodType)")] // method known hither (context aware expressions) public string BloodType { go; set; }
If client-side validation is needed every bit well, function of the aforementioned signature (name and the number of parameters) must be available there. JavaScript corresponding implementation should be registered by the post-obit education:
<script> ea.addMethod('IsBloodType', function(grouping) { return /^(A|B|AB|0)[\+-]$/.test(group); });
Many signatures can be defined for a unmarried function name. Types are not taken under consideration as a differentiating factor though. Methods overloading is based on the number of arguments only. Functions with the same name and exact number of arguments are considered equally ambiguous. The side by side issue important here is the fact that custom methods take precedence over built-in ones. If exact signatures are provided built-in methods are just overridden by new definitions.
Can I have custom utility-like functions exterior of my models?
Sure, provide your own methods provider, or extend existing global one, i.e.
-
extend existing provider:
protected void Application_Start() { Toolchain.Example.AddFunction<int[], int>("ArrayLength", array => assortment.Length);
* ascertain new provider: ```C# public class CustomFunctionsProvider : IFunctionsProvider { public IDictionary<string, IList<LambdaExpression>> GetFunctions() { return new Dictionary<cord, IList<LambdaExpression>> { {"ArrayLength", new LambdaExpression[] {(Expression<Func<int[], int>>) (array => array.Length)}} }; } } protected void Application_Start() { Toolchain.Case.Recharge(new CustomFunctionsProvider());
How to cope with values of custom types?
If you need to handle value string extracted from DOM field in any non built-in way, y'all can redefine given type-detection logic. The default mechanism recognizes and handles automatically types identified as: timespan
, datetime
, enumeration
, number
, string
, bool
and guid
. If non of them is matched for a item field, JSON deserialization is invoked. You can provide your own deserializers though. The process is every bit follows:
-
at server-side decorate your holding with special aspect which gives a hint to client-side, which parser should be called for corresponding DOM field value deserialization:
class Model { [ValueParser('customparser')] public CustomType SomeField { become; gear up; }
-
at customer-side register such a parser:
<script> ea.addValueParser('customparser', function(value, field) { // parameters: value - raw data string extracted by default from DOM element // field - DOM chemical element name for which parser was invoked return ... // handle extracted field value cord on your ain });
Finally, at that place is a possibility to override congenital-in conversion globally. In this case, utilize the type name to register your value parser - all fields of such a type will be intercepted by information technology, eastward.g.
<script> ea.addValueParser('typename', function(value) { return ... // handle specified type (numeric, datetime, etc.) parsing on your own });
If you redefine default machinery, you can still take the ValueParser
annotation on whatsoever fields you consider exceptional - annotation gives the highest parsing priority.
How to cope with dates given in non-standard formats?
When values of DOM elements are extracted, they are converted to appropriate types. For fields containing appointment strings, JavaScript Date.parse()
method is used past default. As noted in MDN, the input parameter is:
A string representing an RFC 2822 or ISO 8601 date (other formats may exist used, simply results may be unexpected)
When some non-standard format needs to exist handled, simply override the default behavior and provide your ain implementation. E.thousand. when dealing with United kingdom format dd/mm/yyyy, solution is:
grade Model { [ValueParser('ukdateparser')] public DateTime SomeField { go; set; }
<script> ea.addValueParser('ukdateparser', function(value) { var arr = value.split('/'); var date = new Date(arr[2], arr[1] - 1, arr[0]); return date.getTime(); // return msecs since January 1, 1970, 00:00:00 UTC });
What if "ea" variable is already used past another library?
Utilise noConflict()
method. In instance of naming collision return control of the ea
variable dorsum to its origins. Old references of ea
are saved during ExpressiveAnnotations initialization - noConflict()
but restores them:
<script src="another.js"> </script> <script src="expressive.annotations.validate.js"> </script> <script> var expann = ea.noConflict(); // relinquish EA's control of the `ea` variable expann.addMethod... // practice something with ExpressiveAnnotations ea... // exercise something with original ea variable
How to control frequency of dependent fields validation?
When a field value is modified, validation results for some other fields, directly dependent on currenty modified one, may be affected. To control the frequency of when dependent fields validation is triggered, change default ea.settings.dependencyTriggers
settings. Information technology is a string containing i or more DOM field event types (such as change, keyup or custom event names), associated with currently modified field, for which fields directly dependent on are validated. Multiple event types tin be spring at once by including each 1 separated by a space.
Default value is 'change keyup' (for more information check eventType
parameter of jQuery bind()
method). If you lot want to turn this feature off entirely, set up it to empty cord, zero or undefined (validation will be fired on form submit endeavour only).
<script> ea.settings.dependencyTriggers = 'change'; // mute some excessive action if you wish, // or turn information technology off entirely (set to undefined)
Alternatively, to enforce re-binding of already attached validation handlers, use following construction:
<script> ea.settings.utilise({ dependencyTriggers: 'new set of events' });
Can I increase web console verbosity for debug purposes?
If you need more insightful overview of what client-side script is doing, enable verbose logging:
<script> ea.settings.debug = true; // output debug messages to the web console // (should exist disabled for release code not to introduce redundant overhead)
Warnings and errors are always flushed to the console, no matter this characteristic is enabled or not.
I prefer enum values to be rendered as numbers, is it allowed?
There is a possibility to setup of how enumeration values are internally processed: equally integral numerics or string identifiers - see enumsAsNumbers
settings flag in the script.
This setting should exist consistent with the way of how input fields values are stored in HTML, due east.g. @Html.EditorFor(k => one thousand.EnumValue)
renders to string identifier by default, in contrast to @Html.EditorFor("EnumValue", (int)Model.EnumValue)
argument, where value is explicitly casted to int
. The flag setup should reflect that behavior, to accept the internal JS model context deserialized appropriately.
How to access one method from another?
Through this
. You may want to plough the registerAllMethods
option on. When enabled, EA attempts to register all of the methods within the model context, unless naming conflict with field identifier occurs - registration of such a particular method is and then skipped.
<script> ea.settings.registerAllMethods = true; ea.addMethod('MethodA', office() { ... }); ea.addMethod('MethodB', function() { return this.MethodA(); });
How to access current control from inside a method?
Simply access it through the __meta__
property of this
scope, east.g.
<script> ea.addMethod('Method', function() { var elem = this.__meta__.element; ... });
Alternatively, you lot can pass the field name to the method and then await for information technology, e.one thousand.
[AssertThat("Method('SomeField')")] public string SomeField { get; set; }
<script> ea.addMethod('Method', function(proper noun) { var field = $(':input[name="' + name + '"]') ... });
How to fetch field's value or its display name in error message?
- to get a value, wrap the field proper name in braces, e.g.
{field}
, or for nested fields -{field.field}
, - to get display name, given in
DisplayAttribute
, use additionaln
(orN
) suffix, eastward.1000.{field:n}
.
Notice that {{
is treated equally the escaped subclass character.
Is at that place any event raised when validation is washed?
Each element validated by EA triggers one or more eavalid
events. Attach to this event type in the post-obit manner:
<script> $('grade').find('input, select, textarea').on('eavalid', function(e, type, valid, expr, cond, alphabetize) { console.log('consequence triggered by ' + east.currentTarget.name); });
The parameters are equally follows:
-
type
- type of the aspect for which validation was executed:'requiredif'
or'assertthat'
, -
valid
- state of the validation:true
(passed, i.e. field is either not required, required just value is provided, or assertion is satisfied) orfaux
(failed, i.east. field is either required but value is not provided, or assertion is non satisfied), -
expr
- expression string which was evaluated, -
cond
* - expression evaluation upshot - optional parameter available whenea.settings.optimize
flag is set up tofalse
, otherwiseundefined
, -
index
- validation execution index in a sequence of all attributes (of the same type) to be executed for a detail field: requiredif - 1st (index 0), requiredifa - 2nd (alphabetize ane) ... requiredifz* - last (index n-1).
*where the concluding two parameters are bachelor simply for 'requiredif'
type of validation.
Can I decorate conditionally required fields with asterisks?
EA does non provide whatsoever congenital-in mechanisms to manipulate DOM. Nevertheless, the asterisk ornament (or whatsoever like event) can be relatively easily achieved with the support of a supplementary code you could write for yourself. It will exist based on the eavalid
events handling. Such an event type is triggered past EA when a field validation is performed. Please have a look at the snippet below (or run web sample to come across it working):
<script> ea.settings.optimize = false; // if flag is on, requirement expression is not needlessly evaluated for non-empty fields // otherwise, it is evaluated and such an evaluation result is provided to the eavalid upshot $(document).set up( function() { var selector = 'input, select, textarea'; $('class').find(selector).on('eavalid', role(eastward, blazon, valid, expr, cond, idx) { // verify asterisk visibility based on computed condition if (type === 'requiredif' && cond !== undefined) { if (idx === 0) { // if offset of its kind... due east.currentTarget.eacond = false; // ...reset asterisk visibility flag } e.currentTarget.eacond |= cond; // multiple requiredif attributes can be applied to a single field - remember if whatsoever status is true if (e.currentTarget.eacond) { $(due east.currentTarget).closest('li').find('.asterisk').show(); // show asterisk for required fields (no matter if valid or non) } else { $(e.currentTarget).closest('li').find('.asterisk').hide(); } } }); $('form').detect(selector).each( role() { // apply asterisks for required or conditionally required fields if ($(this).attr('data-val-required') !== undefined // make sure implicit required attributes for value types are disabled i.e. DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false || $(this).attr('data-val-requiredif') !== undefined) { $(this).parent('li').prepend('<span class="asterisk">*</span>'); } }); $('grade').notice(selector).each( function() { // run validation for every field to verify asterisks visibility if ($(this).attr('data-val-requiredif') !== undefined) { $(this).valid(); $(this).removeClass('input-validation-mistake'); $(this).parent().find('.field-validation-fault').empty(); } }); });
For the needs of this case, the code above makes assumptions:
-
virtually the existence of
.asterisk
form in the CSS:.asterisk { color: #ff0000; vertical-marshal: top; margin-left: -10px; float: left; }
-
about specific HTML structure, where input fields are placed between the
<li></li>
tags:<li> <label ... <input data-val=... </li> <li> <label ... <input data-val=... </li>
-
implicit
data-val-required
attributes addition is disabled for value types in HTML (editGlobal.asax
):protected void Application_Start() { DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = simulated;
How to handle validation based on parent model field?
In this case yous need to have a back reference to your container, i.eastward.
public class TParent { public TParent() { Child.Parent = this; } public TChild Kid { get; set up; } public bool Flag { get; ready; } } public class TChild { public TParent Parent { become; set; } // dorsum-reference to parent [RequiredIf("Parent.Flag")] public string IsRequired { go; set; } }
This is all you demand for server-side. Unfortunately, out-of-the-box client-side support of back-references to the parent context is not implemented. EA at client-side is straightforward and designed to handle nested properties when explicitly provided to the view, without abilities to infer any relationships.
There still exists a manner to handle it though. When using HTML helpers at the client-side, the more nested belongings, the more than prefixed name. When reference to container is used in the expression, what customer-side script actually does, it looks for such a holding within the electric current context, i.e. within the fields of names annotated with the current prefix. EA internally has no idea that such a property refers to a field from a container (most likely already existing grade field with different prefix).
In this exemplary instance above, the Flag
property used in the expression Parent.Flag != nada
, makes client-side EA to await for analogic input field within current telescopic, i.eastward. Child.Parent.Flag
. The "Kid." prefix corresponds with what HTML helper prepends to names of nested properties from the Child
object.
The solution is to provide such a field, EA expects to find, i.east.
@Html.HiddenFor(m => m.Child.Parent.Flag) // subconscious mock
Next, make the mocked field clone the beliefs of the original (from parent) i:
<script blazon="text/javascript"> function Mimic(src, dest) { $(src).on(ea.settings.dependencyTriggers, function(e) { $(dest).val($(this).val()); $(dest).trigger(e.blazon); // trigger the change for dependency validation }); } $(certificate).set up( function() { Mimic('input[proper noun="@Html.NameFor(m => m.Flag)"]', 'input[name="@Html.NameFor(thousand => m.Child.Parent.Flag)"]'); }); </script>
Please note, that this slightly hacky workaround is only needed for such a specific cases, where dorsum-references are required to exist handled by client-side EA logic.
RequiredIf attribute is not working, what is wrong?
Make sure RequiredIf
is practical to a field which accepts naught values.
In the other words, it is redundant to apply this attribute to a field of non-nullable value type, like eastward.thousand. int
, which is a struct representing integral numeric type, DateTime
, etc. Because the value of such a type is ever non-null, requirement demand is constantly fulfilled. Instead, for value types utilize their nullable forms, east.g. int?
, DateTime?
, etc.
[RequiredIf("truthful")] // no effect... public int Value { go; ready; } // ...unless int? is used
[RequiredIf("truthful")] // no event... public DateTime Value { get; set up; } // ...unless DateTime? is used
Few fields seem to be bypassed during validation, whatsoever clues?
Well-nigh likely these input fields are subconscious, and :subconscious
fields validation is off by default.
Such a fields are ignored by default past jquery-validation plugin, and EA follows analogic rules. If this is true, endeavor to enable validation for hidden fields (empty-out the ignore filter), i.e.:
<script> $( office() { // DOM needs to be ready... var validator = $('form').validate(); // ...for the form to be institute validator.settings.ignore = ''; // enable validation for ':hidden' fields });
Client-side validation doesn't work, how to troubleshoot it?
- Check whether setup is done correctly, every bit described in the installation section of this certificate.
- Verify if the HTML code generated by the HTML helpers contains all the
information-val-*
attributes used past EA, with correct names (the aforementioned every bit used in related expressions). - Cheque whether jquery.validate.js and jquery.validate.unobtrusive.js are non accidentaly loaded twice on the folio.
- Verify if uncomplicated
Required
aspect works at client-side - if not, it most likely means your event is not related to EA script. - Set EA into debug mode and open up the browser web console (F12). Wait for suspicious EA activity (if whatever) or another JavaScript exceptions which may abort further client-side execution, forcing immediate post-back to the server. The error, if whatever, should appear just earlier sending the request. Delight annotation, if the panel log is not preserved, whatever is recorded there will be cleared on page reload as soon as response arrives.
- Make certain the fields to exist validated are not hidden, otherwise enable validation of hidden fields.
- Check whether attributes are used properly.
- Finally, please take a look at other FAQs, or go across that if solution is yet to be found.
Is there a possibility to perform asynchronous validation?
Currently not. Although in that location is an ongoing work on async-work branch, created especially for asynchronous-related ideas. If you feel y'all'd like to contribute, either by providing better solution, review code or but test what is currently there, your help is ever highly appreciated.
What if my question is not covered by FAQ section?
If you're searching for an reply to another problem, not covered by this document, try to browse through already posted issues labelled by question tag, or possibly have a wait at Stack Overflow.
Installation instructions
Simplest way is using the NuGet Bundle Manager Console:
-
complete package - both assemblies and the script included (allows complete MVC validation):
PM> Install-Package ExpressiveAnnotations
-
minimal package - cadre assembly only (MVC-related client-side coating components excluded):
PM> Install-Parcel ExpressiveAnnotations.dll
Contributors
GitHub Users
Special thank you to Szymon Małczak
License
Copyright (c) 2014 Jarosław Waliszko
Licensed MIT: http://opensource.org/licenses/MIT
Source: https://openbase.com/js/expressive-annotations-validate/documentation
0 Response to "Expressiveannotations Cannot Read Property 'call' of Undefined"
Post a Comment