Expand my Community achievements bar.

xfa.host.importData("") breaks all my custom classes

Avatar

Level 2

Hi, All

I'm new to ADOBE programming, but have a lot of experience with the mainstream JavaScript (web).

I'm completely lost with this problem and any help would be greatly appreciated.

===================================

I have a form with several custom classes. Each custom class is a script object on the form level.

I also have a data connection to an XML file - but no fields for this file (the idea is to read the data from it and populate the form dynamically based on multiple conditions.

On the form I have a button with a CLICK event that does the following:

- uses some of the custom classes to build some data structures and form view objects.

- loads data from the XML with xfa.host.importData("");

- uses some more of the custom classes to populate form view objects with data from the XML.

The form is supposed to be used in ACROBAT without any server connections.

I test the form in ACROBAT PRO (cannot execute importData() in Designer).

After the call xfa.host.importData("") all my custom classes are lost, i.e. are unreachable in code - the debugger shows exception on 1st statement where a custom class is used.

===================================

I'll provide any additional info (code, PDF, XML) as needed.

Thanks,

Gene

13 Replies

Avatar

Level 7

What do you mean by "custom classes"? There is no concept of a class in LiveCycle Designer, and the only state that exists outside of form objects are in form level variables and form level scripts.

Avatar

Level 2

Hi

Thanks for responding to my post.

On my form I have a bunch of script objects - under the "variables" node.

Some of them are just general purpose functions, while others are classes that encapsulate functionality required for my form.

In particular the form must build a series of subforms (tables) with certain rows that are to be filled from an XML data file.

There's quite a bit of logic (mapping and referencing) involved, so having it structured in OO way is highly beneficial.

Below is an example of one of the classes:

//=== start of example =============================================

abap.#variables[0].MasterCopyItem - (JavaScript, client)

//=== BEGIN: MasterCopyItem Declaration v. Aug 29, 2014 ===

//{tagGS1, txtLCL, data_EN, data_FR, txtNote, editable_EN:bool, editable_FR:bool, mappedSAP: bool}

function McItem() {

    //=== see: ===

    //http://blogs.adobe.com/formfeed/2009/09/script_objects_deep_dive.html

   

    // Declare these variables and keep them private

    var tagGS1 = "";

    var txtLCL = "";

    var data_EN = "";

    var data_FR = "";

    var txtNote = "";

    var editable_EN = false;

    var editable_FR = true;

    var mappedSAP = true;

    // Declare these functions and make them public

    this.getKey = function() {return "key:" + tagGS1;}

   

    // Provide accessors to private variables

    this.setTagGS1         = function(pData) { tagGS1              = pData; }

    this.setTxtLCL         = function(pData) { txtLCL              = pData; }

    this.setData_EN     = function(pData) { data_EN          = pData; }

    this.setData_FR     = function(pData) { data_FR          = pData; }

    this.setTxtNote     = function(pData) { txtNote          = pData; }

    this.setEditable_EN = function(pData) { editable_EN     = pData; }

    this.setEditable_FR = function(pData) { editable_FR     = pData; }

    this.setMappedSAP     = function(pData) { mappedSAP          = pData; }

    this.getTagGS1         = function() { return tagGS1; }

    this.getTxtLCL         = function() { return txtLCL; }

    this.getData_EN     = function() { return data_EN ; }

    this.getData_FR     = function() { return data_FR ; }

    this.getTxtNote     = function() { return txtNote ; }

    this.getEditable_EN = function() { return editable_EN ; }

    this.getEditable_FR = function() { return editable_FR ; }

    this.getMappedSAP     = function() { return mappedSAP ; }

   

    this.getAsString     = function() { return "TAGGS1:" + tagGS1 +

        ", TXTLCL:" + txtLCL +

        ", DATA_EN:" + data_EN +

        ", DATA_FR:" + data_FR +

        ", TXTNOTE:" + txtNote;

        ", EDITABLE_EN:" + editable_EN +

        ", EDITABLE_FR:" + editable_FR +

        ", MAPPEDSAP:" + mappedSAP;

    }

   

}

{   // add braces to hide this declaration in Reader

    var Instance = new McItem();

}

function newItem() {

    return new McItem();

}

function setTagGS1(pData)         { Instance.setTagGS1(pData); }

function setTxtLCL(pData)         { Instance.setTxtLCL(pData) ; }   

function setData_EN(pData)         { Instance.setData_EN(pData); }   

function setData_FR(pData)         { Instance.setData_FR(pData); }   

function setTxtNote(pData)         { Instance.setTxtNote(pData); }   

function setEditable_EN(pData)     { Instance.setEditable_EN(pData); }   

function setEditable_FR(pData)     { Instance.setEditable_FR(pData); }   

function setMappedSAP(pData)     { Instance.setMappedSAP(pData)  ; }   

function getTagGS1()             { return Instance.getTagGS1(); }

function getTxtLCL()             { return Instance.getTxtLCL() ; }   

function getData_EN()             { return Instance.getData_EN(); }   

function getData_FR()             { return Instance.getData_FR(); }   

function getTxtNote()             { return Instance.getTxtNote(); }   

function getEditable_EN()         { return Instance.getEditable_EN(); }   

function getEditable_FR()         { return Instance.getEditable_FR(); }   

function getMappedSAP()         { return Instance.getMappedSAP()  ; }   

function getAsString()             { return Instance.getAsString(); }

function getKey()  { return Instance.getKey(); }

function setAll(pData)          {

    //=== pData must be array of 8 items ===

    Instance.setTagGS1(pData[0]);

    Instance.setTxtLCL(pData[1]) ;    

    Instance.setData_EN(pData[2]);    

    Instance.setData_FR(pData[3]);    

    Instance.setTxtNote(pData[4]);    

    Instance.setEditable_EN(pData[5]);

    Instance.setEditable_FR(pData[6]);

    Instance.setMappedSAP(pData[7]);

}

//=== END: MasterCopyItem Declaration ===

//=== end of example =============================================

Here's an example using an object of this class in code:

oMCI = MasterCopyItem.newItem();
if (itemLblEquiv!=null && itemLblEquiv.value!="")
   oMCI.setTagGS1(itemLblEquiv.value);

    else

   oMCI.setTagGS1(itemGs1Element.value);

   

    oMCI.setData_EN("some text");
    oMCI.setData_FR("some text");

    oMCI.setTxtNote("TODO-" + i + " -Notes");

    oMCI.setTxtLCL(some-value);

    oMCI.setEditable_EN(true);

    oMCI.setEditable_FR(true);

    oMCI.setMappedSAP(true);

//====================================================

This code works before I try to invoke the xfa.host.importData();

After this call any of the objects become Undefined, i.e. the call

oMI = MasterCopyItem.newItem();

fails with the exception "Undefined".

And any other call to any other of the script object to create a custom object creates this exception.

I can send you the complete form if it makes it easier to resolve.

Thanks,

Gene

Avatar

Level 10

Hi Gene,

Maybe try fully qualifying the reference to the script object, so if the scrip object was called Script use;

xfa.form.resolveNode('#subform').Script

Regards

Bruce

Avatar

Level 2

Thanks for your response, Bruce.

This script object works fine before the call to xfa.host.importData();

And it is not fully qualified via resoveNode() - I just call it using the notation <script object name>.<function name>.

So why would it need resolveNode() after importing data on the data connection that existed in the form from the beginning?

Apparently I'm missing some important point in understanding the LiveCycle/ACROBAT runtime programming model.

I just have no time to take full blown ADOBE course set as our consultants advise.

And I only need to create this one form.

Avatar

Level 10

Not sure I can help on the why, I have had the same problem using remerge(), so is worth a try

Avatar

Level 2

Interesting. I'll definitely try later today and will update the notes. Thanks

Avatar

Level 2

I have to postpone further testing for one stupid reason - my trial period for ACROBAT PRO has just ended.

So now I have to wait till my management pays for the legal copy to continue with this development.

I'll update the post as soon as I have any info.

Avatar

Level 2

I tried to do the same in the READER - looks like I can still use it to test the code until I get the legal version of Acrobat.

I tried the suggested way of referencing the script object with fully qualified name - seems to work!

Go figure...

Now I need to solve this:

- I have the xfa.host.importData(); statement that must load the data XML, but I have no fields to directly display this data. Instead I need to iterate through this XML in code and retrieve specific nodes and populate my view programmatically.

- How do I specify the path to the XML nodes of the data? My data connection looks like this:

DataConnection

- @version

- values

  - LABELDATA   - root of the actual data

    - ..... - further levels of the actual data

Thanks, Gene

Avatar

Level 10

Hi Gene,

I'm not sure I understand your data connection structure, but to reference the top element in the data connection you can use;

xfa.datasets.data.nodes.item(0)

So to list all the elements at the next level

for (var i = 0; i < xfa.datasets.data.nodes.item(0).nodes.length; i++)
{
    console.println(xfa.datasets.data.nodes.item(0).nodes.item(i).name)
}

You can also use the somExpression to go to specific nodes.

xfa.datasets.data.resolveNode('...')

You will get a dataGroup object (for a complex type) or a dataValue object (for a simple type).  A dataValue object has a value property.

You can also use E4X (E4X in Form Design) or XPath (via the XMLData.applyXPath method http://help.adobe.com/livedocs/acrobat_sdk/9/Acrobat9_HTMLHelp/wwhelp/wwhimpl/js/html/wwhelp.htm) depends which you are most confortable with.

Regards

Bruce

Avatar

Level 2

Thanks a lot for your input, Bruce!

I can't try this at this moment as my trial of ACROBAT PRO expired and I've no access to another full PRO instance.

I'm hoping to get access later today or tomorrow and test this as well as usage of my "custom classes" with fully qualified naming after the call to .importData().

I'll update the post as soon as I have anything new positive or negative.

Gene

Avatar

Level 2

Hi, Bruce

I installed ACROBAT trial on a dev server and now have another 30 days of trial (or till my PM pays for the license).

It looks like I'm missing something important in understanding the programming model of ACROBAT.

Here's what I'm trying to do with my form:

1) The form must look like a series of simple tables - each having:

    - heading

    - 3 columns and several rows (see screenshot below)

2) The actual number of tables, their headings, number of rows in each and the row headings are defined by a mapping file. This mapping file is converted into XML string and is part of the code.

