cancel
Showing results for 
Search instead for 
Did you mean: 

Share form validation handler

chrisokelly
Champ on-the-rise
Champ on-the-rise
Hi,

I am attempting to create a custom form validation handler to check that one date is later than another date. I have attempted so far with information from http://wiki.alfresco.com/wiki/Forms_Developer_Guide, following the tutorial here ->http://www.tribloom.com/blogs/michael/2011/05/03/share-dynamic-forms/. So so far I have, in a jar file at config/alfresco/web-extension/site-webscripts/org/alfresco/components/form/form.get.head.ftl

<@script type="text/javascript" src="${page.url.context}/res/js/formValidation.js"></@script>
in the same jar file at source/web/js/formValidation.js:
/**
* Corporate Document Expiry and Reminder date's validation handler, tests that the expiry date > reminder date.
*
* @method corporateDatesValidation
* @param field {object} The element representing the field the validation is for
* @param args {object} Not used
* @param event {object} The event that caused this handler to be called, maybe null
* @param form {object} The forms runtime class instance the field is being managed by
* @param silent {boolean} Determines whether the user should be informed upon failure
* @param message {string} Message to display when validation fails, maybe null
* @static
*/
Alfresco.forms.validation.corporateDates = function corporateDatesValidation(field, args, event, form, silent, message)
   {
   Alfresco.logger.warn("Validating state of field '" + field.id + "'");
   var valid = true;
   valid = YAHOO.lang.trim(field.value).length !== 0;
   if (valid)
      {
      Alfresco.logger.warn("field value length test passed, checking dates can be parsed");
      // check dates can be parsed
      str_expiryDate = field.form.prop_mcwf_expiryDate.value;
      str_reminderDate = field.form.prop_mcwf_reminderDate.value;
      Alfresco.logger.warn("Expiry Date: " + str_expiryDate + " | Reminder Date: " + str_reminderDate);
      d_expiryDate = Date.parse(str_expiryDate);
      d_reminderDate = Date.parse(str_reminderDate);
      if (d_expiryDate && d_reminderDate)
         {
         Alfresco.logger.warn("Dates Parsed, checking expiry > reminder");
         // check expirydate>reminder date
         valid = d_expiryDate>d_reminderDate;
         Alfresco.logger.warn("The result of the date validation was: " + valid);
         }
      }
      if (!valid && !silent && form)
      {
         // if the keyCode from the event is the TAB or SHIFT keys don't show the error
         if (event && event.keyCode != 9 && event.keyCode != 16 || !event)
         {
            form.addError("Expiry and Review dates are mandatory. Expiry date must be after Review date.", field);
         }
      }

      return valid;
   };
and in my share-config-custom.xml I have:
        <config evaluator="task-type" condition="mcwf:setExpirationTask">
                <forms>
                        <form>
                                <field-visibility>
                                        <show id="mcwf:expiryDate" />
                                        <show id="mcwf:reminderDate" />
                                        <show id="transitions" />
                                </field-visibility>
                                <appearance>
                                        <set id="" appearance="title" label-id="workflow.set.general" />
                                        <set id="other" appearance="title" label-id="workflow.set.other" />
                                        <set id="response" appearance="title" labelid="workflow.set.response" />
                                        <field id="mcwf:expiryDate" set="other">
                                                <constraint-handler>
                                                        <constraint type="MANDATORY" validation-handler="Alfresco.forms.validation.corporateDates" event="keyup" />
                                                </constraint-handler>
                                        </field>
                                        <field id="mcwf:reminderDate" set="other">
                                                <constraint-handler>
                                                        <constraint type="MANDATORY" validation-handler="Alfresco.forms.validation.corporateDates" event="keyup" />
                                                </constraint-handler>
                                        </field>
                                        <field id="transitions" set="response" />
                                </appearance>
                        </form>
                        <form id="workflow-details">
                                <field-visibility>
                                </field-visibility>
                                <appearance>
                                </appearance>
                        </form>
                </forms>
        </config>

I have also tried with event="change" (I thought keyup might not be triggered given the actual date field being hidden above the displayed date entry field), and originally I had mandatory="true" in the fields (only changed this trial and error wise on my last restart).

