Copy link to clipboard
Copied
I essentially have two scripts that work in unison on a PDF form, namely a custom keystroke script associated with a combo drop-down box and a document level function 'setFieldValues' invoked by the script (both provided below). The issue I am experiencing is that the scripts appear to perform without issue if the script for the combo box is placed in the 'on blur' event (a poor choice at best for obvious reasons) but fail to perform as anticipated if I were to place the script associated with the combo box as a custom keystroke script with the addition of the line 'if(event.willCommit)... in which case I receive 'undefines' (refer to screen shot) for all the form fields intended to be assigned values by the scripts. One thing I noticed is that if I were to replace the index variable 'i' with a digit from 1-14, the form fields miraculously receive the values associated therewith regardless of the selection made in the combo box which is understood. This leads me to believe that for whatever reason, the index variable 'i' is not being recognized when using the custom keystroke script. Why this is, I haven't the slightest idea. Any thoughts or suggestions as to why are most appreciated. Thank you ahead of time. Scroll down to see scripts below.
/* Custom Keystroke Script (Note: 'if(event.willCommit) was intentionally removed when the script was placed and invoked from the 'on blur' event */
if(event.willCommit){
if(event.value == "Select|Lookup Name")
resetForm(["inf"]);
else
setFieldValues();
}
//setFieldValues() function
function setFieldValues(){
var i = event.target.currentValueIndices;
for(j=1;j<15;j++){
f=getField("inf."+j);
f.value=aVendors[i][j];
}
}
Screen shots attached for reference
Copy link to clipboard
Copied
Sorry but I should have also added that when using the custom keystroke script placement, I also receive incorrect values associated with the selection made in the combo box in addition to the undefines. Once again, this makes me believe that for whatever reason the information to be provided by the index 'i' variable in the script remains suspect.
Copy link to clipboard
Copied
The "currentValueIndices" property is not set until after the selected value is committed. This is true for all field properties related to the field's value. It's instructive to place console.println code in the events to display values of interest, then watch what happens in the console as you make selections. You can see exactly how the values change and when.
But using the item index is not the best method. The list item index is not a reliable way to relate the list selection to the item values in the array, because they can get out of sync. A more reliable method is to include the item name in the data. There are two ways to this, include it as an item in the array, or switch out the array for an object.
My first choice would to store the data as an object, where the member names would be the selection value from the dropdown. And the member values would be the array of field values. Then access to the array of "inf" field values is automatic:
The code will now look like this
f.value = aVendors[event.value][j];
I would also opt to use an object for the field values, rather than an array, so the fields could be named for what they are. And the relationship between the value and the field is more reliable.
The data when converted to a string would look like this.
var oVendors = {"American Giant":{website:"dfasdf",password:"dfasdf",....},
etc.
}
Then the field names are "inf.website", "inf.password", etc.
Not a particularly compact way to store data, but very verbose and direct.
Copy link to clipboard
Copied
In answer to 'The "currentValueIndices" property is not set until after the selected value is committed...'. Thank you, I honestly wasn't aware not to mention that your recommendation regarding use of the console in this manner would have undoubtedly given me the answer as to why I was experiencing what I thought to be odd behavior to begin with.
As for using the index and array combination, I have already made provision to keep the names in alphabetical order in both the combo box and array pending addition, deletion, or modification of the array. As such I haven't yet experienced the array being out of sync with the list as the index numbers have remained in sync thus far given the script created/used. In reality, I also feel more comfortable not to mention I am altogether more familiar with and seem to fare better using arrays. I have provided the script below that I created to populate the fields based on the combo box selection for your opinion. I also added/placed the script in a dummy text field along with the script that creates the array for storing the data in the custom script. While this appears to be working like a charm so far, I realize you may still not agree for reasons I remain unaware of in which event once again your professional opinion regarding this subject matter is most appreciated. Unless I am missing something, I don't readily see how the array and list can become out of sync if I am able to maintain the same index between the array and list. Please let me know otherwise.
f=getField("cbNames");
var i = f.currentValueIndices;
for(j=1;j<15;j++){
cField=getField("inf."+j);
if(i!=0)
cField.value=aVendors[i][j];
else
cField.value="";
}
Copy link to clipboard
Copied
In going over the code snippets Thom previously provided, I have decided to try your suggestion using an object rather than an array thereby using the item's value as opposed to the index. This noted, two questions come to mind. Using an object as opposed to an array, am I better off naming the form fields as you suggest, i.e., "inf.website","inf.passsword"... vs "inf.0","inf.1"...? Also, in regard to the object
var oVendors = {"American Giant":{website:"dfasdf",password:"dfasdf",....}, etc.}, can one substitute single for double quotes? Last of all, to auto populate the form fields I am somewhat confused as to where to place the code: f.value = aVendors[event.value][j]; to asign the form field values. Your response to this subject matter is most appreciated as I believe I'm almost there given your suggestions. Thank you ahead of time.
Copy link to clipboard
Copied
Using an object to store data where the member names match the field names creates a kind of self-documenting code. There's an explicit mappting between the stored data and the related field for display. If the data needs to be transfered to another format, then the names can be used for mapping the data to another format. So it's a pretty useful technique. Although, like other verbose data formats it's inefficient.
In the official JSON format, all strings, and specifically object member names, must be double quoted. However, the old "eval()" function doesn't care. It just evaluates whatever code string it's given. So if the "eval()" function is used to restore data, then single quotes are fine. What's important is that the functions for storing and retrieving data are compatible. If the "object.toSource()" function is used to save the data to a field, the use the "eval()" function to get the data out of the field.
The code for populating the form fields should be on the Validate (or keystroke) event of the dropdown (combobox). Both of these events are triggered when the user makes a selection, which is the appropiate time to populate the fields.
I would set the field up to commit the selection immediately. The code for each event is slightly different. Writing code for a Validate event is simpler and it's the one I'd choose.
Copy link to clipboard
Copied
Just wanted to let Thom know that I have decided to follow his lead regarding using the object as opposed to an array and am gald I did since I have only one issue remining to resolve. In reality, I also toyed with the JSON stringify and parse methods that enabled me to save and extract my data from a text field object Thom had suggested earlier that FWIW worked likw a charm (Thank you Thom). The only issue remaining in which I am having a problem is creating the script to populate the form fields from the data stored inside the object based on the selection in the combo box whereby I have two questions, namely: Instead of using the code (syntax) Thom provided, i.e. f.value = aVendors[event.value][j], to access the object in assigning values to the form fields, shouldn't I be using something similar to 'for(var key in oVendors){ ...) similar to what I used and worked to populate the combo box from the names contained in the data object I am presently using? I would also imagne that I would need to refer to a 2nd key or am I off base here? On a plus note, I am so close to accomplishing everything I set out to thanks to Thom.
Copy link to clipboard
Copied
You are absolutely correct! Using an object to store data means that the members must be accessed differently.
Try this code in the validation script for the dropdown. It assumes the form fields are named the same as the member names, i.e., "inf.website", etc.
var oFld;
var oPassData = oVendors[event.value];
if(oPassData)
{// walk members to fill fields
for(var nNm in oPassData)
{// skip fields that don't exist on form
oFld = this.getField("inf." + nNm);
if(oFld)
oFld.value = oPassData[nm];
}
}
else // Reset form fields
this.resetForm("inf");
Copy link to clipboard
Copied
Thanks a bunch. Will try the script you provided. FWIW, while you were so prompt with your reply, I decided to return to the forum to provide the script I did end up trying to no avail as I was under the impression it would work. Unless of course it failed simply because I didn't place it in a validation script as u had recommended. Hmmm?
aField =getField("dataStore");
oVendors = JSON.parse(aField.value);
for (event.value in oVendors) {
for(j=0;j<15;j++){
f=getField("inf."+j);
f.value = oVendors[event.value][j];
}
}
Copy link to clipboard
Copied
if "dataStore" is the name of the dropdown, then the script would not work if placed in any of the value related events for that field. The reason is that the actual selected value of the field is not in the field's "value" property, because it has not yet been commited to the field. During value related events, the newly, pre-commited value, is only available through the event object.
Copy link to clipboard
Copied
Thom,
I will have to take another look but 'dataStore' refers to the dummy text field that stores the data object as a string and gets parsed using JSON whereas event.value denotes the selection or value in the combo drop-down box. This in turn is used to match the name in oVendors to populate the form fields associated with the name selected in the drop down. Does this make sense? I should also state that the form fields in this instance were named inf.o, inf.1, inf.2, .......inf.14. I'll have to play with this some more. Also, come to think of it, my adding another inf field namely inf.o for name I believe screws everything up since the first object or property pair in the nested obects is 'LastUpdate' that would correlate with inf.0 not inf.1. Since the names in the data object lay outside the nested data objects they should not be in the loop. Does this all make any sense to you? At least one thing, thanks to my perseverance and your advise, I've managed to get this far and I at least know what I am trying to achieve can be done. I really do appreciate the help you've provided in my endeavor thus far and I still believe you should write the book I suggested in a previous post..
Copy link to clipboard
Copied
I answered too fast without properly looking at the code. My appologies. Essentially you've tried to mixed the code for restoring the saved data and populating the fields. These operations should be completely separate.
But regardless, this line in particluar is a big problem:
for (event.value in oVendors) {
"event.value" cannot be used like this. Please lookup how the "for" statement is used in a Core JavaScript reference.
This will work, if placed in the Validation event of the dropdown.
var oField =getField("dataStore");
oVendors = JSON.parse(aField.value);
for(j=0;j<15;j++){
f=getField("inf."+j);
f.value = oVendors[event.value][j];
}
However, additional code should be added to use only the array entries that are there, and for protecting against invalid field names, and for handling the default (blank) selection.
var oField = this.getField("dataStore");
oVendors = JSON.parse(aField.value);
var aData = oVendors[event.value];
if(aData)
{
for(j=0;j<aData.length;j++){
f=this.getField("inf."+j);
if(f)
f.value = aData[j];
}
}
else
this.resetForm("inf");
Copy link to clipboard
Copied
In response to the script you provided, I used this initially. Howver, when it failed to produce results, I then added the for (event.value in oVendors){... thinking it was more appropriate given the transition to the object per your recommendation. However, as you pointed out, I was unaware that this particular line of script was incorrect. I since tried the other script again whereby the only minor change I made was renaming the 'datastore' field to 'datasource' and changing j<15 to J<14 since there are actually only 13 paired property values for each name. However, the result failed once again giving me undefines in the form fields. Maybe I just need to take a break and try again later on in which event I'll let you know the outcome. On another note, I did add to the script to handle no selection which in my case is the combo box 'Add/Lookup' or default item. Although I am not finished, the way I have it setup for now, I really cannot select an invalid field name at this time since all names in the list are the same as those contained in the data object. While not fully implemented, I already thought about several scenarios whereby the data object will obviously require updating as well as the combo drop-down list of names given a name/record being added or deleted. Then there is the case for editing values associated with each name/record but I'm getting ahead of myself. First things first, so I really need to get this fields population to work and I believe I can adress everyhing else accordingly. Thanks again for your input.
Copy link to clipboard
Copied
The validation script I ran provided below and the undefines (image file attachment) displayed in the form fields. Hmmm? Back to the drawing board.
var oField =getField("dataSource");
oVendors = JSON.parse(aField.value);
for(j=0;j<14;j++){
f=getField("inf."+j);
f.value = oVendors[event.value][j];
}
Copy link to clipboard
Copied
The key to figuring out any problems with the code (because there can easily be mismatches between what I'm thinking and what you actually have on the form) is to use "console.println" statments in the code so you can see what the actual values are that are being selected. The console window also displays any errors that occur.
This particular code is intened to be used in the situation where the field values are stored in an array, not an object, following the side question you asked above. So if the data is actually an object, then "undefined" values in the fields would be the natural result, because the indexed array values do not exist.
It is very important that there is consistency between the data, the code, and the fields. So, when trying out new techniques, you have to be aware of these issues. Using the console window properly will solve this problem, because you will know write away if there is an inconsistancy, or an error.
Copy link to clipboard
Copied
In reviewing the validation script, it just didn't make sense to me why it failed. In checking the JS debugger, I thought you might be interested in the validation script type error showing oVendors[event.value] to be undefined (refer to image file attachment). Again, this doesn't make sense as to why but explains why the script failed given the undefine for the event.value in which case the script can't perform as intended to populate the fields.
Copy link to clipboard
Copied
Sorry but I didn't initially finish reading your entire comment regarding the validation script was intended for data containing the field values to be stored in an array not an object that obviously explains the undefines. Boy, now I'm really confused as I was under the impression the script was written for an object as that is what I transitioned to. Well at least the script I used to store and extract the data to/from the dummy worked using JSON. This being the case, can the validation script be easily modified to work for the object, oVendors?
Copy link to clipboard
Copied
I already provided code for transfering data in object form to the fields a few posts up. I've reposted it below.
But first, let me review the code in the previous post.
When the data is stored in an array like this:
var oVendors = {"American Giant":["www.something.com","mypassword",....],
etc.
}
Then the data is acquired with index numbers. To match the fields on the form, the fields were also named with numbers
"inf.0", "inf.1", etc.
So the loop that sets the field values uses the same index for both the data and the field name.
Note also that in the code I provided, that the loop limit is not hard coded, but rather uses the actual data array length. This is an important programming technique. Don't hard code values you don't have to. It's much better to use parameters that are naturally available, i.e., when iterating over an array, use the array length.
The code below assumes the data is stored in an object. In this case the data is accessed with a member name, and to match the fields on the form, the fields use the same name.
Data:
var oVendors = {"American Giant":{website:"dfasdf",password:"dfasdf",....},
etc.
}
Fields:
"inf.website", "inf.password", etc.
var oFld;
var oPassData = oVendors[event.value];
if(oPassData)
{// walk members to fill fields
for(var nNm in oPassData)
{// skip fields that don't exist on form
oFld = this.getField("inf." + nNm);
if(oFld)
oFld.value = oPassData[nNm];
}
}
else // Reset form fields
this.resetForm("inf");
Copy link to clipboard
Copied
Thom,
Thank you for your help and patience thus far. I should probably state that I am indeed rusty as I have been away from Acrobat and JS for well over 10 years during which time I also suffered a stroke in 2016. While this has had somewhat of an adverse effect on my cognitive abilities, I make no excuses but rather wanted to let you and others who may have been following this post on the forum that I'm not crazy given I may occasionally fail to process the information individuals like yourself provide. Anyway, I just wanted to thank you and others on the forum for all your help which has been a God send in helping me relearn many things I forgot as well as apprising me about the likes of JSON of which I was totally unaware. I will definitely take the time to review your latest comments regarding the latest scripts you provided and let you know how it turns out. At least I believe I am beginning to see the forest for the trees.
Copy link to clipboard
Copied
Thom,
You have no idea how you made by day! All I needed to do was add two lines of code to access the oVendors object stored in my text field as follows:
dataField =getField("dataSource");
oVendors = JSON.parse(dataField.value);
and correct for a minor typo error, i.e., change 'nm' to 'nNm' to eliminate an undefine and voila, the script works like a charm. I still cannot believe my eyes. Anyway, do you by chance drink Starbucks coffee or is that a dumb question to ask a programmer? If so, I would like to send you a Starbucks gift card as a small token of my appreciation for all the help you have given me. If so, please provide me your email address in confidence as to where I can send it using my personal email address that I believe I can send to you using the form on your PDF scripting site. This aside I just have a couple of very general questions regarding field naming conventions and the ampersand character that seems to be giving me a headache. As for field naming conventions, as I recall, I have elected to adopt camel case, i.e., userID, primaryCC, primaryBank, etc. Is that considered acceptable practice? Regarding the '&', is there anyway I can escape the ampersand in JS to avoid a syntax error in a script I eventually require to update oVendors b4 converting to a string using JSON? Thank you ahead of time.
Copy link to clipboard
Copied
You're welcome, and good catch with the error in the loop variable. I type this stuff really fast and don't always catch those kinds of issues. You can message me through this forum, or at www.pdfscripting.com
Any character can be used in a field name, including white space and punctuation. Variables can only use regular characters. There are no exceptions. Camel case is the standard for variable names, not field names. But it' not a bad idea to
Where exactly is it that you want to use an "&"?
Copy link to clipboard
Copied
I may have jumped the gun regarding the '&' as it may not pose a problem with using the form itself to add a name/record. The problem occured when I created a temporary button for use in converting the oVendors object in its JS format to a string using JSON stringify to store in my hidden dataSource text field. The button is only temporary. What happenned is that the Javascript that created the object throws a syntax error if I insert an '&' typing AT&T in the JS that resides inside the button 'mouse up' action script. I can easily get around this by changing it to ATT and then add the '&' back in to the oVendors string stored inside my hidden field. Depending upon the task, since the form only requires going back and forth between JSON stringify and parse, there shouldn't be an issue with the '&' for now.
Copy link to clipboard
Copied
Be more specific about the code where the "&" was inserted, i.e., show the code. Using the & in an object, as part of either a member name or value will not cause an error if done properly.