6 Replies Latest reply on Sep 19, 2009 5:40 AM by Peter Kahrel

    [JS] How to add a group in a group ?

    Marc Autret Level 4

      I need to group 2 page-items --say obj1 and obj2-- and to add the result in an existing group --say hostGroup.


      Does anybody know why this code doesn't work :






        • 1. Re: [JS] How to add a group in a group ?
          Peter Kahrel Adobe Community Professional & MVP

          Group doesn't have a method add(), instead it has addPath(). But it doesn't seem to work very well. Suppose you have a page with two groups on it, then this


          g = app.documents[0].groups[0];
          array = [app.documents[0].groups[1]];
          g.addPath (array);


          gives you an error message: "Invalid value etc., expected array of page items but received Group". This doesn't look right. When you have one group and two ungrouped items, select those two items, and do this:


          g = app.documents[0].groups[0];
          array = [app.selection[0], app.selection[1]];
          g.addPath (array);


          you end up with a compound path (the two items you selected) and your original group, but there's no relation between the group and the compound path.



          • 2. Re: [JS] How to add a group in a group ?
            Peter Kahrel Adobe Community Professional & MVP

            I now see that I misread your message -- sorry.But it's problematic anyway. The problem appears to be that groups.add() is finicky (and mistaken) about what is and what is not an array. So you'd think that something like this would work:


            myDoc.groups.add ([myGroup1, myGroup2])


            but it doesn't. Indesign thinks that the parameter in add () is a group while in fact it is an array. The only way I can make it work is to ungroup hostGroup, then create a new group with the groups to be grouped created on the fly as parameters of the group to be created. Apologies for the Pythonesque sentence.This convoluted code works for me:


            // get array of page items in hostGroup, then ungroup hostGroup

            x = hostGroup.pageItems.everyItem().getElements();


            // create array two groups: one is the original hostGroup, the seceonf group consists of obj
            array = [app.documents[0].groups.add (x), app.documents[0].groups.add ([obj1, obj2])];
            app.documents[0].groups.add (array);


            Not a thing of great beauty but it works.



            1 person found this helpful
            • 3. Re: [JS] How to add a group in a group ?
              Marc Autret Level 4

              Hi Peter,


              Thanks for your comments and suggestions.


              So we always need to use ungroup() to extend an existing group? In truth, that's the method my script invokes for the moment, but I don't regard this workaround as a robust solution, because there are recursion issues: if you want to add an object in the group G, then you have to ungroup G and to rebuild the result from the parent. But the parent is not necessary a top-level object (Page/Spread/Document). The group G could be embedded in another group (or page item!), which could be embedded in another one... Thus, we need to ungroup recursively the whole hierarchy until we reach a Page/Spread parent, and to rebuild the same structure so to add finally the new object in the last group. For each step, the procedure needs to store the corresponding page items datas for callback, including the groups we are temporarily destroying!


              What I see is that we cannot use the Groups.add() method from any page item, despite that the page item owns a groups property, which is the case of the Group object. The DOM and the documentation are pretty misleading about this. Basically, the Groups.add() method is prototyped to accept for the first argument an array of PageItem, and that's the way I use it in the instruction: hostGroup.groups.add( [obj1, obj2] )


              IMHO, the code above should work, unless the DOM restricts explicitly the usage of Groups.add() for top-level parents.


              Assuming we have a few page items selected on the active page, there is no problem with the code below:


              var objs = app.selection;  // or any page items array
              var host = app.activeWindow.activePage;

              // create a group on the page:
              var newGroup = host.groups.add(objs);


              But, if the host is a Group object, the last line fails... The conclusion is that --apparently-- every group that a script needs to create must be created from a top container (Page/Spread/Document). If you want to build a subgroup G2 inside an existing group G1, you must first destroy G1 (ungroup), then create G2 (on the page), then rebuild G1 (on the page) with G2 and the other elements. All of this supposes that G2 is a top-level object, else, welcome to recursion!


              Tricky, isn't it?




              • 4. Re: [JS] How to add a group in a group ?
                Dave Saunders Level 4

                Complete coincidence that I was working on something similar this morning. I posted a new thread on the issue of adding text frames to an inline group. With that under my belt, I thought I'd give this a shot, but I come to the same conclusion that it doesn't work. I made a group on the only page of a new document and then added a couple of text frames to the page and tried this:


                var myPage = app.documents[0].pages[0];
                var myGroup = myPage.groups[0];
                var myTFs = myPage.textFrames.everyItem().getElements();
                var myNewTFs = new Array();
                for (var j = 0; myTFs.length > j; j++) {
                     var myNewTF = myGroup.textFrames.add();
                     myNewTF.properties = myTFs[j].properties;

                The idea being to group the two new items after they were in the group, but it didn't work. The last line gives a bad parameters error.



                • 5. Re: [JS] How to add a group in a group ?
                  Marc Autret Level 4

                  Hi Dave,


                  Yep, the groups.add() method sounds like a mirage when you call it from a group.


                  You can only extend a group by creating a page item at the group level, targeting the appropriate sub-collection:


                  But how to add in myGroup an existing TextFrame, or to inject in it a subgroup of various page items?


                  In some respects, the Group object behaves as a fake container. For instance, you may have notice that if myGroup contains two objects of different types (a Rectangle R and a TextFrame T), then you will have both R.index == 0 and T.index == 0 ! Because, in fact, the index of an object in a group is not the index in the group container, but the index in the corresponding collection in the group container. So R.index is the R-index in myGroup.rectangles (0), and T.index is the T-index in myGroup.textFrames (0).


                  Anyway, since Group.groups.add doesn't work, let's create this tool.

                  Here's my first try (the method includes the possibility to add a single PageItem rather than a subgroup):

                  Group.prototype.addItems = function(/*PageItem[] | PageItem*/ newItems)
                  // Emulates Group.groups.add(items) or Group.add(existing_item)
                  // <newItems> == Array of 2+ PageItem -> create a <newItems> subgroup in <this>
                  // <newItems> == single PageItem -> add the PageItem in <this>
                  // Returns the added subgroup or item (the whole group hierarchy is preserved)
                  // [this method fails if <this> is anchored/embedded in a story]
                  var     nodes=[], gs=[], g=this, node;
                  var makeNode = function(id,g)
                       var elems = g.pageItems.everyItem().getElements();
                       if (id === null) // placeholder for newItems
                            return {index: elems.length, items:elems.concat(0)};
                       for(var i=elems.length-1 ; i>=0 ; i--)
                                 // need to find the actual index in the group
                            if (elems[i].id == id) break;
                       return {index: i, items:elems};
                  for( var id=null ; g.constructor == Group ; id=g.id, g=g.parent )
                  var add = (function()
                       var host = g;
                       return function(items){return host.groups.add(items);};
                  var r = (typeof newItems == 'array' ) ?
                       add(newItems) :
                  while( g=gs.pop() ) g.ungroup();
                  for( g=r ; node=nodes.shift() ; )
                       node.items[node.index] = g;
                       g = add(node.items);
                  return r;


                  Sample usages:

                  var subGroup = myGroup.addItems(myNewTFs);





                  Hope it will help my fellow scripters...




                  • 6. Re: [JS] How to add a group in a group ?
                    Peter Kahrel Adobe Community Professional & MVP

                    Nice one, Marc! Thanks.