Expand my Community achievements bar.

SOLVED

Accessing "specified values" via scripting

Avatar

Level 10

When specifying item values (on the Binding tab) for a dropdown field, how do you access the specified values from a script - as opposed to accessing the string value?

I'm using WindJack's sample script (programming lists part 1) for feeding a dropdown, but it needs the full string value of the initial dropdown - the strings I have are kinda long and unweildy and if they have to change I have to update the scripts, etc. Being able to access the specified value of the dropdown list would make things much simpler.

var oReasons =
    {
     "CHQ Returned Undeliverable Cheque": ["01: Unclaimed at Address","02: Unknown Address","03: Address Incomplete","04: No Such Post Office","05: No Such Address","06: Deceased","07: Moved, Address Unknown","08: Refused by Addressee","09: No Reason Given on Envelope","10: Returned Twice from Same Address","11: Additional Information Required - Re-Direct to Ministry","12: Refused - Duplicate Payment"],
        "CHQ Stop Payment - Cheque Attached": ["30: Cancelled - Payment Not Required","31: Stale Dated","32: Cancelled - Incorrect Payee Name","33: Damaged/Destroyed","36: Cancelled - Duplicate Payment","37: Cancelled - Incorrect Amount/Currency","38: Cancelled - Not Entitled","39: Cancelled - Deceased","40: Cancelled - Cannot Locate Payee","41: Wrong Currency","43: Cancelled - Change of Payee"],
        "CHQ Stop Payment - No Cheque Attached": ["20: Never Received/Lost in Delivery (BOI Required","21: Lost/Stolen After Receipt (BOI Required)","23: Not Entitled - Duplicate Payment","24: Not Entitled - Deceased","25: Lost in Clearing (BOI must be signed by negotiating FI)","26: Damaged/Destroyed","27: Not Entitled","28: Stale Dated","29: Not Entitled - Incorrect Payee Name","44: Not Entitled - Payment Not Required","45: Not Entitled - Incorrect Amount","46: Not Entitled - Cannot Locate Payee","47: Not Entitled - Wrong Currency"],
        "Restricted Codes": ["34: Forged Endorsement","35: Material Alteration"]
    };

// the long values above (before the colons)

// are what I'd like to access by specified value

function SetReasonEntries()
{
   ReasonList.clearItems();
   ReasonList.rawValue = null;

   var aReasons = oReasons[xfa.event.change];
   if(aReasons && aReasons.length)
   {
      for(var i=0;i<aReasons.length;i++)
        ReasonList.addItem(aReasons[i].toString());
   }
}

1 Accepted Solution

Avatar

Correct answer by
Level 10

Hi Jono,

You can specify a bound value as a second parameter on the addItem method and then access that value using the boundItem method just like when the values are entered in the Designer.

So in your case you could load your values with ;

ReasonList.addItem(aReasons[i].toString(), aReasons[i].toString().substring(0,2));

Then in the click event (or whereever) you could use;

this.boundItem(xfa.event.change)

to return the value that was passed in as the second parameter of the addItem.

In your case you can get away with using the .substring(0,2) to get the bound value but an alternative would be to have an array of objects ;


"CHQ Returned Undeliverable Cheque": [{id: 1, text:"01: Unclaimed at Address"},{id: 2, text:"02: Unknown Address"},{id: 3, text:"03: Address Incomplete"},{id: 4, text:"04: No Such Post Office"},{id: 5, text:"05: No Such Address"},{id: 6, text:"06: Deceased"},{id: 7, text:"07: Moved, Address Unknown"},{id: 8, text:"08: Refused by Addressee"},{id: 9, text:"09: No Reason Given on Envelope"},{id: 10, text:"10: Returned Twice from Same Address"},{id: 11, text:"11: Additional Information Required - Re-Direct to Ministry"},{id: 12, text:"12: Refused - Duplicate Payment"}]
,......

Then you could have ;


ReasonList.addItem(aReasons[i].text,  aReasons[i].id.toString());

... Just in case they come up with a 100th reason for not delivering the cheque.

Bruce

View solution in original post

16 Replies

Avatar

Correct answer by
Level 10

Hi Jono,

You can specify a bound value as a second parameter on the addItem method and then access that value using the boundItem method just like when the values are entered in the Designer.

So in your case you could load your values with ;

ReasonList.addItem(aReasons[i].toString(), aReasons[i].toString().substring(0,2));

Then in the click event (or whereever) you could use;

this.boundItem(xfa.event.change)

to return the value that was passed in as the second parameter of the addItem.

In your case you can get away with using the .substring(0,2) to get the bound value but an alternative would be to have an array of objects ;