3) There's also a data file - XML - too complex to be directly populated into the form via a data connection. The form has a data connection to this data XML file (sample file or schema).

4) When the form opens it automatically loads the mapping XML string (using)

    xfa.datasets.loadXML(strXML, false, false);                             
    xfa.datasets.saveXML();                                                 

After this the code builds the required series of tables - each with proper heading, number of rows and row headings based on this loaded mapping.

5) Next the code tries to load the data XML file using the importData() method. The user is asked to point to the file.

6) Next the code must iterate by the mapping structure and for each target data element (to be shown in one of the tables/rows) to find appropriate element in the data XML.

7) Finally the form is saved.

8) There are more activities but I need to resolve the data loading issues first.

===========================================

Issues that I'm having:

1) after I execute .importData() all the dynamically built tables are lost - the form reverts back to original state before building these tables.

2) any code after .importData() does not execute.

This tells me that I'm missing something in the whole programming model.

Thanks

GeneScreen-1.jpg

Avatar

Level 10

Hi Gene,

The importData causes the form DOM to be rebuild, the template and the new data are merged to create the form DOM.  It is in the form DOM that your code is executing so after the importData the next line is lost.  You maybe able to work around this by moving your code to a function in a script object and calling that.

I am a but curious about the structure of the XML being too complex, I've only had one problem and that was with an inverted XML structure with multiple levels of nested inserted structures.

