[ 
https://issues.apache.org/struts/browse/SHALE-490?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jeff Tsay updated SHALE-490:
----------------------------

    Description: 
I'd like to see the ability to override the validation error 
handler. Currently, with the default validatorUtilities.js, whenever a 
validation error occurs, an alert is displayed. To me that is a bit 
unpolished; I'd rather see some message below the input field that has 
an error. Although it's easy enough to replace validatorUtilities.js, 
jcv_handleError() simply doesn't get enough information in its arguments 
to do much with the DOM tree, unless the ID's of the elements to replace 
are hardcoded. It would be good also to let the user supply his own 
error handling script in the JSF tags, instead of messing with replacing 
validatorUtilities (which would be apply across the entire web app 
anyway). Any ideas on how to do this? Is anyone else interested in 
getting rid of alert()?

---
April 21, 2008
I have a solution that works. I add two properties, clientErrorHandler and 
clientErrorHandlerData to the ValidatorScript tag and the ValidatorTag. In the 
Javascript validation routines in Commons Validator, jcv_handleError() is 
always called with 2nd element of 
2nd element of the 3 element array representing a field to be validated.  To 
avoid changing the Common Validator code, I added the clientErrorHandler and 
clientErrorHandlerData properties to the 2nd element. The 2nd element is 
usually the error message, so I moved that into a property of a hash becomes 
the new 2nd element. So the relevant code in ValidatorScript is:

BEFORE

     writer.write("new Array(\"");
      writer.write(id);
      writer.write("\", \"");
      writer.write(v.getErrorMessage(context, validatorAction, localVars));
      writer.write("\", new Function(\"x\", \"return {");

AFTER

     writer.write("new Array(\"");
      writer.write(id);
      writer.write("\", {\"msg\":\"");
      writer.write(v.getErrorMessage(context, validatorAction, localVars));
      writer.write("\"");
      
      String clientErrorHandler = v.getClientErrorHandler();
      
      if (clientErrorHandler != null) {
          writer.write(",\"errorHandler\":\"");
          writer.write(clientErrorHandler);
          writer.write("\"");
      }
      
      String clientErrorHandlerData = v.getClientErrorHandlerData();
        
      if (clientErrorHandlerData != null) {
         writer.write(",\"errorHandlerData\":\"");
         writer.write(escapeJavascript(clientErrorHandlerData));
         writer.write("\"");
      }

       writer.write("}, new Function(\"x\", \"return {");

Then I needed to change validatorUtilities.js so that the error handler can get 
the old message and also call the client error handler routines if defined:

BEFORE:

 /**
   * Handle error messages.
   * @param messages Array of error messages.
   * @param focusField Field to set focus on.
   */
  function jcv_handleErrors(messages, focusField) {
      if (focusField && focusField != null) {
          var doFocus = true;
          if (focusField.disabled || focusField.type == 'hidden') {
              doFocus = false;
          }
          if (doFocus && 
              focusField.style && 
              focusField.style.visibility &&
              focusField.style.visibility == 'hidden') {
              doFocus = false;
          }
          if (doFocus) {
              focusField.focus();
          }
      }
      alert(messages.join('\n'));
  }

AFTER:

/**
   * Handle error messages.
   * @param instructions Array of instructions on how to handle
     validation errors.
   * @param focusField Field to set focus on.
   */
  function jcv_handleErrors(instructions, focusField) {
      if (focusField && focusField != null) {
          var doFocus = true;
          if (focusField.disabled || focusField.type == 'hidden') {
              doFocus = false;
          }
          if (doFocus && 
              focusField.style && 
              focusField.style.visibility &&
              focusField.style.visibility == 'hidden') {
              doFocus = false;
          }
          if (doFocus) {
              focusField.focus();
          }
      }
      
      var anyHandlersCalled = false;
      var messages = [];
      
      for (var i = 0; i < instructions.length; i++) {
        var instruction = instructions[i];
        
        var msg = instruction['msg'];
        messages.push(msg);
        
        var handlerName = instruction['errorHandler'];
      
        if (handlerName) {
            var handlerDataString = instruction['errorHandlerData'];
          
            if (!handlerDataString) {
               handlerDataString = "{}";
            }
          
            eval(handlerName + '(' + handlerDataString + ', focusField, 
msg);'); 
          
            anyHandlersCalled = true;
        }      
      }
      
      if (!anyHandlersCalled)
      {
          alert(messages.join('\n'));
      }
  }

So the alert is only triggered if no error handler for any of the error fields 
was defined (so old pages will continue to work as usual).

The errorHandlerData property is meant to be flexible, in that it can represent 
a variable reference, a JSON expression, or a list of expressions. Examples 
could be "'emailerrormsgid'" or "{'id' : 'someid'}" or "'emailmsgid', foo" 
(where foo would be variable defined in the Javascript for the page.

The error handler function gets the errorHandlerData as the first argument(s), 
the field to focus on (from which it can pull out the value that caused the 
error), and the error message. I think that should be enough information to 
handle the error.

An example usage would be:

<val:commonsValidator type="required" 
   arg="#{commonBundle.username}" server="true" client="true"
   clientErrorHandler="handleValidationError"  
clientErrorHandlerData="'usererrorid'" /> 

<div id="usererrorid" />


<script>

function handleValidationError(id, field, msg)
{
  var d =  document.getElementById(id);

  d.innerHTML = '<p>' + msg + '</p>';
}

I will attached the changed files (based on Shale 1.0.4). Please review.

4/21/2008 (again)
Darn, I didn't mean to attach ValidatorVarTag.java. It's unchanged. Please 
ignore.

  was:
I'd like to see the ability to override the validation error 
handler. Currently, with the default validatorUtilities.js, whenever a 
validation error occurs, an alert is displayed. To me that is a bit 
unpolished; I'd rather see some message below the input field that has 
an error. Although it's easy enough to replace validatorUtilities.js, 
jcv_handleError() simply doesn't get enough information in its arguments 
to do much with the DOM tree, unless the ID's of the elements to replace 
are hardcoded. It would be good also to let the user supply his own 
error handling script in the JSF tags, instead of messing with replacing 
validatorUtilities (which would be apply across the entire web app 
anyway). Any ideas on how to do this? Is anyone else interested in 
getting rid of alert()?

---
April 21, 2008
I have a solution that works. I add two properties, clientErrorHandler and 
clientErrorHandlerData to the ValidatorScript tag and the ValidatorTag. In the 
Javascript validation routines in Commons Validator, jcv_handleError() is 
always called with 2nd element of 
2nd element of the 3 element array representing a field to be validated.  To 
avoid changing the Common Validator code, I added the clientErrorHandler and 
clientErrorHandlerData properties to the 2nd element. The 2nd element is 
usually the error message, so I moved that into a property of a hash becomes 
the new 2nd element. So the relevant code in ValidatorScript is:

BEFORE

     writer.write("new Array(\"");
      writer.write(id);
      writer.write("\", \"");
      writer.write(v.getErrorMessage(context, validatorAction, localVars));
      writer.write("\", new Function(\"x\", \"return {");

AFTER

     writer.write("new Array(\"");
      writer.write(id);
      writer.write("\", {\"msg\":\"");
      writer.write(v.getErrorMessage(context, validatorAction, localVars));
      writer.write("\"");
      
      String clientErrorHandler = v.getClientErrorHandler();
      
      if (clientErrorHandler != null) {
          writer.write(",\"errorHandler\":\"");
          writer.write(clientErrorHandler);
          writer.write("\"");
      }
      
      String clientErrorHandlerData = v.getClientErrorHandlerData();
        
      if (clientErrorHandlerData != null) {
         writer.write(",\"errorHandlerData\":\"");
         writer.write(escapeJavascript(clientErrorHandlerData));
         writer.write("\"");
      }

       writer.write("}, new Function(\"x\", \"return {");

Then I needed to change validatorUtilities.js so that the error handler can get 
the old message and also call the client error handler routines if defined:

BEFORE:

 /**
   * Handle error messages.
   * @param messages Array of error messages.
   * @param focusField Field to set focus on.
   */
  function jcv_handleErrors(messages, focusField) {
      if (focusField && focusField != null) {
          var doFocus = true;
          if (focusField.disabled || focusField.type == 'hidden') {
              doFocus = false;
          }
          if (doFocus && 
              focusField.style && 
              focusField.style.visibility &&
              focusField.style.visibility == 'hidden') {
              doFocus = false;
          }
          if (doFocus) {
              focusField.focus();
          }
      }
      alert(messages.join('\n'));
  }

AFTER:

/**
   * Handle error messages.
   * @param instructions Array of instructions on how to handle
     validation errors.
   * @param focusField Field to set focus on.
   */
  function jcv_handleErrors(instructions, focusField) {
      if (focusField && focusField != null) {
          var doFocus = true;
          if (focusField.disabled || focusField.type == 'hidden') {
              doFocus = false;
          }
          if (doFocus && 
              focusField.style && 
              focusField.style.visibility &&
              focusField.style.visibility == 'hidden') {
              doFocus = false;
          }
          if (doFocus) {
              focusField.focus();
          }
      }
      
      var anyHandlersCalled = false;
      var messages = [];
      
      for (var i = 0; i < instructions.length; i++) {
        var instruction = instructions[i];
        
        var msg = instruction['msg'];
        messages.push(msg);
        
        var handlerName = instruction['errorHandler'];
      
        if (handlerName) {
            var handlerDataString = instruction['errorHandlerData'];
          
            if (!handlerDataString) {
               handlerDataString = "{}";
            }
          
            eval(handlerName + '(' + handlerDataString + ', focusField, 
msg);'); 
          
            anyHandlersCalled = true;
        }      
      }
      
      if (!anyHandlersCalled)
      {
          alert(messages.join('\n'));
      }
  }

So the alert is only triggered if no error handler for any of the error fields 
was defined (so old pages will continue to work as usual).

The errorHandlerData property is meant to be flexible, in that it can represent 
a variable reference, a JSON expression, or a list of expressions. Examples 
could be "'emailerrormsgid'" or "{'id' : 'someid'}" or "'emailmsgid', foo" 
(where foo would be variable defined in the Javascript for the page.

The error handler function gets the errorHandlerData as the first argument(s), 
the field to focus on (from which it can pull out the value that caused the 
error), and the error message. I think that should be enough information to 
handle the error.

An example usage would be:

<val:commonsValidator type="required" 
   arg="#{commonBundle.username}" server="true" client="true"
   clientErrorHandler="handleValidationError"  
clientErrorHandlerData="'usererrorid'" /> 

<div id="usererrorid" />


<script>

function handleValidationError(id, field, msg)
{
  var d =  document.getElementById(id);

  d.innerHTML = '<p>' + msg + '</p>';
}

I will attached the changed files (based on Shale 1.0.4). Please review.


> Want alternative ways of informing user of validation failure
> -------------------------------------------------------------
>
>                 Key: SHALE-490
>                 URL: https://issues.apache.org/struts/browse/SHALE-490
>             Project: Shale
>          Issue Type: Improvement
>          Components: Validator
>    Affects Versions: 1.0.4
>         Environment: Any
>            Reporter: Jeff Tsay
>         Attachments: CommonsValidator.java, taglib.tld, validateUtilities.js, 
> ValidatorScript.java, ValidatorTag.java, ValidatorVarTag.java
>
>
> I'd like to see the ability to override the validation error 
> handler. Currently, with the default validatorUtilities.js, whenever a 
> validation error occurs, an alert is displayed. To me that is a bit 
> unpolished; I'd rather see some message below the input field that has 
> an error. Although it's easy enough to replace validatorUtilities.js, 
> jcv_handleError() simply doesn't get enough information in its arguments 
> to do much with the DOM tree, unless the ID's of the elements to replace 
> are hardcoded. It would be good also to let the user supply his own 
> error handling script in the JSF tags, instead of messing with replacing 
> validatorUtilities (which would be apply across the entire web app 
> anyway). Any ideas on how to do this? Is anyone else interested in 
> getting rid of alert()?
> ---
> April 21, 2008
> I have a solution that works. I add two properties, clientErrorHandler and 
> clientErrorHandlerData to the ValidatorScript tag and the ValidatorTag. In 
> the Javascript validation routines in Commons Validator, jcv_handleError() is 
> always called with 2nd element of 
> 2nd element of the 3 element array representing a field to be validated.  To 
> avoid changing the Common Validator code, I added the clientErrorHandler and 
> clientErrorHandlerData properties to the 2nd element. The 2nd element is 
> usually the error message, so I moved that into a property of a hash becomes 
> the new 2nd element. So the relevant code in ValidatorScript is:
> BEFORE
>      writer.write("new Array(\"");
>       writer.write(id);
>       writer.write("\", \"");
>       writer.write(v.getErrorMessage(context, validatorAction, localVars));
>       writer.write("\", new Function(\"x\", \"return {");
> AFTER
>      writer.write("new Array(\"");
>       writer.write(id);
>       writer.write("\", {\"msg\":\"");
>       writer.write(v.getErrorMessage(context, validatorAction, localVars));
>       writer.write("\"");
>       
>       String clientErrorHandler = v.getClientErrorHandler();
>       
>       if (clientErrorHandler != null) {
>           writer.write(",\"errorHandler\":\"");
>           writer.write(clientErrorHandler);
>           writer.write("\"");
>       }
>       
>       String clientErrorHandlerData = v.getClientErrorHandlerData();
>         
>       if (clientErrorHandlerData != null) {
>          writer.write(",\"errorHandlerData\":\"");
>          writer.write(escapeJavascript(clientErrorHandlerData));
>          writer.write("\"");
>       }
>        writer.write("}, new Function(\"x\", \"return {");
> Then I needed to change validatorUtilities.js so that the error handler can 
> get the old message and also call the client error handler routines if 
> defined:
> BEFORE:
>  /**
>    * Handle error messages.
>    * @param messages Array of error messages.
>    * @param focusField Field to set focus on.
>    */
>   function jcv_handleErrors(messages, focusField) {
>       if (focusField && focusField != null) {
>           var doFocus = true;
>           if (focusField.disabled || focusField.type == 'hidden') {
>               doFocus = false;
>           }
>           if (doFocus && 
>               focusField.style && 
>               focusField.style.visibility &&
>               focusField.style.visibility == 'hidden') {
>               doFocus = false;
>           }
>           if (doFocus) {
>               focusField.focus();
>           }
>       }
>       alert(messages.join('\n'));
>   }
> AFTER:
> /**
>    * Handle error messages.
>    * @param instructions Array of instructions on how to handle
>      validation errors.
>    * @param focusField Field to set focus on.
>    */
>   function jcv_handleErrors(instructions, focusField) {
>       if (focusField && focusField != null) {
>           var doFocus = true;
>           if (focusField.disabled || focusField.type == 'hidden') {
>               doFocus = false;
>           }
>           if (doFocus && 
>               focusField.style && 
>               focusField.style.visibility &&
>               focusField.style.visibility == 'hidden') {
>               doFocus = false;
>           }
>           if (doFocus) {
>               focusField.focus();
>           }
>       }
>       
>       var anyHandlersCalled = false;
>       var messages = [];
>       
>       for (var i = 0; i < instructions.length; i++) {
>         var instruction = instructions[i];
>         
>         var msg = instruction['msg'];
>         messages.push(msg);
>         
>         var handlerName = instruction['errorHandler'];
>       
>         if (handlerName) {
>             var handlerDataString = instruction['errorHandlerData'];
>           
>             if (!handlerDataString) {
>                handlerDataString = "{}";
>             }
>           
>             eval(handlerName + '(' + handlerDataString + ', focusField, 
> msg);'); 
>           
>             anyHandlersCalled = true;
>         }      
>       }
>       
>       if (!anyHandlersCalled)
>       {
>           alert(messages.join('\n'));
>       }
>   }
> So the alert is only triggered if no error handler for any of the error 
> fields was defined (so old pages will continue to work as usual).
> The errorHandlerData property is meant to be flexible, in that it can 
> represent a variable reference, a JSON expression, or a list of expressions. 
> Examples could be "'emailerrormsgid'" or "{'id' : 'someid'}" or 
> "'emailmsgid', foo" (where foo would be variable defined in the Javascript 
> for the page.
> The error handler function gets the errorHandlerData as the first 
> argument(s), the field to focus on (from which it can pull out the value that 
> caused the error), and the error message. I think that should be enough 
> information to handle the error.
> An example usage would be:
> <val:commonsValidator type="required" 
>    arg="#{commonBundle.username}" server="true" client="true"
>    clientErrorHandler="handleValidationError"  
> clientErrorHandlerData="'usererrorid'" /> 
> <div id="usererrorid" />
> <script>
> function handleValidationError(id, field, msg)
> {
>   var d =  document.getElementById(id);
>   d.innerHTML = '<p>' + msg + '</p>';
> }
> I will attached the changed files (based on Shale 1.0.4). Please review.
> 4/21/2008 (again)
> Darn, I didn't mean to attach ValidatorVarTag.java. It's unchanged. Please 
> ignore.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to