"CHQ Returned Undeliverable Cheque": [{id: 1, text:"01: Unclaimed at Address"},{id: 2, text:"02: Unknown Address"},{id: 3, text:"03: Address Incomplete"},{id: 4, text:"04: No Such Post Office"},{id: 5, text:"05: No Such Address"},{id: 6, text:"06: Deceased"},{id: 7, text:"07: Moved, Address Unknown"},{id: 8, text:"08: Refused by Addressee"},{id: 9, text:"09: No Reason Given on Envelope"},{id: 10, text:"10: Returned Twice from Same Address"},{id: 11, text:"11: Additional Information Required - Re-Direct to Ministry"},{id: 12, text:"12: Refused - Duplicate Payment"}]
,......

Then you could have ;


ReasonList.addItem(aReasons[i].text,  aReasons[i].id.toString());

... Just in case they come up with a 100th reason for not delivering the cheque.

Bruce

Avatar

Level 10

Wow, thanks Bruce.

That's opened my eyes considerably to what can be done with manipulating arrays.

Gonna take me a bit to digest!

Avatar

Level 10

Hey Bruce, just noticed you had some code up in the initalize event as well as the calculate event - there seems to be some duplication. What's the logic involved?

Avatar

Level 10

Hi Jono,

The code could be neater, the "var oReasons = ...." should probably be in a script object.

The first drop-down list is not dependent on anything so I put the loading of the items in the initialize event but as the second drop-down list is dependent on the first I put the code in the calculate event so it would fire whenever the first drop-down list changes.

Bruce

Avatar

Level 10

Hi Bruce,

    In this thread you have given a wondeful solution on the manipulation of arrays and accessing a specified value at run time..

    You also mentioned that "The code could be neater, the "var oReasons = ...." should probably be in a script object."..

     I have a situation that the array elements will be populated at the run time. I am having difficulty in assigning the elements to the array variable at the runtime. The typeof of array variable is returning as String instead of Object and hence the entire script is not working..

    Do you have any hints on how to assign the elements at the run time?

Thank you for your help..

Srini

Avatar

Level 10

Hi Srini,

I'm not totally sure I understand the problem. I made the comment about "var oReasons = ...." because this is used in a number of places and it goes against Adobe's recommentation against creating custom JavaScript properties since the introduction of the "Strict Scope Rules in JavaScript".  Two reasons for putting it in a script object.

An example of creating a array of objects from the top level of Readers menuItems is;

var

menuItems = app.listMenuItems();

var

listItems = [];

for

(var i=0; i<menuItems.length; i++)

{

    listItems.push({text

:menuItems[i].cName, value:i});

}

This creates an array of objects with a text property and a value property and looks something like (using listItems.toSource());

[{text:"File", value:0}, {text:"Edit", value:1}, {text:"View", value:2}, {text:"Document", value:3}, {text:"Annots:TopLevelMenuComments", value:4}, {text:"AcroForm:TopLevelFormsMenu", value:5}, {text:"Tools", value:6}, {text:"Advanced", value:7}, {text:"Window", value:8}, {text:"Help", value:9}]

This could then be loaded using the following code in the initialize or preOpen events [no clearItems required in preOpen];

this.clearItems();

for

(var i=0; i<listItems.length; i++)

{

var listItem = listItems[i];

     this.addItem(listItem.text

, listItem.value.toString());

}

Both arguments to addItem need to be strings which is why I call the toString() method on listItem.value.

If you are lucky enough to only have users with Reader 9.0 or later then you could use the new setItems method which is meant to be faster, though it is a shame it does have the option to take an array as an argument, so you will need to turn the array into a string.

var

listItems = [];

for

(var i=0; i<menuItems.length; i++)

{

    listItems.push(menuItems[i].cName)

    listItems.push(i);

}

this.setItems(listItems.toSource()

,2);

If that doesn't help then post your code and I'll see if I can see any problems.

Bruce

Avatar

Level 10