Another approach is to use util.readFileIntoStream() and then util.stringFromStream() to get your XML and load that into a separate dataset (like you seem to be doing for the mapping data).  Then your JavaScript could process that XML and update the form DOM directly (adding rows with addInstance() and setting the fields rawValue).  That way the XFA form data unloader will sort out creating the data connection.

Also XFA forms have an XSLT processor, so maybe after you load the XML you can run an XSLT to create the data connection XML and do a loadXML/remerge.

Regards

Bruce

Avatar

Level 2

Hi, Bruce

Thanks for your kind response - really appreciate it!

Unfortunately the kind of explanations that you give is impossible to get from the official ADOBE documentation.

Now that you explain it - it makes sense.

When I tried to reverse the sequence of actions - first execute importData(), then all the rest - it seems to be working:

button1-> importData()

button2-> load mapping via XML string

button3-> parse mapping, build mapping object hierarchy, then build form view - series of subforms

button4-> finally populate subforms with data from loaded XML based on mapping objects

Currently it's in the form of individual button actions for unit test purpose.

When I'm confident with unit testing I'll combine code into one action - on load or with a single button.

All my custom code (i.e. "classes" and utility methods) is in script objects - one object per class or family of methods and the event code contains only functional activities.

At this moment I'll try to avoid XSLT as the mapping implementation is quite simple (EXCEL -> ACCESS - > XML string -> copy-paste into script code) and allows easy maintenance - and I expect many changes from users.

I'll also have to deal with other challenges later:

- loading an updated version of data XML into the form after users made data entry (uploadable fields and editable do not mix)

- creating output from the combined set of fields into yet another XML file targeting another application (not PDF form).

I'll also try the methods util.readFileIntoStream() and then util.stringFromStream() - this maybe another solution.

I'll update the post when I have more info.

Thanks again,

Gene