I am in the process of developing a unique Dojo ValidationIdBox widget that extends from ValidationTextBox. The main feature of my custom widget is that it includes asynchronous duplicate ID verification with a backend server.
By extending dijit.form.ValidationTextBox and making adjustments to the isValid() and validate() methods, I have encountered an issue with the validation behavior. While the widget successfully detects and alerts missing required input or a duplicate ID (with the tooltip showing), it fails to highlight the field as expected.
To diagnose the problem, I have created a simplified code snippet below that closely resembles the original Dojo code with minor modifications. My approach involves running standard ValidationTextBox validation first, followed by a check for duplicate IDs. Currently, the uniqueness test intentionally returns failure.
Similarly, I have made changes to the validate() method to perform normal validation before additional processing if the regular validation passes but the uniqueness validation fails. Although I attempted to replicate the same styling logic used when the ValidationTextBox is in error state, the visual effects do not match up: The 'ID not available' tooltip appears, yet the red outline with an exclamation mark does not display.
While examining ValidationTextBox's source code, I was unable to discern how the specific styling triggers work... Can anyone provide insight into how ValidationTextArea operates? In particular, I am unsure about the utilization of this._maskValidSubsetError
, aria-invalid
, and this.state
.
(Additionally, there are instances where I want the tooltip to appear without the red styling, such as during AJAX duplicate ID check request processing.)
// If ValidationTextBox Validates
isValid: function(isFocused, requireUnique) {
if (typeof requireUnique === 'undefined') requireUnique = false;
var isValid = this.inherited(arguments);
var isUnique = false;
return (requireUnique ? (isValid && isUnique) : isValid);
},
validate: function(/*Boolean*/ isFocused){
// summary:
// Called by on init, on blur, and on keypress.
// description:
// Show missing or invalid messages if appropriate, and highlight the textbox field.
// tags:
// protected
var message = "";
var isValid = this.disabled || this.isValid(isFocused);
if(isValid){
this._maskValidSubsetError = true;
}
var isEmpty = this._isEmpty(this.textbox.value);
var isValidSubset = !isValid && isFocused && this._isValidSubset();
this._set("state", isValid ? "" : (((((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "Incomplete" : "Error"));
this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
if(this.state == "Error"){
this._maskValidSubsetError = isFocused && isValidSubset;
message = this.getErrorMessage(isFocused);
}else if(this.state == "Incomplete"){
message = this.getPromptMessage(isFocused);
this._maskValidSubsetError = !this._hasBeenBlurred || isFocused;
}else if(isEmpty){
message = this.getPromptMessage(isFocused);
}
/// Begin custom widget code
if (isValid && !this.isValid(isFocused, true)) {
isValid = false;
var isValidSubset = !isValid && isFocused && this._isValidSubset();
this._maskValidSubsetError = isFocused && isValidSubset;
message = 'ID not available';
this.focusNode.setAttribute("aria-invalid", isValid ? "false" : "true");
}
/// End custom widget code
this.set("message", message);
return isValid;
},