Combo Box off by one

Hello everyone,

I have created a combo box, but I’m not sure why it’s not working the way I would like it to. I want it to change dynamically depending on what item the users put in. I have code on the modified method of the item field in my grid which fills in the description of the item and then I want it to fill in the combo box with the warehouses it finds for that item. It works in the sense that it finds the right warehouses but when I click on the combo box, it shows a blank, then the warehouses it found. If I choose warehouse 1 and tab off it, the warehouse changes to warehouse 2. If choose the blank and tab off it, it chooses warehouse 1. So somehow something is off by 1. Not sure what I’m doing wrong. I’ve tried hard-coding the array size (like below) and I’ve also tried changing the array size dynamically but both have same result. Here is the code:

public void modified()
{
InventItemLocation inventItemLocation;
InventTable inventTable;
InventDim inventDim;
int i = 1;

super();

cboWarehouse.items(3);

TCI_ReceivingLabels.ItemId = strUpr(TCI_ReceivingLabels.ItemId);
TCI_ReceivingLabels.Name = InventTable::find(TCI_ReceivingLabels.ItemId).NameAlias;
TCI_ReceivingLabels.NumOfLabels = 1;

inventItemLocation = inventItemLocation::findDefault(TCI_ReceivingLabels.ItemId, false);

while select * from inventItemLocation
join inventDim
where inventDim.inventLocationID != ‘’
&& inventDim.inventDimId == inventItemLocation.inventDimId
&& inventItemLocation.ItemId == TCI_ReceivingLabels.ItemId
{
cboWarehouse.item(i);
cboWarehouse.text(inventdim.inventLocationID);
i++;
}
}

Anyone see what I’m doing wrong?

What if you try to index it from zero?

By the way, it think that most AX developers would use a lookup with a temporary table. As I see in other threads, you’re struggling with this for a long time, therefore consider using the usual solution rather than something innovative.

I’ve figured out a piece of this. I needed to write this in the form’s methods and then call it from the init. The problem now is that I want to call this method on the form from the Modified() method of my string field in my grid on that form. How do I do this?

So are you saying I should create a temp table called Warehouses, fill it when I modify my item, and then bound my combo box to that temp table?

I’m sorry, but I don’t understand what problem you have with calling the method. Please give us more information.

Here is my code for my method fillComboWarehouse on my form TCI_ReceivingLabelsSingle

public void fillComboWarehouse()
{
InventItemLocation inventItemLocation;
InventDim inventDim;
int i = 1;

if(TCI_ReceivingLabels.ItemId != “”)
{
inventItemLocation = inventItemLocation::findDefault(TCI_ReceivingLabels.ItemId, false);

while select * from inventItemLocation
join inventDim
where inventDim.inventLocationID != ‘’
&& inventDim.inventDimId == inventItemLocation.inventDimId
&& inventItemLocation.ItemId == TCI_ReceivingLabels.ItemId
{
cboWarehouse.items(i);
cboWarehouse.item(i);
cboWarehouse.text(inventdim.inventLocationID);
i++;
}
}
}

My form has a datasource of a table called TCI_ReceivingLabels
and it has a grid where I have put in TCI_ReceivingLabels.item and cboWarehouse
When a user inputs an item number it looks up the item name, etc. It’s in here that I want to call fillComboWarehouse again but I don’t know how. this.fillComboWarehouse() doesn’t work because I’m in the item’s modified() method. Here is the code I have: As you can see I’ve tried getting the caller but it doesn’t work.

public void modified()
{
InventItemLocation inventItemLocation;
InventTable inventTable;
InventDim inventDim;
Object caller = element.args().caller()
int i = 1;

super();

TCI_ReceivingLabels.ItemId = strUpr(TCI_ReceivingLabels.ItemId);
TCI_ReceivingLabels.Name = InventTable::find(TCI_ReceivingLabels.ItemId).NameAlias;
TCI_ReceivingLabels.NumOfLabels = 1;

caller.fillComboWarehouse();
}

Regarding: “So are you saying I should create a temp table called Warehouses, fill it when I modify my item, and then bound my combo box to that temp table?”

Almost. If you use a lookup, you don’t use combobox at all. Consider your ItemId field - it’s a string field, not a combobox, but it still has an lookup where you can select available items. Also, you can fill the table in advance (if you know the values) and merely filter it as needed.

I see what you are saying but I’m not sure if it works for this instance. A user is going to use this form I created to print a label for an item. On that label is the Item Number, Item Description, and Default Location. When a user types in an item and presses tab, it looks up the name of that item, but there is only one result for that. One item could be in multiple warehouses so I want the user to know what their options are, then choose a warehouse. Once they choose a warehouse, the default location will fill in.

This is the code to find the warehouses:
inventItemLocation = inventItemLocation::findDefault(TCI_ReceivingLabels.ItemId, false);

while select * from inventItemLocation
join inventDim
where inventDim.inventLocationID != ‘’
&& inventDim.inventDimId == inventItemLocation.inventDimId
&& inventItemLocation.ItemId == TCI_ReceivingLabels.ItemId
{
Warehouse = inventdim.inventLocationID
}

And this is the code to find the default location:
inventItemLocation = inventItemLocation::findDefault(TCI_ReceivingLabels.ItemId, false);

