Complex Validations

A couple of days ago, Michael Ramirez “asked me”:http://blogs.adobe.com/formbuilder/2006/08/invalid_flashing_fields_2.html#comments how to do complex validations on forms. He asked how one could have a validation as follows: Given 3 text fields A, B and C and a check box E, A is mandatory only if B and C are filled or if E is checked. I thought this would make a great little sample of both complex validation scripts and what I like to call the “Two Button Submit” technique.

“Download Sample [pdf]”:http://blogs.adobe.com/formbuilder/samples/ComplexValidations.pdf

*Minimum Requirements:* Designer 7.x, Acrobat 7.x.


h2. The PlanFirst, let’s figure-out what the plan is before we start scripting. The idea is to place these fields on a new form along with a submit button such that the user cannot submit the form unless the validation rules succeed. Since Field A isn’t always mandatory, we can’t default it to be _User Entered — Required_ by using the Value tab in the Object palette. We’ll need a way to make it required only when Fields B & C are filled or when Field E is checked. Furthermore, we don’t want the form’s data to be submitted unless these rules are met.The easiest solution that comes to mind is one that’s passive as the user is entering data into the fields but aggressive at the point when they try to submit it by putting the validation script on the submit button’s Click event. The catch here is that there’s no way of stopping the submission process once the Click event has fired so regardless of whether your validation succeeds or fails, the form is going to be submitted. That’s where the “Two Button Submit” technique comes-in to save the day.h2. “Two Button Submit” TechniqueThankfully, there’s a scripting method called _execEvent_ that lets you programmatically cause an event to be executed on a field. With this in mind, you place a regular (non-submit type) button on the form, make it visible and set its caption to read something like, “Submit”. Then you place the _actual_ submit button (could be email, HTTP or even print) on the form and make it _invisible_. Please note: make it *invisible*, not hidden or else the _execEvent_ call on it will fail because Acrobat won’t know it exists in the XFA Scripting Model. For this example, let’s call it “EmailSubmitButton”.Now that both buttons are on the form, in the regular (fake submit) button’s Click event, put the following script (FormCalc or JavaScript works just the same):bc. EmailSubmitButton.execEvent(“click”);With that script, when you click on the fake submit button, you’ll cause the Click event on the actual submit button to fire and the fake submit button will, to the user, behave just like a normal submit button.The advantage of this is that you now control if and when the real submit button’s Click event is executed and therefore if and when the form is submitted.If you were to add the following JavaScript statement before the _execEvent_ line:bc. if (FieldA.rawValue != null && FieldA.rawValue.length > 0)the form wouldn’t submit unless Field A was filled.h2. Validations Prior to SubmittingUsing the “Two Button Submit” technique, we can now perform any kind of validations — really simple to very complex — we want and have total control over if and when the form may be submitted.Given our example of fields A, B, C and E, we can do something like this:bc.. var bCanSubmit = true;if ( (IsSpecified(FieldB) && IsSpecified(FieldC)) ||IsChecked(FieldE) ){if (!IsSpecified(FieldA)){xfa.host.messageBox(“Please fill Field A.”);bCanSubmit = false;}}if (bCanSubmit)EmailSubmitButton1.execEvent(“click”); // submit the formp. This will prevent the form from being submitted if Field A isn’t filled when Fields B & C are filled or Check Box E is checked.