As you can see, I've riddled the js with logger messages, none of which are generated. Earlier on in share-config-custom.xml I have enabled client debugging, and I can see that it appears the normal date and time validation is being run. (although with firebug I can see that the formValidation.js file is loaded properly)
09:52:34 DEBUG - Determining whether submit elements can be enabled…
09:52:34 DEBUG - Validating mandatory state of field 'page_x002e_data-form_x002e_task-edit_x0023_default_prop_mcwf_expiryDate'
09:52:34 DEBUG - Validating mandatory state of field 'page_x002e_data-form_x002e_task-edit_x0023_default_prop_mcwf_reminderDate'
09:52:34 DEBUG - Validating field 'page_x002e_data-form_x002e_task-edit_x0023_default_prop_mcwf_expiryDate-cntrl-date' has a valid date and time
09:52:34 DEBUG - Validating field 'page_x002e_data-form_x002e_task-edit_x0023_default_prop_mcwf_reminderDate-cntrl-date' has a valid date and time

I get the feeling that the issue is this (I have nothing to back this up other than observed behavior): perhaps date fields don't work so great yet with the extensibility side of Shares validation handlers, likely due to what I mentioned above - the fact that the date field is actually a text input, a hidden input and a javascript control all rolled up, rather than a single input like other fields. As a result (perhaps) when a date field is detected to be mandatory, it automatically uses the date-time validation handler, which could well be the only one which works with the field (and even then, it seems most of the work is done by the inline js changing the class of the field, the validation handler just determines if it has the invalid class).

Am I anywhere near the mark here? Can anyone see a way around this, or possibly just something silly that I've missed?

EDIT: further info, I have tested running from the firebug console the following command:
YAHOO.Bubbling.fire("registerValidationHandler",{fieldId: "page_x002e_data-form_x002e_task-edit_x0023_default_prop_mcwf_expiryDate",handler: Alfresco.forms.validation.corporateDates,when: "onchange"}); 
.

When I do so, the validation handler works fine, so at this point I can confirm the only issue is actually adding it to the field. At this point my thoughts are that I will go with the messy solution, defining a custom field template and including script to run the code above when the page loads, but this seems fairly inelegant to me.
4 REPLIES 4

chrisokelly
Champ on-the-rise
Champ on-the-rise
Initial post was already getting a bit mammoth on edits, so here's the end of my findings. My particular use-case is now working - I won't mark this solved though because to get it working I had to subvert the validation extension point and use a highly dodgy technique to make it work. Right, so:

