10 Replies Latest reply on Apr 11, 2016 6:17 PM by tt27079448

    How to dynamically update a dropdownlist after it's been created?

    Techie_Dave Level 1

      I'm trying to create a small GUI that gives the user the ability to select a layer from the list of layers in a document. Initial population of the drop down is easy, it's done at creation. But if the user creates or deletes a layer, then I need to update the items in the dropdownlist. I've gone over the relevant documentation (including the latest rev of "Beginning ScriptUI"), but can't seem to find a way to do this.

      Here's a standalone snippet of code that *should* work, except that the events are not being called (onClick, onActivate, onDraw). Anyone have any tips?

       

      #target Illustrator

      #targetengine main

       

      var testW = new Window ("palette", "test");

      var labelSpacing = 15;

      var listOfLayers = [];

       

      // Create group for layers label and dropdown list

      var grpLayer = testW.add("group");

      grpLayer.alignment = "left";

       

      // label for Layers selection

      var layerName = grpLayer.add ("statictext", undefined, "Layers:");

       

      // populate the list of layers from the active Illustrator document

      listOfLayers = buildCurrentLayerList();

      var mydropdownList = grpLayer.add ("dropdownlist", undefined, listOfLayers);

      mydropdownList.characters = labelSpacing;

      mydropdownList.selection = listOfLayers.active;

       

      // Add onClick event - builds list of current layers

      mydropdownList.onClick = function() {

        alert("onClick event on dropdownlist, activeDoc = " + app.activeDocument);

        listOfLayers = buildCurrentLayerList();

        myropdownList.removeAll();

        listOfLayers.foreach(mydropdownList.add(listOfLayers[index]));

      }

      // TRY onActivate event listener to build list of current layers

      mydropdownList.addEventListener ('onActivate', function() {

        alert("onActivate event on dropdownlist, activeDoc = " + app.activeDocument);

        mydropdownList.removeAll();

        listOfLayers = buildCurrentLayerList();

        listOfLayers.foreach(mydropdownList.add(listOfLayers[index]));

      });

      // TRY onDraw event listener to build list of current layers

      mydropdownList.addEventListener ('onDraw', function() {

        alert("onDraw event on dropdownlist, activeDoc = " + app.activeDocument);

        mydropdownList.removeAll();

        listOfLayers = buildCurrentLayerList();

        listOfLayers.foreach(mydropdownList.add(listOfLayers[index]));

      });

       

      // Create Close button

      var grpButtons = testW.add("group");

      grpLayer.alignment = "center";

      var closeButton = grpButtons.add ("button", undefined, "Close");

      // close the window

      closeButton.onClick = function() {

        testW.close();

        testW = null;

      }

       

      // Draw the window

      testW.show();

       

       

      // ============================================================

      // Function: buildCurrentLayerList

      // Returns:  array of layer names and index of active field

      // ============================================================

      function buildCurrentLayerList() {

        var layerCount;

        var layers = ["<use active layer>","-"];

        layers.active = 0;

             

        if ( app.activeDocument == null ) {

          alert("Active documents is null");

        } else if ( app.activeDocument == "" ) {

          alert("Active documents is empty");

        } else {

          layerCount = app.activeDocument.layers.length;

          for ( idx = 0; idx < layerCount; idx++ ) {

            layers[idx+2] = app.activeDocument.layers[idx].name;

            if ( layers[idx+2] == app.activeDocument.activeLayer.name ) {

              layers.active = idx+2;

            }

          }

        }

        return(layers);

      }

        • 1. Re: How to dynamically update a dropdownlist after it's been created?
          CarlosCanto Adobe Community Professional & MVP

          couple of concepts, in order for palettes to communicate with Illustrator, you must use BridgeTalk, check the Tools Guide for details. You can also search the forum, we have posted plenty of samples on this subject, here's one of them

          Introducing: Select Layers Script

           

          next, to repopulate the dropdown list dynamically, you need to remove your dropdown, then add a new one with the new set of items.

           

          your script has a couple of errors,

          - dropdown lists don't respond to onClick events, use onChange instead.

          - typo here "myropdownList.removeAll();" missing a "d"

          - this version of javascript does not support "foreach"

           

          I didn't do extensive debugging, get the above sorted and we'll go from there.

          • 2. Re: How to dynamically update a dropdownlist after it's been created?
            Techie_Dave Level 1

            Hi Carlos,

            Thanks for the quick reply. I wasn't sure about the onClick so I added onActivate and onDraw to test further. And yes, I saw the missing 'd' after I posted, I should have learned by now not to code on the fly. Same thing goes for 'foreach', I'll switch it to a proper 'for' loop.

             

            Removing and re-adding seems rather extreme, but I'll give it a try. I just need those events to trigger first. Out of curiosity, does the onChange trigger when the dropdown is clicked? Or will it trigger after the list has been displayed and the user has click on an entry? I couldn't find a reference about sequences or order of operations.

             

            In the meantime I'll follow your link and get informed, thanks for the tip!

            • 3. Re: How to dynamically update a dropdownlist after it's been created?
              CarlosCanto Adobe Community Professional & MVP

              yeah, in reality there's no way (that I know of) to update dropdowns dynamically, removing and recreating is a workaround I found rather painfully.

              • 4. Re: How to dynamically update a dropdownlist after it's been created?
                Techie_Dave Level 1

                Well, I've made some changes and still don't have a solution. The weird thing is that the onChange event is not triggered consistently – it works on some script invocations and not on others (no changes to the script in-between). Not sure what is going on there but it's a topic for another time .

                 

                I tried changing the dropdownlist into a button that would open a supplementary window which creates the dropdownlist dynamically, this way I should be able to get the up-to-the-minute view of the layers. But unfortunately, the window must be out of context and the regular app.* data structures are not entirely available. I threw an alert into the window gen to get the following data:

                Screen Shot 2016-04-09 at 5.40.13 PM.png

                As you can see, there is a document (app.documents.length == 1) but there is no active document (app.activeDocument == null) and the top document is undefined (app.documents[0].name == "undefined"). I'm assuming that Carlos's suggestion of using BridgeTalk is what is required here to introduce a messaging pipe between the script and the Illustrator App, but this is getting way too complicated for such a simple tool. I'll see if I can design a different UX model that avoids the issue.

                 

                Thanks for your help Carlos, I really appreciate the fact that Adobe staff monitors and contributes to these forums. It's a great resource!

                • 5. Re: How to dynamically update a dropdownlist after it's been created?
                  CarlosCanto Adobe Community Professional & MVP

                  BridgeTalk is complicated at first, but if you want to use palettes you must use it.

                   

                  your idea about creating a new window since getting the layers seems to work at creation time is not working because you loose connectivity to the Illustrator app when you create the first window, so it's pretty much the same problem you had...by the way I'm not staff, I'm just another user.

                  • 6. Re: How to dynamically update a dropdownlist after it's been created?
                    Techie_Dave Level 1

                    I thought as much. The context of the Illustrator app is lost when I open the palette (as opposed to a dialog): asynchronous vs. synchronous I guess.

                    I'll have to read up on BridgeTalk and get familiar with it if I'm going to be doing more tools like this, thanks for the tips!

                     

                    And wow, if you're not Adobe staff then many more thanks for taking your time to mentor. I assumed the "ACP" badge meant "Adobe Creative Personnel" or some-such. As I become more comfortable with this toolset I hope I can also pay it back by contributing to the discussions.

                    • 7. Re: How to dynamically update a dropdownlist after it's been created?
                      CarlosCanto Adobe Community Professional & MVP

                      you're welcome, it stands for Adobe Community Professional

                      • 8. Re: How to dynamically update a dropdownlist after it's been created?
                        tt27079448 Level 1

                        My approach is to increase a button

                        Button's function is to close the window, open again

                        • 9. Re: How to dynamically update a dropdownlist after it's been created?
                          Techie_Dave Level 1

                          Hi tt27079448,

                          Thanks for the alternative. However, asking the user to open/close the window all the time to update the contents would become irritating.

                           

                          In my reading from Carlos I've come across a great discussion that summarizes BridgeTalk nicely:

                          How to access app.activeDocument from a palette button?

                           

                          alanomaly gave a simple example of how to implement the comms between a palette and Illustrator. It's actually much simpler than I thought and should be relatively easy to integrate into my tool. I'll still have to destroy and recreate the dropdownlist, but at least now I can get the current information from Illustrator without requiring any extra user interaction.

                           

                          Basic code from alanomaly is:

                           

                          function someFunction() {

                            // get data from the application

                            return app.activeDocument.selection.length;

                          }

                           

                          palette.button.onclick = function(){

                            // make a BridgeTalk object to throw the script

                            var bt = new BridgeTalk();

                            bt.target = "illustrator";

                           

                            // a string containing javascript code to execute in Illustrator

                            bt.body = someFunction.toString()+'someFunction();';

                           

                            // a function that recieves whatever the body JS above returns

                            bt.onResult = function(result){

                              palette.info.text = result.body;

                            };

                           

                            bt.send();

                          }