while select * from inventItemLocation
join inventDim
where inventDim.inventLocationID == TCI_ReceivingLabels.TCI_Warehouse
&& inventDim.inventDimId == inventItemLocation.inventDimId
&& inventItemLocation.ItemId == TCI_ReceivingLabels.ItemId
{
location = inventItemLocation.WMSLocationIdDefaultIssue;
}
TCI_ReceivingLabels.TCI_Location = location;

So I guess the reason I want to use a combo box is so the user knows all the options of warehouses when they choose an item since a user could be at any one of our plants when using this. I’m fine if combo box is not that right course of action. I just wanted you to know all the facts before pointing me in the right direction. Would you still suggest I use a temp table and a lookup?

I’m sorry, but I don’t understand either your problem nor your code. Let’s try to analyze it.

You said: “When a user types in an item and presses tab, it looks up the name of that item, but there is only one result for that”. Is this a problem, or just information unrelated to your problem? If it’s a problem, what other name of your item do you expect?

*"*One item could be in multiple warehouses." Of course.

“I want the user to know what their options are, then choose a warehouse.” Sound a lookup of warehouses to me.

Now your code:

inventItemLocation = inventItemLocation::findDefault(TCI_ReceivingLabels.ItemId, false);

while select * from inventItemLocation
    join inventDim
    where inventDim.inventLocationID != ''
        && inventDim.inventDimId == inventItemLocation.inventDimId
        && inventItemLocation.ItemId == TCI_ReceivingLabels.ItemId
{
    Warehouse = inventdim.inventLocationID
}

You first fill inventItemLocation by find() method, but you immediately overwrite the buffer by the select statement. Therefore the first line has no effect at all; you can throw it away.

Then you execute a loop, you always overwrite the Warehouse variable, there it’s the same as removing the while loop and taking the last wearehouse only.

Your other code snippet has the same bugs.

You continue with this:

“the reason I want to use a combo box is so the user knows all the options of warehouses”. Isn’t it what lookups are all about? Don’t you get a selection of all items in standard AX, for example? You’ll see thousands of examples in AX, in virtually every form.

And if you don’t have any limit for number of records, a simple lookup with a query is all what you need.

Okay, because I’m still a newbie, I guess I don’t understand how a user will choose from the options of warehouses using a lookup, but I know that you definitely know what you are talking about so I’m going to look into it.

It seems that you should familiarize yourself with Dynamics AX interface before trying to design something by yourself.
For example, create a sales order and a line - select a customer, item, the warehouse etc., so you understand how these things work and what users expect from customizations as well.

I’m doing some research but can’t get any thing to work. Can you help me get something working? So let’s go with a lookup of the warehouse for the item the user enters. I over-write the lookup method for the field TCI_Warehouse in my datasource of my form? And how/when does that get executed? I put some code in there an nothing happens.

Okay, I’m getting somewhere. In SQL, if I run this query, I get all the warehouse choices:
SELECT
INVENTLOCATIONID
FROM
INVENTDIM
INNER JOIN
INVENTITEMLOCATION ON INVENTITEMLOCATION.INVENTDIMID = INVENTDIM.INVENTDIMID
WHERE
INVENTLOCATIONID <> ‘’
GROUP BY
INVENTLOCATIONID

So I’ve created a lookup but for some reason it keeps telling me that I have a invalid sort field. What am I doing wrong?

Query query;
QueryBuildDataSource qbds;
QueryBuildRange qbr;
SysTableLookup lookup;

query = new Query();
qbds=query.addDataSource(tableNum(InventDim));
qbds=qbds.addDataSource(tableNum(InventItemLocation));
qbds.addLink(fieldNum(InventDim, InventDimId), fieldNum(InventItemLocation, InventDimId));
qbds.addSelectionField(fieldNum(InventDim, InventLocationId));

qbds.addGroupByField(fieldNum(InventDim, InventLocationId));

lookup=SysTableLookup::newParameters(tableNum(InventDim),_callingControl, true);
lookup.parmQuery(query);
lookup.addLookupfield(fieldNum(InventDim, InventLocationId), true);
lookup.performFormLookup();

Actually got this working. It was the order I was putting things. Here is the working code:
Query query;
QueryBuildDataSource qbds;
QueryBuildRange qbr;
SysTableLookup lookup;

query = new Query();
qbds = query.addDataSource(tableNum(InventDim));
qbds.addRange(fieldNum(InventDim, InventLocationId)).value(SysQuery::valueNotEmptyString());
qbds.addGroupByField(fieldNum(InventDim, InventLocationId));
qbds = qbds.addDataSource(tableNum(InventItemLocation));
qbds.addLink(fieldNum(InventDim, InventDimId), fieldNum(InventItemLocation, InventDimId));

lookup=SysTableLookup::newParameters(tableNum(InventDim),_callingControl, true);
lookup.parmQuery(query);
lookup.addLookupfield(fieldNum(InventDim, InventLocationId), true);
lookup.performFormLookup();

Now I just need to pass in the item that the user chooses and re-sort.

Martin, I also want to thank you for all your help. I think you have replied to every single one of my posts and I’ve learned so much in the last 2 weeks with your help. This lookup method is going to be huge. Thank you again and again!

You’re welcome. :slight_smile:
If I recognized that you’re not familiar with lookups, I would push you to use them a long time ago; they’re very important and common in Dynamics AX.
Also, your original case (displaying a list of generated numbers) sounded like a legitimate case for using a combobox, but the same can’t be said about a list of warehouses, so this requires a different approach.