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

[JS CS4] Sorting linked dropdownlists alphabetically problem

Guest
Apr 01, 2010 Apr 01, 2010

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

TOPICS
Scripting
1.9K
Translate
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 , Apr 03, 2010 Apr 03, 2010

> 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 cl

...
Translate
Community Expert ,
Apr 01, 2010 Apr 01, 2010

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.text)
                {
                list_obj.add ("item", s, i);
                if (select)
                    list_obj.items.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

Translate
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 ,
Apr 02, 2010 Apr 02, 2010

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

Translate
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
Guest
Apr 02, 2010 Apr 02, 2010

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.

Translate
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 ,
Apr 03, 2010 Apr 03, 2010

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

Translate
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
LEGEND ,
Apr 03, 2010 Apr 03, 2010

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

Translate
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 ,
Apr 03, 2010 Apr 03, 2010

> 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] = b;
    return array;
    }
Translate
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
Guest
Apr 06, 2010 Apr 06, 2010

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.

Translate
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
LEGEND ,
Apr 06, 2010 Apr 06, 2010

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] = b;
   return hashTable;
   }

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

Harbs

Translate
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 ,
Apr 06, 2010 Apr 06, 2010

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.

Translate
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
LEGEND ,
Apr 06, 2010 Apr 06, 2010

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

Translate
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 ,
Apr 06, 2010 Apr 06, 2010

> 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

Translate
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
LEGEND ,
Apr 06, 2010 Apr 06, 2010

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

Translate
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
LEGEND ,
Apr 06, 2010 Apr 06, 2010
LATEST

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.

Translate
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
LEGEND ,
Apr 06, 2010 Apr 06, 2010

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

Translate
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