One of the great features available in Dynamics AX is the support of lookup forms that provide a user-friendly interface for selecting a value for a field from a list, and are highly customizable, allowing the developer great flexibility in meeting user needs.
Recently, I was posed a question of how to present a user with a list of custom-defined values in a lookup form.
The simple (and suggested) approach here is to create a new BaseEnum, containing all the specified values, and add a ComboBox control for this enumeration to the form. If the values are to be displayed conditionally (only a subset is shown each time), you can build a superset of all values in AOT, and use SysFormEnumComboBox class to limit the actual output at runtime.
But, this would not work in my case, because the values in the list were dependent on other data in the form plus the current date. Using a temporary table for this scenario seemed like an overkill (but possible). So i decided to investigate the system class SysLookup for hints on how this can be done with minimum effort. The implementation of this method is provided below.
As part of posting this implementation, I decided to also briefly describe some of the other lookup method options available to an AX developer, turning this post into a small tutorial on lookup methods.
1. The approach used most in the application is the implicit lookup based on table fields. As you can see from the control properties, DataSource and DataField specify which table field the control is based on. In my example, it is based on SalesTable.CustAccount, which uses the ExtendedDataType CustAccount, which has a relation to CustTable.AccountNum. Therefore, any time you add this field to a form, it will automatically provide a lookup button to select one of the customers.
Relations being specified on EDTs is at times confusing to people, who are used to seeing the relations between tables on the tables themselves. Technically speaking, such definitions on EDTs are incorrect. But no worries, AX supports the “correct” scenario out of the box as well. The relation to CustTable could have been specified on the table just as well.
2. 2nd most used approach is to specify the ExtendedDataType on the control directly. This is used to allow the user to specify a value to filter the records on directly from the form, for example (without the need to go to Extended Query form). It is also indirectly used on all RunBase dialogs in the system (when creating a DialogField, we specify the EDT to be used, which is transfered to the ExtendedDataType property on the corresponding control). In the tutorial, it is again the CustAccount EDT that is specified in the properties.
3. The 2 above examples both used metadata to define what lookup is to be displayed. The 3rd most used approach is relying on SysTableLookup class and builds the lookup at runtime. The code is relatively straightforward, and is described in more detail on MSDN. Using this approach, the developer can specify the query to filter the data being displayed in the lookup form. Note, that SysTableLookup only allows to have data from one table in the lookup form (+ display methods on this table). SysMultiTableLookup is an extension I have created a while ago, that adds this and other useful functionality to SysTableLookup class.
4. The remaining 2 standard approaches are rarely used in the application. Lookup based on ExtendedDataType is very similar to approach described under #2, but is executed from code at runtime. This way, you can change the lookup data displayed dynamically, based on some conditions (For example, on Ledger Journal lines, the offset account lookup shows vendors, customers, banks, etc. based on the offset account type specified on the line).
5. BaseEnum values are usually represented as a ComboBox (and, in special cases, CheckBox or RadioButton) control on forms in Dynamics AX. The lookup is provided by the kernel automatically for this type of control. But, sometimes, it is required to show the values of an enumeration in a string control – most common scenario is providing filter capabilities based on enums, where multiple values can be specified at once, similar to extended query form filters. In fact, this approach is actually used on SysQueryForm for enum fields. As you can see from the code, the lookup call is also very simple in this case.
6. This approach does not currently exist in the application, and the goals for its implementation were already described above. The lookup method code in this case looks rather straightforward, here it is:
public void lookup()
{
Counter yearCount;
List valueList = new List(Types::String);
for (yearCount = 0; yearCount < 5; yearCount++)
{
valueList.addEnd(strFmt("Year %1", year(SystemDateGet()) - yearCount));
}
SysLookup::lookupList(this, valueList, "List of years");
}
As you can see, the data displayed in this lookup depends on current system state (date) and other data (yearCount). It uses the class List to hold the values to be displayed.
You can download the project (Compatible with Axapta 3.0 – Dynamics AX 2009) with the tutorial and custom list lookup implementation by following the link below:
Note: The xpo contains changes to SysLookup class/form (only usr layer has been exported, for your convenience). Be careful when importing those, and don’t import them into the production environment.
Hi i have a query
ReplyDeleteIn Ax2009 the employee name from EmplTable is fetched using the dirParty().Name.
My client has a customized lookup in AX40 , in which he is using SysLookup Class to create a lookup.The fields he added in it are EmplId and Empname. And we are upgrading the AX40 application to Ax2009.
how do i write a lookup in which i can have both Id and Name of the employee in the lookup.
Please help
Well, you have 3 approaches:
ReplyDelete- use the class I created here:
http://kashperuk.blogspot.com/2008/09/sysmultitableloookup-dynamic-lookups.html
- use a display method (one exists on EmplTable) displaying it in the lookup
- create a separate form (one is actually created - EmplIdLookup)
Hi,
ReplyDeleteUsing SysTableLookup approach (#3), Is there a way to make "go to main table" open up different form (NOT to the form specified in the EDT relation)?
Thanks,
Charles
Well, SysTableLookup does not have anything to do with "Go to main table". It is only used for lookups.
ReplyDeleteBut, what you want to do is possible.
Simply override the jumpref method on the control (or, preferably, datasource field).
In there you can put whatever code you like instead of the call to super()
Please browse the web for examples of jumpRef use.
how to achieve go to main table on dialog field.
ReplyDeletefor example a dialog is having a field of lookup custAccount, now what i need to have a go to mai table functionality on the same.
for ne suggestions do reply me on amolgupta1983@gmail.com
is anyway to filter records (dataset) based on display method?
ReplyDeleteNo. Filtering on display and edit methods is not possible.
ReplyDeleteHi Vanya,
ReplyDeletefirst, congratulations for your blog!
I need to develop something like the fourth aproach you described. Basically, I have a StringEdit with EDT ProdId. But in the lookup of this, it´s necessary to show only the production orders with ProdStatus == StartedUp.
How can I do that?
Thanks in advance
Lucas, Brazil
Well, the easiest thing to do would be to create a new EDT ProdIdStartedUp, which has a relation set up similar to ProdId, with an extra Related Field Fixed relation "4 == ProdStatus".
ReplyDeleteOtherwise, you have to go with option 3, where you create the lookup through SysTableLookup. Browse the net for examples - there are plenty, and in the application itself as well.
How do you change the fixed relation value in code? I have two drop-down edt and i want the second edt to filter based on the selection of the first edt. So basically, the selection of the first drop-down will set the fixed relation value for the second drop-down.
ReplyDeleteThanks,
Mike
Well, you can't dynamically change the underlying EDT properties, so it's not an option here.
ReplyDeleteBut it is really easy to achieve the desired result using approach #3 mentioned in the post above - use SysTableLookup class, building your query and adding a range based on the value in the first lookup.
good day Vanya.
ReplyDeletePls.. to help me i am a junior programmer on a company and i need to research a information about ax2009, after i have done on editing in methods on ax the display edit would not open so i can not edit again my programm in methods, why is that happen and what should i do.
I am sorry. I don't think I understood what you mean there. I will try to answer the question the way I understood it.
ReplyDeleteJust to recap - you edited some code in AX, but now you cannot do it anymore. Is that right?
If so, it can be due to one of the following:
- Source Control way disabled, but now it is enabled and you don't have the file checked-out.
- The development license expired, and you need to update it
- The configuration keys responsible for development were turned off (not sure that it is possible, though)
Hi Vanya,
ReplyDeleteI have to get in the lookup of a form field the RecId of the register selected. How can I do that?
Thanks
Samuel
Well, just add that field to the lookup form field list. But I would advise against this, since RecId is a non-user friendly field, so the user should NEVER see it. Present the correspondig natural key instead.
ReplyDeleteSorry Vanya, I did not express myself clearly. Think in a hipotetic case of a lookup field that shows two fields. The combination of both is a primary key, while a single one is not. As we are talking about a comboBox, when I select, one of the fields will be shown (put there). But I have to be able to catch this combination, because the other field will be put in another control in the form. That´s why I thought about catching the RecId, because it is unique. So the "getting" that I wrote was related to the field selected.
ReplyDeleteSorry about the bad question before.
Thanks a lot
Samuel
OK, now I understand. Yes, this is definitely possible, i have don't that a couple of times at least on various occasions. But they were specific solutions to specific forms.
ReplyDeleteLet me try to think of a generic way to handle that. If I can't come up with one, I'll post a short entry about how to handle your scenario - it would require to create your own lookup form
in how many ways we can create report
ReplyDeleteDepends on what type of report, SSRS or X++.
ReplyDeleteIf it's the latter, consider using the report wizard - that's the easiest way.
There is a large chapter about working with reports in MorphX IT book. Maybe you should invest into buying one.
There is also a tutorial_RunBaseReport class in the application - do check it out.
Hi
ReplyDeleteI was reading the comment on getting the recid from the selected lookup record. I have also checked your followup.
I had the exact same problem, a table that has two fields that are unique when combined.
One easy way to solve this was to declare the SysTableLookup in classDeclaration.
In the modified event if the stringedit control the selected record could be located e.g. by using the following line:
EmplTable.data(sysTableLookup.parmFormRun().dataSource().cursor());
However, this approach also requires a check in the validate method if the user selects a record by typing the name. This check should return false if more than one record with this value exists.
I don´t know if this was what "Anonymous" was looking for, but i think it was.
/Jonas
Hi Vanya Kashperuk,
ReplyDeleteKinldy help for the following query. In Ax 2009, dimensions are made global. Still i am looking for some query or mapping where i can sort it company wise where ever the dimension exists in the form. Any workaround !!
Regards,
dipankar,
diptouch@gmail.com
Hi,
ReplyDeleteHow we can have Inventory dimension in lookup,
I have a scenario where in I require the itemid and inventory dimension in lookup from PurchLine Table
Is it possible if yes then how
Regards
Abhishek Mehta
abhishekmehta3@gmail.com
Hi,
ReplyDeleteI'm fairly new to AX 2009 and i was wondering if there is any way to add a lookup field to a dialog form, based on the Dialog class.
Thanks,
Eric
zedleppelin13@hotmail.com
OVERVIEW:-
ReplyDeletehi, we are intigrating .net application (our ERP->WM) & AX 2009. so in order to work we need some mapping as site mapping, customer group mapping.
So we decided to make only one table for this all mappings with columns like
1.For which Mapping data this row contain.
2.AX data value.
3.Our ERP data value.
as eg.
ROW1: site,4,WM4
ROW2: customerGroup,cus1,WMCus1
ROW3...
now i have created one preference form on that we want to allow to user that can map values as needed.
here on form we have created 2 grid one for sites and second grid for custGroup.
STRUCTURE OF GRIDS:
on both grid there is two column only as one for AX Data and second for WM Data third column value is handled internally.
MY PROBLEM IS:
1. how to bind this one table with two grid on same form? is it possible?
2. on both grid i want to provide combobox so user can select values as per grid. here in site grid combobox must show site related value for both column.
3.And after user select values, data stored in same table as mention with firstColumn values as site or CustMapping.
4.This is good way to provide mapping or i impliment this using different TABLES for CustGroup & Site. if we go with this option we need to increase number of tables as mapping increase.
Thank you for your time in advance.
HI, for Above case of intigration of AX & WM (our ERP)
ReplyDeleteMain PROBLEM is while retriving data on grid.
as we have single table-> preferanceTable and that we are using on two grids on same form preferanceForm.now while form loads at that time how we can display sites related all (selected values) on siteGrid & custGroup Related values on custGroupGrid. Thank you
1. Just add 2 different form datasources for the same table. Use the 1st datasource for the first grid and the second datasource for the second grid (be careful about setting the properties on form group controls correctly there, to avoid unexpected navigation issues)
ReplyDelete2. You can override the lookup methods on the respective datasource fields. This way, you can display different lookups for different grids.
3. If you apply a filter on "Site" or "CustomerGroup" in the init of the datasource (which you have to do anyway in order to only display the respective values), the field value for this column will automatically be assigned if you create a new row in that grid.
4. It's an OK way. There is already a similar pattern that you might want to take a look at in AX - it's called External codes, and the sole purpose is to provide a way to do this kind of mapping of internal AX codes with external codes.
Hi Vanya,
ReplyDeleteI have a dialog field with UserID type. The field automatically has the dropdown list with 3 columns: userId, name, and security identifier. I like to remove the 3rd column. What's your suggestion on best approach?
Thank you for your help!
The UserID refers to a system table, so the easiest way to change the behavior is to just use the SysTableLookup approach described above, imho.
ReplyDeleteHi Vanya,
ReplyDeleteOn SalesCreateOrder form - I have a requirement of filtering contact id lookup - currently we see only the fields which are mentioned on contactpersonlookup form are appearing..
my requirement is to display addtional columns of Delivery address, city, country, zipcode only when there is a delivery type address is there for the customer..
means the additional columns should appear only when there is address type delivery is there for the customer..if possible can you provide the code..
Thanks in advance - jagx.69@gmail.com
Hi Vanya,
ReplyDeleteI have a requirement for Year dropdown on a report as filter. I tried something like this on the dialog method of the report..
public Object dialog(Object _dialog)
{
DialogRunbase dialog = _dialog;
DialogField fieldYear;
Yr yearCount;
List valueList = new List(Types::Int64);
;
dialog.addGroup("@SYS1046");
fieldYear = dialog.addFieldValue(typeid(Yr), calYear, "@SYS23908");
for (yearCount = 2005; yearCount < 2015; yearCount++)
{
valueList.addEnd(yearCount);
}
SysLookup::lookupList(fieldYear.control(), valueList, "List of years");
fieldYear.lookupButton(2);
return dialog;
}
The SysLookup::lookupList() is not suited for using with dynamically added controls. You would need to either postpone calling this method until the lookup is actually invoked (see controlMethodOverload method help), or create a form that opens in the lookup, or modify the code so that it supports integer controls, as well as buildcontrols (not runtime controls)
ReplyDeleteHi,
ReplyDeleteI want to be able to get the lookup drop down to open up as you type. It should look like the way the google suggestions look. Do you have any ideas?
Thanks
I don't think that will be possible to do in AX without major coding.
ReplyDeleteThe way lookup forms work in AX is that focus is set to the lookup form as soon as it is opened, and the lookup form is closed automatically as soon as the focus is removed. Now, you can code to avoid that by introducing some sort of a condition controlling that.
But then you are still left with the problem of correctly setting the focus and position back to the original control.
So, it is probably possible to get very close to the behavior of Google, but it would require a lot of time, which is a waste.
Filter by Grid can be a much faster option.
Hello All,
ReplyDeleteJust struggling with a look up form and wondering if someone could help me please. On my sales ledger form under sales Line Tab I have inserted a new field called Job id which is EDT. I am calling a lookup form on this field. The data source of this look up form is a table contains sales id, job id and name. I want to add filter on the sales id of this look up form.
So if user creates a new sales line select item number and when he clicks on job ID he can only see the record which is linked with the current sales id of sales line.
At the moment if user clicks on the field he see following values in look up form
Sales Id - Job Id - Name
SO7546 701 Futaba
SO7546 702 Futaba
SO7546 703 Futaba
SO7547 704 Futaba
SO7547 705 Futaba
SO7548 706 Futaba
As i am creating a sales line on Sales ID SO7547 so i only want to see this record in my look up form.
SO7547 704 Futaba
SO7547 705 Futaba
Kind Regards,
Well, I don't have access to AX right now to check, but the first thing I would try is add a Relation to SalesLine on SalesId to your table. AX is usually pretty smart and might automatically add a dynalink for you.
ReplyDeleteIf not, use args.record inside your lookup form to manually apply the filter
Hi Vanya,
ReplyDeleteI have an issue related to Dimension hierarchy that should be implemented in EP as well. So the Dimension Lookup in EP (Selective modules) should show dimension hierarchy pattern. How do i modify this Lookup?
Hey guys,
ReplyDelete1. Setting dimension hierarchy for Purchase requisition and Expense Report.
2. This should be done for the EP related forms only.
3. At the time of edit and create of these 2 forms dimensions should work according to the hierarchy.
So what are the modifications that can be done in the Lookup of dataset?
If anyone has any idea of how it is done please let me know.
Regards,
Saurabh.
punawalasaurabh@yahoo.co.in
Hi,
ReplyDeleteWhile relating two fields in a table(for eg., ID and NAME, When we select ID then in NAME field it should show the respective matched names for that particular ID), but in NAME column lookup two columns are showing(Name (which the matching one) and ID which we selected). But i need only matched NAME in lookup and not with ID which we have selected in NAME field. What can i do for getting only matching NAME lookup in NAME field? Can you please give me a solution?
Hi,
ReplyDeleteI need two tabs in lookup field. In one tab apecific list of ItemId should display. In other tab all the ItemId should be displayed. So how can i create a lookup with two tabs? Kindle help me..
I tried "form help" property in edt. But it doesnt look satisfactory.. Please suggest me some idea..
Regards,
_Kannan
Well, there are a bunch of existing examples in AOT for this.
ReplyDeleteForms\InventLocationIdLookup
Forms\UnitOfMeasureLookup
are just some of the examples.
Typically, the Form Help property on EDT is the one used to select a lookup form
You can see if that if you take a look at
EDTs\InventLocationId
EDTs\UnitOfMeasureSymbol
I am not sure why it did not work for you - maybe in the specific form you are trying to open a lookup, it is overridden or something, and a different form is displayed instead?
Hi,
ReplyDeleteIf i change to companies automatically some form functionalities(like tabpages) will be enabled or disabled.how can i achieve this thing.try to help me
Can you explain what you mean by that? I am not sure I follow. And what does it have to do with lookups?
ReplyDeleteHi Vanya,
ReplyDeleteIn my report Dialog method,
I added a dialog field with EDT InventSiteId, which gives the InventSite Table dropdown.
Now I want to add another field of the same Table side by side with the InventSiteId, but only as a lookup reference.
Any idea how to do it????
Well, the simplest would be to use your own form and override the modified event on the first field (InventSiteId)
ReplyDeleteOtherwise, you'll have to use the controlname_modified() approach, where you would populate the value of the other control.
Hi Vanya,
ReplyDeleteI have a report dialog where the second dialog field needs to have a lookup based on the selected value of 1st dialog field.
So how do i add a custom lookup to a dialog field in report?
see my above comment
ReplyDeleteHello Vanya
DeleteHow can i not allow the user enter a value that does not appear in the list of values of lookup .
Thanks
Hello ,
ReplyDeleteHow to not allow the user to enter a value that does not exist in in the list of values of lookup .
Kindly Help .
Hello ,
ReplyDeleteHow can I do to not allow the user to enter a value that does not appears in the list of values of a lookup .
Thanks .
Besides the obviously of using a base enumeration, there's a solution, but it's ugly, so I would suggest that you simply add validation on validateField, which would throw a warning if the value violates the query used in the lookup.
ReplyDeleteIf you still want to investigate the ugly solution, you can try overriding the validate() method on the control, and returning false; This method should not be called when you select a value from the lookup, as far as I remember. so the user won't be able to type in, but will only be able to select from the lookup.
The even uglier solution is to override the typechange or whatever that method is called, which is called whenever you type in a character, and try handling user input through that.
MANY THANKS !
DeleteThis lookup code is not supported in Ax7 anymore.
ReplyDeleteOne of the other bloggers has recently done a refresh on this blog post. You should check that out. After all, this post is from 2009 :)
Delete