Bruce,

      Thank you for your prompt reply with the code snippet..

     I started modifying my code by following the sample you provided..

     In my form, the XML will have Country tag as parent and the All airports and Cities will be the child tags. In the initialization, I should populate the Country dropdown and based on Country selection I should populate the City dropdown at the client side.

     Currently I am searching thru the entire XML based on the Country code and then loop thru the City list to populate the dropdown. Which is taking more processing time. So I wanted to try your sample using the arrays. While testing, if I hard code the array values in the form, the City list is getting populated quickly with out much delay. Since the XML is being passed during the initialization, I should populate the array variable in the initialization itself and reuse it in multiple places and multiple instances inside the form.

     I am attaching the sample form in which I am preparing a string variable and then using the push method sending the data to an array variable.

     But the double quotes inside the string are replaced with escape character after I use the push method. I am attaching the form and sample XML I used. I have written the code in the initialize event of the dropdown.

     I will continue debug the problem.. and thank you for your time..

     <countryList>
          <Country>
               <Code>1E</Code>
               <Name>Europe</Name>
               <Airports>

                    <Airport>
                         <AirportCode>WPA</AirportCode>
                         <AirportName>Puerto Aisen</AirportName>
                    </Airport>
                    <Airport>
                         <AirportCode>WPR</AirportCode>
                         <AirportName>Porvenir</AirportName>
                    </Airport>
               </Airports>
               <Cities>

                    <City>
                         <StateCode>00</StateCode>
                         <CityCode>QOU</CityCode>
                         <CityName>Oued Rhiou Off-Line Pt</CityName>
                    </City>
                    <City>         
                         <StateCode>00</StateCode>
                         <CityCode>QOZ</CityCode>
                         <CityName>Oued Zenati Off-Line Pt</CityName>
                    </City>
               </Cities>
          </Country>

     </countryList>

Thanks

Srini

Avatar

Level 10

Hi Srini,

I think loading all your data (about 2Mb) into one JavaScript object is a bit much, it takes about 15 seconds on my machine.

I have left the code commented out in the sample and use an alternative method to access the city values.

I think you were having trouble with the escaped characters because you were not using the object literal syntax but a string that looked like an object literal, see my attempts for a better explaination.

Hope it helps.

Bruce

Avatar

Level 10

Bruce,

     Thank you for your response. This really helps. Your code is simple and neat. I think I should go with the second approach you provided rather than loading the 2MB data to the script object variable.

Thanks

Srini

Avatar

Level 10

Hi Bruce,

I have a similar problem to Srini and was wondering how well your sample would scale to more data items and more dropdowns...and how one might do that - my javascript skills aren't that great for complex stuff.

The data set in spreadsheet terms is about 2000 rows by up to 8 columns of data. And the need is for a user to be able to drill down the consecutive dropdowns - at least, that's the only way I can figure it can be done in LiveCycle.

I've attached a small sample xml file in the style the data will be - it's only 3 levels deep though.

Any pointers greatly appreciated!

Avatar

Level 10

Hi Jono,

It would depend on how many drop downs you are talking about.  I seem to quickly run into problems with lots of dropdowns doing lots of processing in their initialise events.

But that might not be a problem if there is one drop down with eight dependent dropdowns.

I have also started using a lot more e4x since I don't always need to support versions of Reader below 8.0.

I have a preference for using JavaScript than complicated som expressions but in Srini situation it didn't perform well.

I've attached a sample with a couple of JavaScript approaches that might help

Good luck

Bruce

Avatar

Level 10

Thanks for the help Bruce! Hopefully we can take it from there.

Yeah, I'm not sure how that will work yet...that gives me an idea though, each dropdown could have a script to populate the next dropdown instead of trying to do it all at once?

As I said, there are up to 8 columns of data and the data isn't necessarily continuous - some of the columns are empty.

I'd not heard of that before...something new to learn!  I still have a ways to go on JS itself!

Avatar

Level 8

Hi,

I find this thread useful... Thanks to all.

Tarek.

Avatar

Level 8

I've examined the code in details and I am very happy with code and the XML Data. I was actually searching for such data since quite some time.

May I ask how you did you generate the XML for Countries, Cities and Airport Data ? What was your source ?

I have the following feedback:

- The code which is populating the Country DropDown is first loading an array of object "stsTripInfo[]" and then populating the DropDown. We could have populated the DropDown directly, to save the memory usage.

- How can you sort ? I think the only way to sort XML inside javaScript in LC is to load into array, sort the array, and load the Drop-Down, right ?

- Can we generate a sorted XML from the beginning ?

Thanks

Tarek.

Avatar

Level 10

Tarek,

 

          1. May I ask how you did you generate the XML for Countries, Cities and Airport Data ? What was your source ?

          Srini: We generated the XML from SAP database.


          2. The code which is populating the Country DropDown is first loading an array of object "stsTripInfo[]" and then populating the DropDown. We could have populated the DropDown directly, to save the memory usage.

          Srini: Yes you are correct. But in our case, the data for the Country list was not sorted when the XML is generated. So I have to write the code to sort the data before loading into the Dropdown.


          3. How can you sort ? I think the only way to sort XML inside javaScript in LC is to load into array, sort the array, and load the Drop-Down, right ?

          Srini: You are correct.


          4. Can we generate a sorted XML from the beginning ?

          Srini; You can. The query to retrieve the data for input XML can sort according to Country Name/ City Name. Then you can just use the dynamic binding in the Drop down properties and you can save memory usage.

Hope this helps..

Thanks

Srini