14 Replies Latest reply on Apr 6, 2010 11:38 AM by John Hawkinson

    [JS CS4] Sorting linked dropdownlists alphabetically problem

    Skempy Level 1

      Hi,

       

      I have built a simple dialog script that looks up and displays data from a CSV file. There are three drop down lists with the first two being linked to each other so the selection in the second changes if the selection in the first changes.

       

      I am quite pleased with this especially as I only need update the CSV file to have the dropdown list automatically populated. Someone I have shown this to has pointed out that the second dropdown is not sorted alphabetically.

       

      My problem is that I can only have either one or the other list displayed aphabetically.

       

      Here is the code so far, a lot of which I got from the kind contibutors of this forum. I have added a link to the script and CSV file.


      var colWidthValue = "100mm"
      var firstLine = getHeadings();
      firstLine.shift()
      firstLine.shift()
      var colWidths = firstLine;
      var myPubCodeList = getCodes(0)
      var myTitlesList = getCodes(1)
          var w = new Window("dialog", "Publication Information Lookup");
          w.orientation = "row";
      w.addList = new Array();

      // 1st Drop Down
      w.textPubCode = w.add('statictext', undefined, 'Pub Code:');
      w.pubCodes = w.add('dropdownlist',undefined,myPubCodeList);
      w.pubCodes.selection = w.pubCodes.items[0];

      // 2nd Drop Down
      w.textTitle = w.add('statictext', undefined, 'Title:');
      w.Titles = w.add('dropdownlist',undefined,myTitlesList);
      w.Titles.selection = w.Titles.items[0];

      w.Titles.onChange = function() {
          w.pubCodes.selection = w.Titles.selection.index;
      }

          // 3rd Drop Down
      w.textCols = w.add('statictext', undefined, 'Data:');
      w.colNum = w.add('dropdownlist',undefined,colWidths);
      w.colNum.selection = w.colNum.items[0];
      w.group = w.add( "group" );

      w.pubCodes.onChange = function() {
        code = w.pubCodes.selection.text
        cols = w.colNum.selection.index
        w.Titles.selection = w.pubCodes.selection.index;
        if ( this.window.addList.length > 0 ) {
                  this.window.group.remove( this.window.addList.pop() );
                  this.window.layout.layout( true );
              }
              this.window.addList.push( w.group.add( "statictext", undefined, getWidth(code,cols+2)) );
              this.window.layout.layout( true );
          }
      w.colNum.onChange = function() {
        code = w.pubCodes.selection.text
        cols = w.colNum.selection.index
       
         
       
          if ( this.window.addList.length > 0 ) {
                  this.window.group.remove( this.window.addList.pop() );
                  this.window.layout.layout( true );
              }
              this.window.addList.push( w.group.add( "statictext", undefined, getWidth(code,cols+2)) );
              this.window.layout.layout( true );
          }   
      w.show();

      function getWidth(myPubCode,myCols) {
        
      mySizeFile = File("C:/size_lookup.csv");
        mySizeFile.open("r", undefined, undefined);
        do{
         myLine = mySizeFile.readln();
         myPubArray = myLine.split(",");
         //alert(myPubArray[0] + " | " + myPubCode);
         if(myPubArray[0] == myPubCode) {
          return myPubArray[myCols];
          break;
          }
           
        } while(mySizeFile.eof == false);
        mySizeFile.close();
       
        }

      function getCodes(c) {
        var myArray = []
        mySizeFile = File("C:/size_lookup.csv");
        mySizeFile.open("r", undefined, undefined);
        do{
         myLine = mySizeFile.readln();
         mytempArray = myLine.split(",");
         myArray.push(mytempArray[c]);  
            
           
        } while(mySizeFile.eof == false);
        mySizeFile.close();
       
        return myArray
       
        }

      function getHeadings() {
        var myArray = []
        mySizeFile = File("C:/size_lookup.csv");
        mySizeFile.open("r", undefined, undefined);
        myLine = mySizeFile.readln();
        myArray = myLine.split(",");
        return myArray 
        }

       

       

      I know my scripting is probably clumsy and long winded but it works.

       

      It would be greatly appreciated if anyone could point me in the right direction to being able to get both drop down lists to display alphabetically yet still update the other with the correct value.

       

      Thanks

       

       

      http://webbanners.nepads.co.uk/Scripts/LookupScript.zip

        • 1. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
          Peter Kahrel Adobe Community Professional & MVP

          For adding one item at a time, I use the following method. First, display a sorted list. In your script that would be something like this for one list:


          w.pubCodes = w.add('dropdownlist',undefined,myPubCodeList);

           

          Then, to add an item to the list, add  it in a position that keeps the list sorted:

           

          insert_item (w.pubCodes, "some new code", true);

           

          function insert_item (list_obj, s, select)
              {
              // if the item is not in the list
              if (list_obj.find (s) == null)
                  {
                  var le = list_obj.items.length;
                  for (var i = 0; i < le; i++)
                      {
                      if (s < list_obj.items[i].text)
                          {
                          list_obj.add ("item", s, i);
                          if (select)
                              list_obj.items[i].selected = true;
                          break
                          }
                      }
                  }
              }

           

          The function first checks if the item you want to indert is not already in it. If it's not, then it races through the list and places the new item in its proper place.

           

          Peter

          • 2. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
            Peter Kahrel Adobe Community Professional & MVP

            To display a sorted list you need this:

             

            w.pubCodes = w.add('dropdownlist',undefined,myPubCodeList.sort());

             

            not the version in the previous post, which simply repeats yours.

             

            Peter

            • 3. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
              Skempy Level 1

              Thanks for the replies Peter,

               

              The two drop down lists are related,

               

              So if I select code "EPNN" in list one, list 2 changes to have "Evening Post" selected.

              And if I select "Admag" in list 2, List 1 changes to display "ANNS".

               

              This all works fine but the CSV file lists the Publications in alphabetical order by Pub Code but the corresponding Titles are not alphabetical.

               

              Therefore the Title displayed in List 2 are not in alphabetical order making it harder to locate the required Title.

               

              I am looking for help with a strategy to get round this problem.

               

              Thanks again.

               

              Simon Kemp.

              • 4. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                Peter Kahrel Adobe Community Professional & MVP

                Ah, ok, I see what you mean now. You have two lists, codes and publications. First item in codes corresponds to the first item in publications, etc. Codes is sorted, publications isn't. You want to sort publications and maintain the correspondences (or links).

                 

                I guess that what you need to do is this: create an index in which you can look up the links. An associative array would probably be the easiest. Then sort the publications list. When you pick an item in the codes, look up which publication is linked to that code, then select that publ. in the dropdown.

                 

                Have you worked with associative arrays? They look as follows:

                 

                index1 = [];

                index1 ["ABCD"] = "Gazetteer";

                index2 ["EFGH"] = "Lancaster Guardian";

                etc.

                 

                So you create this index, then you sort the publications and display the window. Now when you select a code, you do this:

                 

                var title_to_select = index1 [w.pubCodes.selection.text];

                 

                This returns a string; e.g. if you select the code EFGH, you get the string "Lancaster Guardian". Then you select "Lancaster Guardian" in the publication dropdown.

                 

                You'd have to create a separate index to select a code if you click a publication.

                 

                Hope this helps.

                 

                Peter

                • 5. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                  John Hawkinson Level 5

                  Err, did you really mean to use "index2" there? If so, I think you skipped part of the explanation...    

                  • 6. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                    Peter Kahrel Adobe Community Professional & MVP

                    > Err, did you really mean to use "index2" there? If so, I think you  skipped part of the explanation...

                     

                    You're right, that should have been index1. Anyway, below is a working example. The script displays a window with to list boxes (these are virtually the same as dropdowns scripting-wise but you can see much better what is going on). Click on the left-hand list and the script selects the corresponding item in the right-hand list, and vice versa. The indexes could probably be implemented more cleverly.

                     

                    Peter

                     

                    #target indesign;

                    array1 = ['A', 'B', 'C', 'D', 'E'];
                    array2 = ['dA', 'eB', 'aC', 'cD', 'bE'];

                    // Create indexes -- associative arrays
                    // index12 is used to find which item in list 1 points to which item in list2

                    index12 = create_index (array1, array2);

                    // and index21 is used to find which item in list 2 points to which item in list1

                    index21 = create_index (array2, array1);

                    //~ At this point,
                    //~ index12 ['A']  returns 'dA'
                    //~ index12 ['B']  returns 'eB'
                    //~ etc.

                    //~ index21 ['dA'] returns 'A'
                    //~ index21 ['eB'] returns 'B'
                    //~ etc.

                    w = new Window ("dialog");
                        w.orientation = "row";
                        // display list 1 and select first item
                        list1 = w.add ("listbox", undefined, array1);
                        list1.selection = 0;
                        // display list 2 sorted
                        list2 = w.add ("listbox", undefined, array2.sort ());
                        // when the window is drawn, select the correct item in list 2
                        list2.selection = list2.find (index12[array1[0]]);

                        list1.onChange = function ()
                            {
                            // selection made in list 1:
                            var select_in_list2 = index12 [list1.selection.text];
                            list2.selection = list2.find (select_in_list2);
                            }
                       
                        list2.onChange = function ()
                            {
                            var select_in_list1 = index21 [list2.selection.text];
                            list1.selection = list1.find (select_in_list1);
                            }

                    w.show ();


                    function create_index (a, b)
                        {
                        var array = [];
                        for (var i = 0; i < a.length; i++)
                            array [a[i]] = b[i];
                        return array;
                        }
                    • 7. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                      Skempy Level 1

                      Peter,

                       

                      Thank you.

                       

                      This is exactly what I was struggling to achieve.

                      I haven't used associative arrays before but with your example I can make my script a whole lot more useful and can also go on to solve a few more problems too.

                       

                      This forum has got to be the single most useful resource for InDesign scripting.

                       

                      Again thanks a lot.

                      • 8. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                        Harbs. Level 6

                        Peter,

                         

                        JS doesn't really support associative arrays. You're MUCH better off using proper objects like so:

                         

                        function create_index (a, b)
                           {
                           var hashTable = {};
                           for (var i = 0; i < a.length; i++)
                               hashTable[a[i]] = b[i];
                           return hashTable;
                           }

                         

                        If you google "associative array js", you'll get a lot of articles on why...

                         

                        Harbs

                        • 9. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                          Peter Kahrel Adobe Community Professional & MVP

                          Harbs,

                           

                          I remember that discussion in this forum a while ago, and I've seen many posts saying that associative arrays are not safe and that instead you should use objects. But I fail to see the difference between the two: in fact I believe they're notational variants of the same thing. Here's an associative array:

                           

                          array = [];
                          array ["one"] = "een";
                          array ["two"] = "two";
                          array ["three"] = "drie";

                           

                          You can approach this associative array in two ways:

                           

                          array ["two"] returns "twee"

                          array.two also returns "twee".

                           

                          Now let's define an object and fill it with some values:

                           

                          obj = {one: "een", two: "twee", drie: "drie"};

                           

                          The object's properties can be addressed in two ways:

                           

                          obj.two returns "two"

                          obj ["two"] returns "two".

                           

                          So how do "array" and "obj" differ apart from their notation?

                           

                          As to your hash table, you use the variable name "hashTable" where I used "array", but otherwise I can't see any difference between your function and mine. Or am I missing something?

                           

                          Peter

                           

                          OT: I can't believe this puritan Jive: i had abbreviated "associative" to its first three letters, and it showed up as ***. What utter stupidity.

                          • 10. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                            Harbs. Level 6

                            pkahrel wrote:

                            As to your hash table, you use the variable name "hashTable" where I used "array", but otherwise I can't see any difference between your function and mine. Or am I missing something?

                            You used: []

                            while I used: {}

                             

                             

                            As for problems:

                             

                            What's going to happen when you try something like this?

                             

                            array = [];
                            array ["length"] = "een";
                            array ["height"] = "two";
                            array ["width"] = "drie";
                            

                             

                            Harbs

                            • 11. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                              Harbs. Level 6

                              Here's one article on the evils of being in the habit of using Arrays instead of Objects: http://ajaxian.com/archives/javascript-associative-arrays-considered-harmful

                               

                              There's many, many more...

                               

                              For most simple uses, there's not much difference, but if you ever use for-in, you're `going to get bitten if you use Arrays instead of Objects sooner or later...

                               

                              Harbs

                              • 12. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                                Peter Kahrel Adobe Community Professional & MVP

                                > You used: [] while I used: {}

                                 

                                You did! Hadn't spotted that. Pesky braces.

                                 

                                > What's going to happen when you try something like this?

                                 

                                array = [];
                                array ["length"] = "een";

                                 

                                Clever. You get an error: "1.#QNAN is out of range". Looks like a problem. But then it's very confusing to use a property name "length". Anyway, since the difference is just between {} and [], might as well use an object.

                                 

                                But I must say that the evils and dangers are a bit exaggerated. For instance, the links you gave on the evils of assoc. arrays don't really describe any evil. The main link says "The harmful side effects of using Array for key/value pairs are not  experienced unless Array.prototype is extended." That's about it. And as I don't Prototype (nor do you) it doesn't bother me much. The objections are mainly fuelled by sentiments such as "arrays aren't supposed to do that". Smacks very much like "You shouldn't use myDoc.pages[0] because you're dealing with an object, not an array, so you should use myDoc.pages.item(0) or even myDoc.pages.firstItem()."

                                 


                                But I see that if you want to be perfectly on the safe side you're better off using objects.

                                 

                                Peter

                                • 13. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                                  Harbs. Level 6

                                  You don't use any Array prototype functions?

                                   

                                  Yes, the "evils" are exaggerated. The biggest problem in my book is that it breeds a misconception on what's going on. Using Array gives the impression that it's a feature of Array which allows for this use...

                                   

                                  Take this illustration:

                                  array = [] //array = Array()
                                  array = "" //array = String()
                                  array = /""/ //array = RegExp()
                                  array = <root/> //array = XML()
                                  and array = {} array = Object()

                                  all work equally well!

                                   

                                  The only reason any of them work is because, at their basic level, they are all just js objects, and js objects are dynamic. It's therefore wrong to call an Object anything but an Object...

                                   

                                  The same way you wouldn't use a String or RegExp (Or "Application" for that matter!!!) for this purpose, you should not use an Array!

                                   

                                  Harbs

                                  • 14. Re: [JS CS4] Sorting linked dropdownlists alphabetically problem
                                    John Hawkinson Level 5

                                    One of the concerns is that if you are taking user input, a user might very well have a cell in their spreadsheet called "length", and when you try to set dictionary[key]=value where key and value come from user input, if key happens to be the string "length" then you will bave a problem.

                                     

                                    If anyone who isn't a JavaScript programmer might be using your script, they'll have a lot of trouble understanding the problem.