Copy link to clipboard
Copied
I am working on an essentially very simple script that is supposed to do the following:
I can loop over the app.activeDocument.rectangles collection with no problem, but as soon as I duplicate an individual Rectangle object, the loop break. It seems that duplicating an element unshifts the copy onto the beginning of the array of objects represented by the Rectangles collection, rather than pushing it onto the end.
So if I have three Rectangle objects in the document (let’s make them red, green and blue, just to tell them apart), I’d initially get a collection like this:
I loop over the collection and copy the current object on each iteration like so:
var els = app.activeDocuments.rectangles;
var targetLayer = app.activeDocument.layers.itemByName("Target Layer");
for (i = 0, j = els.length; i < j; i++) {
var orgEl = els;
var newEl = orgEl.duplicate(targetLayer);
$.writeln(i + ": " + orgEl.id + " / " + newEl.id);
// do more stuff with the duplicated element here
}
Doing this, I would (naïvely) expect the collection to end up looking like this:
– but instead this is what happens:
In other words, when I call orgEl.duplicate() in the first iteration (i = 0), the duplicated element is unshifted into the collection at position 0, and the current element’s index is moved up one, becoming 1. On the next iteration (i = 1), naturally, I get the same element again, since its position has moved since the start of the loop.
Now, it is of course possible to overcome the obstacle that this presents for looping over collections, by doing this for example:
var els = app.activeDocuments.rectangles;
var ids = els.everyItem().id;
var targetLayer = app.activeDocument.layers.itemByName("Target Layer");
for (i = 0, j = els.length; i < j; i++) {
var orgEl = ids;
var newEl = orgEl.duplicate(targetLayer);
$.writeln(i + ": " + orgEl.id + " / " + newEl.id);
// do more stuff with the duplicated element here
}
But that’s rather unintuitive and cumbersome. I can think of several good reasons why duplicating an element onto the end of a collection would be usual and make sense, but I cannot think of a single good reason why adding it on to the beginning. All the effects I can think of are negative: the weirdness of modifying the index position of the current element, the rather significant performance hit that comes with unshifting compared to pushing, and just… general common sense.
So why is it that duplicate() apparently unshifts rather than pushing? Is there some logical reasoning behind this seemingly counterintuitive decision?
Collections are dynamic and reordered everytime you touch a child object of the collection. To avoid issues, you can force convert collection into a javascript Array by using
collection.getElements(); //Returns an array.
But still items could be removed by your script and references later be non valid.
The strongest approach would be probably to store items id in a object as IDs don't change whatever you do in the meanwhile.
Copy link to clipboard
Copied
Collections are dynamic and reordered everytime you touch a child object of the collection. To avoid issues, you can force convert collection into a javascript Array by using
collection.getElements(); //Returns an array.
But still items could be removed by your script and references later be non valid.
The strongest approach would be probably to store items id in a object as IDs don't change whatever you do in the meanwhile.
Copy link to clipboard
Copied
Oh, I see. So it’s not that the newly created elements are ‘unshifted’ onto the beginning of the collection, but rather that the entire collection gets recreated as soon as the element is created, and since the new element is in the same position as the old one, but on a higher layer (?), it ends up being the first in the new collection.
That actually makes a lot more sense!
Copy link to clipboard
Copied
Loic.Aigon wrote
… The strongest approach would be probably to store items id in a object as IDs don't change whatever you do in the meanwhile.
Definitely.
But if you only want to duplicate elements an array will work. Duplicating elements cannot change the gathered array of page items.
var rectArray = app.documents[0].rectangles.everyItem().getElements();
Note: The array above will not contain rectangles in nested structures like groups or anchored frames etc.pp.
Regards,
Uwe
Find more inspiration, events, and resources on the new Adobe Community
Explore Now