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

Drop down list returns to first value

New Here ,
Feb 08, 2023 Feb 08, 2023

The form I'm creating uses mulitple drop down fields who's values are combined to create a unique part number.  I'm having issues with the drop downs reverting to the first option in the list (''") after selection.  The fields are populated via .setItems in a single Custom Calculation script (vs. script in multiple fields).

 

I've seen other posts solve this with moving the .setItems scriptto Custom Validation, which solves the 'repopulating' issue, but this then creates the problem of the lists not updating if the array used to create the list is modified.  So, this is not the answer for me.

 

Best I can tell, this is caused by the script cycling back through and the list 'repopulating', even though the value selected by the user is still current value of the field.  I've had moderate success with using an if statement to 'lock out' the list so that it will not 'repopulate' (example below), but this is currenlty not working and I don't understand why.  Is there a better way to do this?

 

     var count = this.getField("X");

      if(count.numItems === 0 || Current_array !== X_array) {
           this.getField("X").setItems(X_array);
      }
      var Current_array = X_array;

 

I'm  running Adobe Acrobat Pro DC (32-bit) 21.11.20039.

Appreicate any help. 

 

 

TOPICS
Create PDFs , General troubleshooting , How to , JavaScript , PDF forms
6.6K
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 ,
Feb 08, 2023 Feb 08, 2023

All calculation scripts are executed each time the value of any field in the field is changed, and when you use the setItems method the field will revert to the default value, which is the first item in the list. That's the reason this is happening.

There are various solutions:

- To use a Validation script (as you've mentioned), since it only executes when the value of that field is changed (as opposed to the value of any field). You didn't really explain what the issue with that is, or how you're populating the array with the values... Why not update that array in the code, when you need to update the field?

- Add a condition to the calculation script to only proceed if a specific field has triggered the event (by checking the value of event.source.name).

- Save the field's current value before calling setItems, and then apply it back afterwards, to keep that value as the selected one. This will only work if the value that was selected before is still present in the new list, of course.

 

Out of all of these solutions the first one is the best one, in my opinion, especially if you have many fields in your file.

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
New Here ,
Feb 09, 2023 Feb 09, 2023

More background - I've set my form up so that all the script runs from one field's Custom Calculation script.  This was done to faciliate easier updating and maintanence, as this form will be propigated to many variations to create various part numbers based on other specifications.  Currently 12 fields are used in defining the final part number.

 

Validation issue - When moving the .setItems to custom validation of the field with the custom calcuaiton script, and  then updating the object propertiers that are populated by the associated arrays, the lists did not update. The lists would update with the chaange with the .setItems as part of the calculation script.  I tried moving one of the .setItems to its respective drop down field's custom validation script and the file got stuck in a loop requiring a force close of Acrobat.

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 ,
Feb 09, 2023 Feb 09, 2023

Sorry, I don't follow. What "properties" are not updating, exactly? Could you share the actual file?

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
New Here ,
Feb 14, 2023 Feb 14, 2023

Sorry, I can't share the file.

 

By "properties", I'm referring to a value within an Object being changed.  Below is an example of the Objects I use to fill the drop down list via an array.  If I change Mat_A_Obj's 'material' from "Material A" to "Material AA", the list was not updating.

 

var Mat_A_Obj = {code: "A", material: "Material A", materialSpec: "1"};
var Mat_B_Obj = {code: "B", material: "Material B", materialSpec: "2"};
var Mat_C_Obj = {code: "C", material: "Material C", materialSpec: "3"};


var X_array = ["", Mat_A_Obj.material, Mat_B_Obj.material, Mat_C_Obj.material];

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 ,
Feb 10, 2023 Feb 10, 2023

The "field.setItems" function will trigger a cascade of events, because it changes the value of the list/dropdown field. If this is necessary, then use a blocking variable to prevent recursion.

For example, put this code at the top of the script

 

if(!this.bBlock){

     this.bBlock = true;

 

Then at the end of the script:

 

    this.bBlock = false;

}

 

The putting all the code into a single calculation script is not a good technique.  It would be better to create document level functions that are called from the relavant events. This still puts all the code into a single location for simpler maintenance. 

But if you are going to use this technique, another method for preventing runaway execution (besides the blocking variable) is to use selective execution based on the field that is triggering the event.

 

And finally to repeat Try67s last point. If a list field is being modified, then the previous value needs to be saved and restored. 

 

var oldValue = oFld.value;

oFld.setItems(..);

oFld.value = oValue;

 

 Be aware, both the "setItems" and setting the value will trigger an event cascade. 

 

 

 

     

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

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
New Here ,
Feb 14, 2023 Feb 14, 2023

I was not aware of the blocking function, thank you for sharing this.  This is in essence what I was trying to accomplish with the if statement I posted, while allowing for the drop down list to be updated if there was a change.

 

Forgive me, I'm still a novice and couldn't find 'this.bBlock' in the Acrobat API.  Is .bBlock a standard function(?) like .getField or .setItems?  'b' is not a variable, field title, or ...? 

 

WRT restroing values, should the last line be oFld.value = oldValue;?  Also, these three lines should be listed sequencially as shown?  I set up a test run and get the following error when trying this:

 

        InvalidSetError: Set not possible, invalid or unknown.
        Field.value:3:Field Test_Drop:Calculate

 

Test script: (Custom Calculation script in field "Test")

   var oldValue = this.getField("Test_Drop").value;
   this.getField("Test_Drop").setItems(["", "1", "2", "3"]);
  this.getField("Test_Drop").value = oldValue;

 

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 ,
Feb 14, 2023 Feb 14, 2023

 "this.bBlock" is a custom document level variable. Just something I developed to handle exactly the same issues you are seening. 

 

Your test script looks good, except, you do need to make sure the old value is in the new set of entries. If it's not you'll get the "InvalidSetError". 

For Example

 

var aItems = ["", "1", "2", "3"];  

this.getField("Test_Drop").setItems(aItems)

if(aItems.some(a=>a==oldValue))

     this.getField("Test_Drop").value = oldValue;

  

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

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
New Here ,
Feb 14, 2023 Feb 14, 2023

Thom, I got the same invalid error.  I also tried the below script, with the same result.  The app.alert pops up correctly, but the srcipt errors out when trying to set the Test_Drop field to oldValue.

 

var oldValue = this.getField("Test_Drop").value;
var aItems = ["", "A", "B", "C"];

this.getField("Test_Drop").setItems(aItems)

if(aItems.indexOf(oldValue)==-1){
app.alert("Value NOT found in array.",3);
} else {
app.alert("Value FOUND in array.",3);
this.getField("Test_Drop").value = oldValue;
}

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 ,
Feb 14, 2023 Feb 14, 2023

Where did you put this code?

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
New Here ,
Feb 15, 2023 Feb 15, 2023

Created a blank form, with one text field and one drop down field.  Script went in the custom calculation script of the text field.  This mimics how the other form is structured.

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 ,
Feb 14, 2023 Feb 14, 2023

don't make one of the new items an empty string. Make it a single space or a dash.

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

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
New Here ,
Feb 15, 2023 Feb 15, 2023

Same result with your version and my version of the script using a "-" instetad of "".  I've attached the test file.

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 ,
Feb 15, 2023 Feb 15, 2023

The problem is this script conflicts with the value selected by the user. When should this code execute, exactly? It doesn't make sense to use it as a calculation script, as that executes each time any field in the file is edited.

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
New Here ,
Feb 15, 2023 Feb 15, 2023

We've drifted a little off the orginal target of not having the drop down return to the first value of the list.  I do need help solving the current conversation for a different scenario.  I'll start a new thread for that.

 

Back to the drop downs.  Here is an updated test file with how I structure the script (has my original and Thom's suggested scripts).  The goal is for .setItems to only execute if the drop down field is empty (e.g. after a reset of the form that clears all fields), or if there is a difference between the Currrent_array and X_array values.  If not, then the list would not be repopulated (i.e. reset to first value).

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 ,
Feb 15, 2023 Feb 15, 2023

Actually we haven't drifted off the original topic. As we've already established, the "setItems" funtion causes the value of the list field to change to the first item in the new list. That's how it works.  If you want the value to be something else, then it has to be set after the setItems call.

The problem is that setting the value of the list field with setItems starts off a cascade of the value change events.  To see this your script should use "console.println" statements instead of "app.alerts" which break up the real event processing. In fact, you should place "console.printlns" in all of the events for the list field so you can see the complete sequence as it unfolds. 

 

This sequece is "Comment > Validate > Format > Calculate".  But you're already in a calculate event, and the JavScript model prevents reentrant calculations. This is why there is a calculation order. When one field changes, all the other calucualtions take place in order without causing new calculations. I believe that setting the value of the list field a second time causes it to choke because the value of the list field from the first set hasn't settled yet, so it can't be set from outside the event structure. 

The solution would be to 

1) not use a calculation

2) set the new list field value from inside the event structure. For example, set it from the validation event on the list field. 