Adding validation to Date controls in share forms:
No matter what handler is specified in share-config-custom.xml, the validDateTime handler is used (sure do wish that was documented somewhere, the wiki seems to suggest this would work as expected, or at least does not specify any differences between these and other fields for setting validation). To test your validation-handler, you can turn on debug mode in Share (or use firebug's javascript console) and run from the console:
YAHOO.Bubbling.fire("registerValidationHandler",{fieldId: "[FIELD_ID]",handler: [VALIDATION_HANDLER],when: "onchange"});
where [FIELD_ID] is the html id of the field, and [VALIDATION_HANDLER] is the name of your custom validation handler (something like Alfresco.forms.validation.dateValidator). The event is up to you, but as it is a hidden field keyboard and focus based events may not work. onchange seems the best fit for date fields.

That should return false, and will add the handler so you can see if the logic works. if so, you will want to create a custom field control for your date field. You can put this under the site-webscripts directory in web-extension. I just copied the OOTB date control from tomcat/webapps/share/WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/form/controls/date.ftl and made slight modifications. My file (in tomcat/shared/classes/alfresco/web-extension/site-webscripts/org/alfresco/components/form/controls/customeDate.ftl) looks like:

<#if field.control.params.showTime?? && field.control.params.showTime == "true"><#assign showTime=true><#else><#assign showTime=false></#if>
<#if showTime><#assign viewFormat>${msg("form.control.date-picker.view.time.format")}</#assign><#else><#assign viewFormat>${msg("form.control.date-picker.view.date.format")}</#assign></#if>

<#assign disabled=field.disabled>
<#if field.control.params.forceEditable?? && field.control.params.forceEditable == "true">
   <#assign disabled=false>
</#if>

<#assign multiValued=false>
<#if field.value != "" && field.value?index_of(",") != -1>
   <#assign multiValued=true>
</#if>

<#if form.capabilities?? && form.capabilities.javascript?? && form.capabilities.javascript == false><#assign jsDisabled=true><#else><#assign jsDisabled=false></#if>

<div class="form-field">
   <#if form.mode == "view">
      <div class="viewmode-field">
         <#if field.mandatory && field.value == "">
            <span class="incomplete-warning"><img src="${url.context}/res/components/form/images/warning-16.png" title="${msg("form.field.incomplete")}" /><span>
         </#if>
         <span class="viewmode-label">${field.label?html}:</span>
         <span class="viewmode-value">
         <#if field.value == "">
            ${msg("form.control.novalue")}
         <#elseif !multiValued>
            ${xmldate(field.value)?string(viewFormat)}
         <#else>
            <#list field.value?split(",") as dateEl>
               ${xmldate(dateEl)?string(viewFormat)}<#if dateEl_has_next>,</#if>
            </#list>
         </#if>
         </span>
      </div>
   <#elseif !multiValued>
      <#if jsDisabled>
         <label for="${fieldHtmlId}">${field.label?html}:<#if field.mandatory><span class="mandatory-indicator">${msg("form.required.fields.marker")}</span></#if></label>
         <input id="${fieldHtmlId}" name="${field.name}" type="text" class="date-entry" value="${field.value?html}" <#if field.description??>title="${field.description}"</#if> <#if disabled>disabled="true"<#else>tabindex="0"</#if> />
         <div class="format-info">
            <span class="date-format">${msg("form.control.date-picker.entry.datetime.format.nojs")}</span>
         </div>
      <#else>
         <#assign controlId = fieldHtmlId + "-cntrl">

         <script type="text/javascript">//<![CDATA[
         (function()
         {
            new Alfresco.DatePicker("${controlId}", "${fieldHtmlId}").setOptions(
            {
               <#if form.mode == "view" || disabled>disabled: true,</#if>
               currentValue: "${field.value?js_string}",
               showTime: ${showTime?string},
               mandatory: ${field.mandatory?string}
            }).setMessages(
               ${messages}
            );
         })();
         //]]></script>

         <input id="${fieldHtmlId}" type="hidden" name="${field.name}" value="${field.value?html}" />

         <label for="${controlId}-date">${field.label?html}:<#if field.mandatory><span class="mandatory-indicator">${msg("form.required.fields.marker")}</span></#if></label>
         <input id="${controlId}-date" name="-" type="text" class="date-entry" <#if field.description??>title="${field.description}"</#if> <#if disabled>disabled="true"<#else>tabindex="0"</#if> />

         <#if disabled == false>
            <a id="${controlId}-icon"><img src="${url.context}/res/components/form/images/calendar.png" class="datepicker-icon" tabindex="0"/></a>
         </#if>

         <div id="${controlId}" class="datepicker"></div>

         <#if showTime>
            <input id="${controlId}-time" name="-" type="text" class="time-entry" <#if field.description??>title="${field.description}"</#if> <#if disabled>disabled="true"<#else>tabindex="0"</#if> />
         </#if>

         <@formLib.renderFieldHelp field=field />

         <div class="format-info">
            <span class="date-format">${msg("form.control.date-picker.display.date.format")}</span>
            <#if showTime><span class="time-format<#if disabled>-disabled</#if>">${msg("form.control.date-picker.display.time.format")}</span></#if>
         </div>



         <script type="text/javascript">//<![CDATA[
         setTimeout(function(){YAHOO.Bubbling.fire("registerValidationHandler",{fieldId: "${fieldHtmlId}",handler: Alfresco.forms.validation.corporateDates,when: "onchange"});},2000);
         //]]></script>



      </#if>
   </#if>
</div>


I've used some line breaks to make the major change obvious. Note the use of the setTimeout function; my plan originally was to just insert the first command from above to add validation handling, however this is run too early, before the YUI fields have been registered. In this case the setTimeout sets up validation 2 seconds after the page is loaded.

then set the forms config in share-config-custom.xml to use the new template for the field in question (information on this in the forms wiki page).

I'd still be more than glad to hear that this is the stupid way to do it and that yes, as a matter of fact, the date/time fields in share forms are easily configured via the normal extension point.

alhol
Champ in-the-making
Champ in-the-making
Hi, I think i know why you cant register your custom validation. You missed a letter "S" at the end of <constraint-handlerS> in share-config. I've done all the things you've described in 1st post and it all works for me.

EDIT
I'm sorry, in my case it works only with basic content field, not date picker. Now the sitiation is the same as yours.

aitbenmouh
Champ in-the-making
Champ in-the-making
Hello i tested your solution then im not able to validate my date input by ftl controle is it working for you chrisokelly ?

stacy
Champ on-the-rise
Champ on-the-rise
Hello,
I am facing the similar issue with the date validation.

Could any body here please help me solve this issue, after performing all the steps mentioned in docs and forum i am still not able to see the validation effect on my fields.its not displaying the message if the validation fails.
Alfresco version:5.0

Regards