23 Responses to Complex Validations

  1. smvo says:

    Stefan,I was looking for a discussion topic similar to my question, and I hope this is the right one.I was trying to find out why the number of digits that one can enter in a numeric field is always different from that indicated with the leaddigits? (is indiferent if we use Designer 7.0 or 7.1)For instance, if I make this:this.value.decimal.leadDigits = “1”;I will be able to write 4 digits in the fieldIf I make this:this.value.decimal.leadDigits = “3”;I will be able to write 6 digits in the field… and not 3This difference depends on what? decimal places? (counting with the decimal separator).My problem with this is that when one inserts more digits than those specified by the leaddigit (for instance 4 instead of 3 without decimal places), the value will not be accepted and I don´t see where I can get that value if it is not accepted.I need that value because I shouldn´t just not accept the new value without telling the user that the value he entered as not been accepted.The rawvalue in this condition is still the previous value on the field… Maybe there is an uncommited value that I can get?Thank you!smvo

  2. smvo,The use of the leadDigits and fracDigits on the <decimal> value type can be a little confusing.As far as Acrobat is concerned, it looks at the leadDigits and fracDigits and combines them, including the decimal character, to create a maximum length for the field.Since the default value for decimal.fracDigits is 2, when you specifydecimal.leadDigits = 3;, Acrobat sets a maximum length of (3 lead digits + 1 decimal character + 2 frac digits) 6 characters for that field.When the user is entering the value into the field, it doesn’t prevent them from entering a value that violates the lead and frac digit settings. Rather, it simply discards entries which don’t match the lead and frac digit settings, which is why you can enter “123.45”, “123456”, “1234.5”, “12345.” and prior to not being able to type characters any longer while “123.45” would be the only one accepted/committed by Acrobat. Is it the best user experience “out of the box”? Certainly not!Luckily, the Change event can help you out in this case because it occurs every time a key is pressed on the keyboard, regardless of whether the character gets entered into the field or not. In that event, you can see what value the user is entering as they enter it by accessing thexfa.event.newTextproperty. If you then store that value into a Form Variable (see Form Variable Tip for information on using Form Variables in scripts), you could look at the entered value in the Exit event (which occurs when the Enter or Tab key is pressed, after the value is committed to the field). By comparing the saved value with this.rawValue and doing a little bit of parsing against the saved value given decimal.leadDigits and decimal.fracDigits, you should be able to determine if the value committed was the same as the value entered and display an error message using thexfa.host.messageBoxfunction.

  3. smvo says:

    Stefan,That was what I needed!Thank you!

  4. Alessio says:

    Sorry for the question, that I think it’s very stupid, but not so stupid to make me find a solution.How is it possible to implement the same kind of validations that are automatic when there is a submit botton in the case I have a execute button?I submit data to a WebService, but even if I made some fields mandatory, when I press the button I send the data without any kind of validation.Thanks for helping,Alessio

  5. Alessio,I believe you should still be able to use the “Two Button Submit” Technique which I described in this article: Just make your actual execute button invisible and use the click event of a regular button to trigger the click event of the execute button once you’ve completed all validations in the regular button’s Click event.

  6. Jo says:

    Stefan,I’ve implemented your “two button submit” technique in my pdf form but I got a “ReferenceError: EmailSubmitButton is not defined” when the validation function succeeds. I’ve double-checked my 2nd button properties and the name is correct (same characters, same case, form field visible). Any idea?Btw, I’m still using Acrobat 6.1 Pro, could it be the source of the problem?Tx.– Jo

  7. Jo,I don’t believe Acrobat 6.1 would be the problem. The script required to make the “two button technique” work should be supported in that version of Acrobat.You error sounds more like a syntax error or a scoping problem to me. You say you’ve verified that the name of the submit button is, in fact, “EmailSubmitButton”. You should therefore be accessing it using the following script in another button’s Click event:EmailSubmitButton.execEvent(“click”);If this isn’t working, then is it possible that the email submit button is in a separate container? If it’s not a sibling to the other (regular) button in the form’s hierarchy (see the Hierarchy palette), then you’ll have to access its container prior to accessing the email submit button itself. For example, if it was on the page itself at the top and the regular button you’re using to do the validation and execute the email submit button’s Click event is located on a subform one level deep from the page, then you would have to write the following script (shown here in JavaScript):this.parent.EmailSubmitButton.execEvent(“click”);

  8. John Nesbitt says:

    Stefan,Is it possible to change the target URL of the submit button at runtime?We have different development environments (Dev, UAT, Prod) and would like to be able to set the submit button’s URL property to the current environment’s endpoint.It would be nice if the URL property was a dynamic property but it doesn’t seem to be in Designer 7.1.Thanks,John.

  9. John,It’s certainly possible to change the target URL of a submit button at runtime — you just need to know a little about XFA in order to do it.Essentially, submit buttons are regular buttons which have a Click event (<event activity=”click”>) with a <submit> node as its one-of property. The submit node is where you’ll find the “target” property which you can use to modify the target URL.Here’s a JavaScript script that you can use to set the target URL of a submit button:var oEventList = SubmitBtn.resolveNodes(“#event”);for (var i = 0; i < oEventList.length; i++){  var oEventNode = oEventList.item(i);  if (oEventNode.activity == “click”)  {    oEventNode.resolveNode(“#submit”).target = “new URL”;    break;  }}

  10. John Nesbitt says:

    Stefan,Awesome – it worked perfectly!Thanks for your help,John.

  11. Chalmal says:

    Dear Stefan,I have the same requirement. I’m using Designer 7.0. I tried the same. But, have some issues.Kindly clarify more details on the above Javascript. Which button should we use? Http Submit button? Also, in which event of the button, we have to add the Javascript?Thanks,Chalmal.

  12. Chalmal says:

    Dear Stefan,Thx. Now it’s working. I have put this code in normal Submit click event and executed the event of HttpSubmit button. It’s working fine. Thx. for your information.But I have few more requirements. I need to restrict the input (key-in) into the Text fields (like allow only numerics, characters, or dates…).More details are as follows:I’m using Adobe Professional – Live cycle designer 7.0 to design pdf form. Also, I’m using an existing pdf (supplied by the customer), which is designed through teleform designer (with adobe 6.0) model for this design. In the existing one, the javascript methods are working fine for restricting keys, validation, etc. But these scripts are not working in designer as the designer is using XFA model.For eg. a function used in the teleform version:function TFTemplate_KeyStroke( mask ){if (event.willCommit) {return;}var value = AFMergeChange( event );if (!mask.test( value )) {event.rc = false;app.beep( 0 );}}I’m trying to restrict the key inputs (like only numbers/characters should be entered). But I couldn’t find the equivalent statements for some of the statements (which are used in the teleform pdf).For eg.event.rc = true. – Allows keystroke to be added to entry. – event.rc = false. – Prevents keystroke being added to entry in the following function:I couldn’t find the matching statements in Designer for event.willCommit, AFMergeChange(),event.rc, etc.If I get, I can restrict the inputs.Expecting any solutions from you…Thanks in Advance…Chalmal

  13. Chalmal,Fortunately, it should be possible for you to limit the characters that can be entered into a field. It won’t necessarily be as easy as the script you’ve quoted but you should be able to achieve similar functionality.The trick lies in using the change property of the xfa.event object (available in all XFA events) in the Change event.This property behaves slightly differently depending on the type of field you’re using. For this explanation, I’ll assume we’re talking about a text field.Every time a character is entered into a text field, the Change event fires. The xfa.event.change property then contains the character that was typed into the field and which will be added to the field’s current value. If this property is set to an empty string, no character is appended to the field’s value.Knowing this, you could, say, prevent the user from entering the character “a” into a text field with this simple script in the text field’s Change event:

    if (xfa.event.change == “a”)   xfa.event.change = “”;

    You may also find it useful to use the xfa.event.newText property which, in the Change event, contains the entire new text to be set in the text field. This means that as you type, “a”, then “s”, then “d”, the newText property has the following values, in sequential calls to the Change event: “a”, “as”, “asd”.Note that if the user erases a character, both the newText and change properties will be empty strings.

  14. Angelo Veraldi says:

    Hi Stefan – I’ve been researching the adobe forums regarding my issue and have found your posts helpful, though they pertain to a slighlty different situation than my own.Using your Highlight Required Field document as reference: I have a series of exclusive groups of radio buttons. Instead of printing the form after validating user input for these groups, I would like the data to be emailed (xml or pdf w/ digital signature). I have seen your posts regarding the two button submit technique but am not sure how to alter the code to still validate the groups/buttons, then trigger the click event to submit.I am not an experienced LiveCycle user, so I have pieced my form together from examples that partially address my needs.I have even inquired to companies I have seen online to have them produce my form based on a static pdf version of it to no avail. They don’t even respond my initial inquiry. I am willing to pay someone to help me…please.Thanks…

  15. Angelo,I’m sorry to hear you’ve had such a difficult time designing your form.You should be able to achieve this quite simply by following the “two button submit” technique as I describe it in this article but instead of using an email submit button, you’ll need to use a regular button and then convert it into a submit button.To convert a regular button into a submit button, simply add a regular button to your form and then select the “Submit” radio button on the Object palette’s Field tab. Doing so will cause the Submit tab to appear in the Object palette.On the Submit tab, set the URL property to “mailto:email@address.com” (where “email@address.com” is the email address to which the data should be submitted), set the “Submit As” property to “XDP” and check the PDF and “Document Signature” check boxes in the Include section. This will result in an XDP containing 3 packets: the form as a PDF with the data filled-in, the digital signature(s) (if any) and the form data.Once you’ve set these properties on the button, just hide it and execute its Click event from another regular “non-submit” button’s Click event after you’ve validated the exclusion groups.

  16. Angelo says:

    Hi Again…Thank you for your guidance on my previous issue – the form is up and running! I was so excited after clearing that last hurdle that I have started a new project.There’s a post on the Adobe forum from last May (http://www.adobeforums.com/cgi-bin/webx/.3bbfd473) where you address making fields mandatory if a certain field is filled in. My form is similar in that there are multiple sections that may or may not be filled in. I understand the theory of it, but without seeing a working sample, I’m having trouble applying it to my needs. Instead, I have modified the sample of Complex Validations so that if fieldA is filled in, then succesive fields are required. The problem I am experienceing is that even if FieldA is not filled in, the user can input data into some or all of the other fields and still print or submit the form with incomplete fields. Another scenario is that if FieldA is filled in, I can skip several fields but fill in the last field and it will still print/submit. I would like to make all fields dependent on each other so if any one is filled in the others are required, no matter in what order that may occur. I hope you are able to follow what I’m trying to explain, because I feel like I am talking in circles.

  17. Angelo says:

    Hey Stefan -I hope you enjoyed your time away!I can save you some time and let you know that I finally solved my complex validation issue. I’d try to explain how I accomplished it, but there are so many steps that I lose my train of thought halfway through. I can send you the form and you can check it out if you like. My labeling is a little off, but I’m scared to clean it up right now for fear of wrecking it.Since it works, I am now trying to improve on it. One of my text fields is designed to display file pathh using this code :var myDoc = event.target;var sPath;myDoc.importDataObject(sPath);var myDataObject = myDoc.getDataObject(sPath);TextField1.rawValue = myDataObject.path;I can locate any random file on our server. What it displays is only the file name and extension (exterior.sign.ai). How can I expand the functionality to display either the entire file path (\\igsserver\igs\igs.jobs\igs.clients\a-f\alpine.river.club\2007\…) or preferrably display the last 4 or 5 levels of the file path.Thanks…

  18. Angelo,Yes, I enjoyed my little break very much although it went by way too fast!I’m glad to hear that you solved your first problem. Did you use the “Two Button Submit” technique I described in this article? That would let you create your own validation such that you could validate all fields and decide if and when to allow form submission to occur. As for printing, you can’t really lock it down since there are too many ways to print within Acrobat and you can’t disable all of them programmatically.As for your next question with regards to displaying the file path, try using the event.target.path or event.target.URL properties. “path” should give you the device-independent file path and “URL” should give you the path in the “http://” or “file://” format.

  19. Shawn Forney says:

    if (xfa.event.change == “a”)xfa.event.change = “”;Unfortunately, the script referenced above simply doesn’t work, at least in Acrobat 7.x. You can put that in the change event of a text field and type a’s like they’re going out of style. Any changes to xfa.event.change or xfa.event.newText are simply ignored by the application. Considering this behavior directly contradicts all documentation regarding these properties, it seems like a bug.

  20. Angelo says:

    Stefan -I’m obviously missing something, because when I edit the code to this:var myDoc = event.target.path;var sPath;myDoc.importDataObject(sPath);var myDataObject = myDoc.getDataObject(sPath);TextField1.rawValue = myDataObject.path;nothing is happening, not even the browser window opens. Can you elaborate please, maybe give me a little more context as to how the event.target.path is used?As for my previous issues, yes, the Two Button Submit worked. But, I had posted another message about making multiple fields mandatory after data is input into a field.I have four different sections in my form, two in which all fields are always mandatory. The problem I had was getting the third & fourth sections to respond. If the user entered data into one of these sections, whether the field was in the begining, middle or end of that section, I then wanted to make all empty fields mandatory. It took some head scracthing but I finally narrowed it down to the processes contained insided the { } & ( ) and figuring out where & when to use &&, ||, IsSpecified & !IsSpecified. Like I said in my other post, I kept getting lost in the code. But now, I’m pretty proud of myself and wanted to share it with you if you’d like to take a look at it. It’s kind of a complex-complex validation.Now, if we can just figure out the damn file path thing.Thanks…

  21. Shawn,I copied and pasted the script you posted directly into the Change event on a text field and tried running the form in both Acrobat 7.0.9 and Acrobat 8.0 and the script worked just fine.The script you posted in obviously in JavaScript. Is it possible your Change event’s Script Language is still set to FormCalc (in which case, the script wouldn’t be executed)?What exact version of Acrobat 7 are you testing this with? Is it Reader and what version?

  22. Angelo,I’m sorry for misleading you: I originally thought you were looking for the path to the PDF form which is executing the script. In that case,

    event.target.path

    would give you that.By changing the first line of your original script to “event.target.path”, you’re assigning a string to the “myDoc” variable — not the Doc object. That’s why you no longer get the file picker dialog (the script interpreter doesn’t know what to do with a string object when you call “importDataObject” on it).I believe what you’re after is the full path to the file that was imported. If that’s correct, then your original script should work, although I would recommend giving a name to the data object (the first parameter of the “importDataObject” is the name you want to assign to it):

    var myDoc = event.target;myDoc.importDataObject(“DataObject”);var myDataObject = myDoc.getDataObject(“DataObject”);TextField1.rawValue = myDataObject.path;

    Unfortunately, this still only yields the file name and extension, excluding the full original path even though the API documentation states that it returns “the device-independent path to the file that was embedded.”Although you could look at this as a bug in Acrobat, it’s actually like that for security reasons (all the way back to Acrobat 6, I believe) since the path to the file could contain sensitive information like a person’s username (depending on where the file was located). Therefore, once the data is imported, all that remains available is the original file name and extension. I will report the error in the documentation.As for your solution to your validation problems, normally I would say I’d love to have a look at it however I’m still back-logged with comments to respond to so I’ll have to pass this time. I’m glad it’s working for you, though.

  23. Shawn Forney says:

    We were using Acrobat 7.0 and Reader 7.0.5. After talking with Adobe support, the change event bug must have been fixed somewhere around version 7.0.8.