Using Try/Catch Statements in PDF Scripts
This statement runs another script when errors occur.
I enjoy answering questions on the Acrobat Users' Forum. That’s where I learned much of what I know about Adobe Acrobat when I was the one asking questions. It keeps me sharp, challenges me, and gives me ideas for this newsletter. I often read questions, and even though I don’t know the answers off the top of my head, I can quickly find answers, formulate solutions, and test those solutions before providing answers.
It took me a long time - decades of living and breathing Adobe Acrobat and JavaScript on a daily basis - to get to this point. I just spent a year developing an interactive course to teach others how to quickly find answers, then formulate and test solutions. You can view the course details here in the course outline tab. If you're interested, send me a message and I'll provide you with a promo code for $100 off.
Solution Process - A Real Example
Paraphrasing a recent question:
How can I check if a photo is uploaded in an image field using a script? I want to show the upload status in a text field.
I thought this was going to be an easy answer. An image field is actually a button field that is set up to insert an image as an icon for the button face. All I had to do was try to get the button field's icon using the buttonGetIcon( ) method. If an image had not been inserted yet, the script would return a null value or an error - or so I thought. It turns out that buttons always return an object icon, even when there is no icon associated with the button yet, and even if the button layout won’t accept an icon (layout = "Label Only"). If the button has no icon the method returns an object icon without any properties.
Since the field method buttonGetIcon( ) returns an icon object, I couldn’t use this to test whether a photo had been "uploaded" to the button. I would need to try something else.
There's a util method called util.iconStreamFromIcon( ) that takes an icon object as the input parameter and converts it to an icon stream object. When the input is the icon object from a button field that actually has an icon, it returns a stream object. For example, running the following script in the console:
var icn=this.getField("Button1").buttonGetIcon();
util.iconStreamFromIcon(icn);
returns
[object Stream]
when the button has an icon (an image has been loaded into the button). When the button does not have an icon, the script returns the following error:
RaiseError: Expected a dict object.
Script Errors
When an error is encountered in a script that runs in a PDF form, all other scripts stop immediately. This is why one of the most common responses from the experts on the Acrobat Users Forum is “Did you check the console for errors?” and also why I often link to my article The JavaScript Console. It's usually a quick and easy way to figure out what when wrong. Simply press Ctrl + j on the keyboard to see the error.
One of the most common errors is the following:
TypeError: this.getField(...) is null
The error above means that a field referenced in a script does not exist. It could be that it was removed by the form designer, forgetting that it was referenced in a script somewhere in the form. More often than not, there is a spelling error or typo in the field name when it is referenced in a script. A lot of times the typo is simply a case sensitivity error, which matters in JavaScript. For example, if there's a field called Total, but no field called total, and this.getField("total") is part of a script, the error in the code block above will print to the console.
These types of errors will cause people to say things like “my script was working fine and all of a sudden it doesn’t work any more”, or “the fields only calculate to this field, and then the calculations stop”. The response will be check the console for errors:
One of the issues with the error in the code block above is that it doesn't name the field that doesn't exist. The total in TypeError: this.getField(total) is null is replaced by three dots: TypeError: this.getField(…) is null
Several Adobe versions ago, this error used to name the non-existent field so it was easy to find where the error was occurring. I'm not sure why they decided to do away with this functionality but it's gone now. It can take a long time to find an error like this, especially in complicated forms with lots of fields and scripts, so it's a good idea to check the console often when adding scripts to a form.
What’s The Solution?
Since errors stop all scripts from running, how can a forced error be used in a script to obtain a result without all the scripts immediately stopping?
The answer is a try/catch statement which tries a script, catches and stores the error (if applicable), ignores the error and runs another script (optional). The statement looks like this:
try{/*the script to try*/}
catch(/*a variable represent the error. e is usally used*/)
{/*script to run if an error is caught*/}
Following the non-existent field example above, the following script popups up an alert, with the alert message as the variable representing error. As stated in the code block, e is usally used as the variable but it can be any legitimate variable.
try{this.getField("a").value}catch(e){app.alert(e)}
When the line of code above runs and the field called “a” does not exist, a popup displaying the error will occur.
If the field exists, no popup will display because no error was caught.
Putting It All Together
Back to the button icon question. The following script, entered as a mouse up action in a button field, sets the value of a text field called Status to either Has image or Does not have image.
event.target.buttonImportIcon();
var icn=event.target.buttonGetIcon();
var status="Has image";
try{util.iconStreamFromIcon(icn)}catch(e){status="Does not have image"}
this.getField("Status").value=status;
This script can be tested by clicking the button field and importing an icon, or clicking the button field and clearing the icon (if one is already present).
Great article. Packing away for future use.