To do this the desired value would need to be saved in a document variable in the calculation script, then conditionally set in the validation on the list field. 

 

I think #1 is the best solution. There are just too many issues with calculations, I avoid them as much as possible. And when using calculations I avoid creating complex and reentrant cascades of events. 

 

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

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
New Here ,
Feb 15, 2023 Feb 15, 2023

I'm not trying to replace the value of the drop down field with a new value.  I just want the user selection from the list to stay visible.  And, when an Object value gets changed (likely manually in the script) have the list repopulate accordingly; this is where using a validation script was not successful for me (admittedly with only a quick test when you and Try67 suggested it).

 

I think the script in my orginal post in this thread avoided reentrant calculations.  Is that a true statement?  If not, please point it out, and I'll add it to the list of what I need to (re)learn. 🙂

 

Also, thanks for the reminder on using console.println().  app.alert was the first way I learned I can get feedback as the script runs.  I just happend to copy a section from those days since I knew it worked.

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 ,
Feb 16, 2023 Feb 16, 2023

I would suggest placing console.println statements in all of the list field events, as well as at each location in the calculation script where the list is modified. Then you can see the exact sequening of events, and the values at each step. 

 

Acrobat Blocks reentrant calculations as I explained in the previous post. So in this case the blocking variable isn't really necessary. I originally developed this technique when using validation events with a set of interdependant dropdowns that reset the list items.  

 

And the fact is that your are in fact trying to replace the dropdown value with a new value. The previous value is lost whenever the items are reset. So you're changing it when setting the new items, and changing it again when restoring the previous value. 

 

And I provided you with an idea for a solution to restore the previous value, i.e., set the old value inside the event structure. 

 

 

 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

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 ,
Feb 15, 2023 Feb 15, 2023

Why are you placing the script under the Calculate event of the "Test" text field? What does it have to do with it?

There's no logic behind executing this script all the time. There needs to be some kind of event that triggers updating the list. What is that event?

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
New Here ,
Feb 16, 2023 Feb 16, 2023
LATEST

"Test" field represents the field where the part number is created from the other 12 fields in the form.  "Test_Drop" represents one of the 4 drop downs that have to populated (.setItems) and the user selected to gerenate part of the part number.

 

I've successfully gotten the lists to keep the selected value, and have the lists update when I edit the script manually, by correcting the array comparison.  By converting the arrays to strings, the if statment now locks out the resetting of the list.

      if(count.numItems === 0 || JSON.stringify(Current_array) !== JSON.stringify(X_array)) {
           this.getField("X").setItems(X_array);
      }
      var Current_array = X_array;

 

I guess the events that should trigger this portion of the script are if the rest button is clicked (clears the form of all selections/entries), or if the list values are changed in the code.

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