Populating grid record field values from custom lookup

Hi, I got a table in which one row can contain hand-typed data and another row data will have a copy of values from another table. In my example I got custom (in-memory) table called DPTable1, which has 4 columns as follows:

LogisticsElectronicAddressRecId (existing AX EDT)
LogisticsElectronicAddressLocator (also existing AX EDT)
Description (also existing AX EDT)
SomeOtherStringField (my own EDT)

I created a new form by means of SimpleList wizard, called DPSimpleList, added DPTable1 to data sources of the form and set DataSource property of the grid control. I then added 3 fields on to the grid from my one and only datasource:

DPTable1_LogisticsElectronicAddressLocator
DPTable1_Description
DPTable1_SomeOtherStringField

Here’s how my project looks so far (hope I didn’t forget anything):

On my form I want the user to either populate 3 controls in each row by hand, or use a custom lookup attached to the DPTable1_LogisticsElectronicAddressLocator control, in which case the 2 of the 3 controls in the grid record will be populated for the user from LogisticsElectronicAddress table based on lookup selection.

From here I’m leaving this up with the Gurus of this venue in hope that someone will offer a solution.

Just to bring up other things I’ve tried so far. I’ve googled many posts with various examples for different lookups, but wasn’t able to find just the one that really fits my bill.

In one approach I set Lookup=“Always” property on DPTable1_LogisticsElectronicAddressLocator control and override lookup() method with the following code:

public void lookup()

{

Args args = new Args();

FormRun formLookup;

LogisticsElectronicAddressLookup lookup = LogisticsElectronicAddressLookup::newParameters(this);

lookup.parmMethodType(LogisticsElectronicAddressMethodType::Email);

args.name(formStr(LogisticsElectronicAddressLookup));

args.caller(this);

args.lookupField(fieldNum(LogisticsElectronicAddress, Locator));

args.lookupTable(tableNum(LogisticsElectronicAddress));

args.parmObject(lookup);

formLookup = ClassFactory.formRunClass(args);

formLookup.init();

this.performFormLookup(formLookup);

}

The lookup appears to show up, however from this point on I got no clue how to capture the record LogisticsElectronicAddress table returned from the lookup in order to populate my other controls.

Another post I came across suggested to use reference group and lookupReference() method. For that to work, I had to add a foreign key relation between my temp table and LogisticsElectronicAddress.RecId column; I re-added LogisticsElectronicAddressRecId field to the grid and it was recognized as reference group; added lookup() method to it and, voila, I could surely use the record returned from the lookup to populate my grid record in code. Alas, it did bite me on adding another temp record with hand-typed entries - the form attempted to validate the reference group and complained, despite I set Validate=“No” on the foreign key relation. Thus this approach unfortunately has rendered itself useless, unless I missed something.

Any suggestions would be appreciated.

The form can actually return the record back to the calling LogisticsElectronicAddressLookup object, therefore that’s the class you want to use. I would do the following.

First a few changes in your form:

public class FormRun extends ObjectRun
{
    LogisticsElectronicAddressLookup lookup;
}

// On your DS field
public void lookup(FormControl _formControl, str _filterStr)
{
    lookup = LogisticsElectronicAddressLookup::openForm(
        _formControl,
        0,
        LogisticsElectronicAddressMethodType::Email);
}

// On your DS field
public void modified()
{
    super();

    // Here is the trick. i use the lookup object to get the address record
    // and set fields of the active DPTable1 record.
    DPTable1.LogisticsElectronicAddressLocator = lookup.parmElectronicAddress().Locator;
    DPTable1.Description = lookup.parmElectronicAddress().Description;
}

Unfortunately this alone wouldn’t work, due to the second parameter of openForm(). That’s PartyId and I assume you don’t want it for any particularly party, so I passed zero. The lookup would try to find a party with ID = 0, and there is none, therefore it wouldn’t return anything. Let’s change it so it ignores empty party IDs:

// In LogisticsElectronicAddressLookup class
public void addParty(DirPartyRecId _party)
{
    // My new code
    if (!_party)
    {
        return;
    }

    if(!conFind(parties, _party))
    {
        parties += _party;
    }
}

Thank you Martin. You suggestion has pointed me in the right direction and worked great (of course :slight_smile: ). I followed your approach and managed to avoid modifying the standard LogisticsElectronicAddressLookup class. So I added a form variable to form constructor as you suggested:

``

**public class FormRun extends ObjectRun**

`

{

LogisticsElectronicAddressLookup lookup;

}

`

But instead of relying on LogisticsElectronicAddressLookup::openForm() call I used my own lookup() override on my DPTable1_LogisticsElectronicAddressLocator string control as follows:

``

**public void lookup()**

`

{

Args args = new Args();

FormRun formLookup;

lookup = LogisticsElectronicAddressLookup::newParameters(this); // ← sign to form member variable

lookup.parmUseLookupValue(true);

lookup.parmMethodType(LogisticsElectronicAddressMethodType::Email);

args.name(formStr(LogisticsElectronicAddressLookup));

args.caller(element);

args.lookupField(fieldNum(LogisticsElectronicAddress, Locator));

args.lookupTable(tableNum(LogisticsElectronicAddress));

args.parmObject(lookup);

formLookup = ClassFactory.formRunClass(args);

formLookup.init();

this.performFormLookup(formLookup);

}

`

The code above allows me overcome the party id filter hardcoded in the lookup controller class. Pretty much same approach except I didn’t need to mess with existing lookup form. Then, I overrode modified() method on DPTable1_LogisticsElectronicAddressLocator string control just as you suggested. The only challenge I was facing after all this is the need to reset lookup variable while navigating between the records in the grid, because my locator was causing modified() method to fire forcing the last lookup values. That was easy enough:

``

**public boolean modified()**

`

{

boolean ret;

ret = super();

if (lookup) // ← make sure the lookup class instance is alive

{

DPTable1.LogisticsElectronicAddressLocator = lookup.parmElectronicAddress().Locator;

DPTable1.Description = lookup.parmElectronicAddress().Description;

}

return ret;

}

`

and then override leaveRecord() method as follows:

``

**public boolean leaveRecord(boolean _forceUpdate = false)**

`

{

boolean ret;

lookup = null; // ← reset lookup class reference

ret = super(_forceUpdate);

return ret;

}

`

Thank you so much for your help!

It’s a matter of preference. I chose not to duplicate the code and generally have less code to maintain.

To avoid the modification of standard code, I could inherit the class and override the single method. Although it would be better for maintainability, I think it would make much sample code less clear.

Once again, thank you Martin! You saved me many hours… [:)]

Once again, thank you Martin! You saved me many hours… [:)]