• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Check for the existence of an expected element

Community Expert ,
Dec 08, 2016 Dec 08, 2016

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. 😃

TOPICS
Scripting

Views

1.7K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Dec 09, 2016 Dec 09, 2016

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) {}

Votes

Translate

Translate
Adobe
Community Expert ,
Dec 08, 2016 Dec 08, 2016

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

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 08, 2016 Dec 08, 2016

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..?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Valorous Hero ,
Dec 08, 2016 Dec 08, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2016 Dec 09, 2016

Copy link to clipboard

Copied

do you use a similar kind of checking function? How do you handle these types of situations?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2016 Dec 09, 2016

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) {}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2016 Dec 09, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2016 Dec 09, 2016

Copy link to clipboard

Copied

do you have that many try/catch? perhaps there's an alternative to avoid them instead of replace them.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 09, 2016 Dec 09, 2016

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?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Dec 09, 2016 Dec 09, 2016

Copy link to clipboard

Copied

Not so helpful but you can use alert(e.line) to know where it fail.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 10, 2016 Dec 10, 2016

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;

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2016 Dec 12, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Dec 12, 2016 Dec 12, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2016 Dec 12, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Dec 12, 2016 Dec 12, 2016

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2016 Dec 12, 2016

Copy link to clipboard

Copied

Great, thanks. That's good to know. I'll investigate ways to make that useful.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2016 Dec 12, 2016

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 12, 2016 Dec 12, 2016

Copy link to clipboard

Copied

brilliant. Thanks guys. 😃

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Dec 10, 2016 Dec 10, 2016

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;

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Dec 13, 2016 Dec 13, 2016

Copy link to clipboard

Copied

LATEST

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines