Copy link to clipboard
Copied
Hello again, scripters!
I'm looking for a solution to a problem that has plagued me for quite some time.. In order to make my scripts more robust and less prone to failure, i spend a lot of energy writing test conditions to make sure that an expected element actually exists in the document. Now, this element could be a groupItem or a textFrame or a layer.. Basically anything.
The syntax I wish i could use is this:
if(docRef.layers["someLayer"].exists)
{//do something}
else
{//do something else}
But unfortunately "exists" is not a property of layer/groupItem/textFrame etc.
A quick example, since this happens to be what I was working on when i decided to write this post. I like to put stuff into a file upon completion of a task so that at runtime, i can check to see whether said process has already been completed and then determine whether to proceed or not. Perhaps there are better methods, but i typically create specifically named sublayers to indicate a task has been completed. Unfortunately, however, the checks become quite convoluted in order to avoid runtime errors for "no such element".
How do you guys check that an important element exists so you can be sure to proceed appropriately? My method seems to always go back to try/catch blocks that can sometimes end up really ugly looking. I think I'm at the point of writing myself an abstract function that I can call whenever I need it, but i wanted to see how you guys handle similar issues before i invest the time into writing something potentially unnecessary.
Thanks in advance everyone. 😃
It depends, when targeting named objects that I KNOW will fail, I always use try/catch.
If I'm expecting objects returned from a function I may add a true/false property then use if (true) {}.
if I need lets say at least one document to proceed, I use if (docs.length>0) {}
Copy link to clipboard
Copied
::sigh::
Well as per usual, the very act of trying to explain my predicament helped shed some light. Thanks to all of you for being my rubber ducks.
I'll need to do some much more thorough testing on this to make sure it doesn't break down somewhere else (let me know if you can imagine a situation where it will fail). I'd love your thoughts on the below solution.. Should this have been a very "DUH" solution that i should have been using since day 1?
function exist(parent,child)
{
var valid;
try
{
var test = parent[child];
valid = true;
}
catch(e)
{
valid = false;
}
return valid;
}
//then it would be implemented thus:
if(exist(myLayer.groupItems , "nameOfGroup"))
{
//do something
}else
{
//do something else
}
Copy link to clipboard
Copied
Hmmm. No. That doesn't really work in such a simplistic form. It can still cause runtime errors in the exact same way because the arguments are evaluated before the function is executed. So if some parent doesn't exist, everything comes crashing down before the exist function even has a chance to test it.. Example:
doc has a single layer. The script will fail if you try to do something like:
if(exist(doc.layers[1].groupItems, "nameOfGroup"))
{//etc};
Because the index is out of bounds...
I had another thought which was to simply pass the parent as a string, but then i had issues with variables being undefined during the evaluation..?
Copy link to clipboard
Copied
For those kinds of checking functions, you'd at least have to know your parent container - if the parent container itself is prone to not existing, I suppose your function can be first used to check for it in it's parent and so on.
Copy link to clipboard
Copied
do you use a similar kind of checking function? How do you handle these types of situations?
Copy link to clipboard
Copied
It depends, when targeting named objects that I KNOW will fail, I always use try/catch.
If I'm expecting objects returned from a function I may add a true/false property then use if (true) {}.
if I need lets say at least one document to proceed, I use if (docs.length>0) {}
Copy link to clipboard
Copied
Hmm. that's disappointing. I was sure that there must be a better solution. I feel like having so many try/catch blocks really just mucks up the code. i spose i'll just keep trudging on that way then until i sit down and invest some time in trying to create a robust checking function.
Thanks, guys.
Copy link to clipboard
Copied
do you have that many try/catch? perhaps there's an alternative to avoid them instead of replace them.
Copy link to clipboard
Copied
I'm working with files that are touched by a lot of different people at a lot of different times. I cannot rely on things being exactly as i expect they should be. So to avoid constant errors caused by file inconsistency, i have to conditionally check for a lot of different things to make sure things are as expected before i proceed.
One of the reasons i don't like try/catch is that i have to decide whether to put multiple statements in a try block and not know which one failed, or whether to write a try/catch for each individual thing i need to confirm exists.. for example:
try
{
var something = doc.layers["test"];
var somethingElse = doc.layers["test1"]; //lets pretend this one doesn't exist
var somethingElseElse = doc.layers["test2"];
}
catch(e)
{
alert(e); //this will merely say "No Such Element"
}
So there were 3 possible places for failure to occur, and i can't identify which line failed. So then i'm stuck with doing 3 separate try/catch blocks for those 3 variable definitions..
Am i going about this all wrong?
Copy link to clipboard
Copied
Not so helpful but you can use alert(e.line) to know where it fail.
Copy link to clipboard
Copied
I see, for the scenario you posted, this is what I do, if a layer is not found, I create it.
var someLayer = getLayer('layerName');
// get or make a layer
function getLayer(layerName) {
var idoc = app.activeDocument;
try {var ilayer = idoc.layers[layerName];}
catch (e) {
var ilayer = idoc.layers.add();
ilayer.name = layerName;
ilayer.move(idoc, ElementPlacement.PLACEATBEGINNING);
}
app.redraw();
return ilayer;
}
Copy link to clipboard
Copied
moluapple:
alerting "e" doesn't tell me where it failed, because it only says the generic error message. It doesn't say "this is the thing you were looking for and there is no such element." So if i'm looking for 3 separate items, and it fails somewhere in the try statement, i get the same error message regardless. So i don't know whether the first statement failed or the third.
Your next example seems correct to me. That'd be the most thorough way to do it, but it's not any better looking or concise than a ton of try/catch.. bummer. =(
CarlosCanto:
much of the time, i'm not actually looking to create the layer. i just need to find out whether it's there so i know what to do next. Like i said, i'm sure that using layers for this purpose is probably up there on the list of really terrible decisions, but I've already made these decisions and now I have to live with them.
ok. Well thanks guys. I guess i'll just keep with the try/catch blocks.
Copy link to clipboard
Copied
Well, I mean alert(e.line) will tell you the line number of the script code where it failed. It can be helpful sometime.
Copy link to clipboard
Copied
ooooh. i'm stupid and i don't read good sometimes. I thought you were just saying alert(e) which i had tried and didn't work. i didn't know there were properties of the error code. Is there documentation for the available properties of 'e' (or whatever is used as the error code variable)?
will `alert(e.line)` show the line number of the script itself? I'd have to think long and hard about how to efficiently make use of that info since i'd have to update any conditions whenever i add/remove lines from the script.
Copy link to clipboard
Copied
Yes, you can find it in the data browser panel of ESTK(look for Error object). It's the line number of the script itself.
Copy link to clipboard
Copied
Great, thanks. That's good to know. I'll investigate ways to make that useful.
Copy link to clipboard
Copied
...likewise, creating a layer was proof of concept, you do what you need to do for your own needs.
as moluapple said, use e.line, then parse e.source to get the actual code
Copy link to clipboard
Copied
brilliant. Thanks guys. 😃
Copy link to clipboard
Copied
I have never write code like this, but that's the sequence if you want to ensure obj really exists: app > document > layer (optional) > group (optional) > (path, textframe, etc.)
function isExists(obj, prop) {
var valid;
try {
obj[prop];
valid = true
} catch (e) {
valid = false
}
return valid
}
if (isExists(app, 'activeDocument')) {
if (isExists(activeDocument.layers, 2)) {
if (isExists(activeDocument.layers[2].groupItems, "nameOfGroup")) {
alert('ok');
// do some thing;
} else {
// do some thing;
}
} else {
// do some thing;
}
} else {
// do some thing;
}
Copy link to clipboard
Copied
So, i think I've worked out an easier way to determine what failed in a try block (or at least the first failure), at least in terms of whether an element exists.. (this won't work for actual tasks performed by the script).
//first declare the variables that will be defined in the try block
var something,
somethingElse,
lastThing;
try{
var something = someValue;
somethingElse = someOtherValue;
lastThing = lastValue; //lets say 'lastValue' doesn't exist. so we head over to the catch
}catch(e){
if(something == undefined){
alert("something is undefined. someValue does not exist);
}
if(somethingElse == undefined){
alert("somethingElse is undefined. someOtherValue does not exist);
}
if(lastThing == undefined){
alert("lastThing is undefined. lastValue does not exist);
}
}
This will at least show me the first instance of a missing element.