web
You’re offline. This is a read only version of the page.
close
Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Unanswered

MultiSelect Lookup Issue: Selected items not retained + dependent lookup not updating (D365FO)

(3) ShareShare
ReportReport
Posted on by 666

Hi all,

I'm using SysLookupMultiSelectGrid and SysLookupMultiSelectCtrl in a UIBuilder for a report (Consumption Report) where users select Parent Items and then Child Items based on that.

Issues:

  • SysLookupMultiSelectGrid always highlights the first record on reopen, even when different items were selected earlier.
  • SysLookupMultiSelectCtrl works for Parent selection but Child Item lookup doesn't trigger based on parent selection. It stays blank.

What I Expect:

  • Keep only selected items highlighted in the Parent multiselect.
  • Refresh the Child Item lookup dynamically based on selected parents.

Any help on dynamically refreshing child lookups or fixing the default focus behavior is appreciated.

 

Tagging experts:
@Martin Dráb @André Arnaud de Calavon @nmaenpaa @Jonas "Jones" Melgaard

Categories:
I have the same question (0)
  • Martin Dráb Profile Picture
    237,978 Most Valuable Professional on at
    Are you sure you're passing correct values to SysLookupMultiSelectCtrl.set()? You can see an example in ERMultiselectParameterUIBuilder.initMultiselectControl(), for instance.
  • Saalim Ansari Profile Picture
    666 on at
    Hello @Martin,
     
    Here is my complete code.
     
    internal final class xxx_milkconsumptionreportuibuilder extends srsreportdatacontractuibuilder
    {
        xxx_milkconsumptionreportcontract     contract;
        dialogfield                           dialogmainitemid;
        dialogfield                           dialogbomitemid;
        systablelookup                        sys;
        container 			          mainidselectedfields;
        list 			          mainidlist =  new list(types::string);
        
        public void build()
        {
            contract             = this.datacontractobject();
            dialogmainitemid     = this.adddialogfield(methodstr(xxx_milkconsumptionreportcontract, parmmainitemid), contract);
            dialogbomitemid      = this.adddialogfield(methodstr(xxx_milkconsumptionreportcontract, parmbomitemid), contract);
        }
        
        public void postbuild()
        {
            super();
            contract             = this.datacontractobject();
            dialogmainitemid     = this.bindinfo().getdialogfield(contract, methodstr(xxx_milkconsumptionreportcontract, parmmainitemid));
            dialogbomitemid      = this.bindinfo().getdialogfield(contract, methodstr(xxx_milkconsumptionreportcontract, parmbomitemid));
            dialogmainitemid.lookupbutton(formlookupbutton::always);
            dialogbomitemid.lookupbutton(formlookupbutton::always);
        }
    
        public void mainitemidlookup()
        {
            query query = new query();
            querybuilddatasource qbdsinventtable = query.adddatasource(tablenum(inventtable));
            querybuilddatasource qbdsecoresproducttranslation = qbdsinventtable.adddatasource(tablenum(ecoresproducttranslation));
            qbdsecoresproducttranslation.addlink(fieldnum(inventtable, product), fieldnum(ecoresproducttranslation, product));
            qbdsinventtable.fields().addfield(fieldnum(inventtable, itemid));
            qbdsecoresproducttranslation.fields().addfield(fieldnum(ecoresproducttranslation, name));
    
            container selectedfields = [tablenum(inventtable), fieldnum(inventtable, itemid)];
            syslookupmultiselectctrl multiselectctrl = syslookupmultiselectctrl::constructwithquery(this.dialog().dialogform().formrun(), dialogmainitemid.control(), query, false, selectedfields);
            container selectedvalues = multiselectctrl.get();
    
            for (int i = 1; i <= conlen(selectedvalues); i++)
            {
                mainidlist.addend(conpeek(selectedvalues, i));
            }
            info(strfmt("%1,%2", con2str(selectedvalues), mainidlist.getenumerator()));
        }
    
        private void bomitemidlookup()
        {
            xxx_cuonsumptionreportloweritemlookup lowerlookuptemp;
            delete_from lowerlookuptemp;
            
            listenumerator le = mainidlist.getenumerator();
            while (le.movenext())
            {
                this.itemexplode(le.current());
            }
    
            query query = new query();
            querybuilddatasource qbds = query.adddatasource(tablenum(xxx_cuonsumptionreportloweritemlookup));
    
            qbds.fields().addfield(fieldnum(xxx_cuonsumptionreportloweritemlookup, combinationfield));
            qbds.fields().addfield(fieldnum(xxx_cuonsumptionreportloweritemlookup, itemname));
            container selectedfields = [tablenum(xxx_milkconsumptionreporttemp), fieldnum(xxx_cuonsumptionreportloweritemlookup, combinationfield)];
    
            syslookupmultiselectctrl::constructwithquery(this.dialog().dialogform().formrun(), dialogbomitemid.control(), query, false, selectedfields);
        }
    
        private boolean haschild(itemid _itemid)
        {
            bomversion bomversion;
    
            select firstonly * from bomversion
                where bomversion.itemid == _itemid
                    && bomversion.active
                    && bomversion.fromdate <= systemdateget()
                    && (!bomversion.todate || bomversion.todate >= systemdateget());
    
            return (bomversion.recid != 0);
        }
    
        public void itemexplode(itemid _itemid)
        {
            bomversion  bomversion;
            bom         bom;
            inventtable inventtable;
    
            select firstonly * from bomversion
                where bomversion.itemid == _itemid
                    && bomversion.active
                    && bomversion.fromdate <= systemdateget()
                    && (!bomversion.todate || bomversion.todate >= systemdateget());
    
            if (!bomversion)
                return;
    
            while select * from bom
                where bom.bomid == bomversion.bomid
                join inventtable
                    where inventtable.itemid == bom.itemid
            {
                xxx_cuonsumptionreportloweritemlookup lowerlookuptemp;
    
                lowerlookuptemp.clear();
                lowerlookuptemp.combinationfield = strfmt("%1 - %2", bom.itemid, _itemid);
                lowerlookuptemp.itemid = bom.itemid;
                lowerlookuptemp.itemname = inventtable.itemname();
                lowerlookuptemp.mainitemid = _itemid;
                lowerlookuptemp.insert();
    
                if (this.haschild(bom.itemid))
                {
                    this.itemexplode(bom.itemid);
                }
            }
        }
    
        public void postrun()
        {
            this.mainitemidlookup();
            this.bomitemidlookup();
            contract = this.datacontractobject();
        }
    }
    
     
  • Martin Dráb Profile Picture
    237,978 Most Valuable Professional on at
    You don't call set() at all. That looks like the problem to me.
  • Saalim Ansari Profile Picture
    666 on at
    Thanks for pointing out the missing set() call—could you please explain a bit more about where exactly we should use the set() method when working with SysLookupMultiSelectCtrl in a report dialog, and why it's important?
     
    Specifically, does it need to be used right after constructWithQuery(), or in a modified event, and how does it help ensure the selected values are retained or displayed correctly during re-selection? This will help us understand its proper usage and avoid similar issues in future implementations.
     
    Thanks again!
  • Martin Dráb Profile Picture
    237,978 Most Valuable Professional on at
    As I understand, you want the control to show certain values already selected. That's what set() method is for.
     
    I strongly encourage you to look at the example I gave you before (and don't forgert that you can use Find references to locate all other examples in the application). ERMultiselectParameterUIBuilder.initMultiselectControl() creates an instance of SysLookupMultiSelectCtrl and passes the values to be selected to set(). But what it receives from the data contract class is a container of textual values, while SysLookupMultiSelectCtrl requires two containers: one with RecIds and one with actual values. Therefore initMultiselectControl() finds RecIds for the values before calling set(). Whether you need to do the same or not depends on what data you have as the input, e.g. how you store selected values in xxx_MilkConsumptionReportContract.
  • Saalim Ansari Profile Picture
    666 on at

    Thank you for the detailed explanation. I tried the suggested approach, and it works correctly when the data is already fetched — I’m able to get the correct infos for items that are already present.

    However, when I modify the main item, the selected data doesn’t get updated or fetched accordingly. Is there any additional logic I need to handle for dynamic updates after modifying the main item?

     
  • Saalim Ansari Profile Picture
    666 on at
    Update Code:
    How can we override or reinitialize the SysLookupMultiSelectCtrl values at runtime based on the latest selection?
     
    class XXX_MilkConsumptionReportUIBuilder extends SysOperationAutomaticUIBuilder
    {
        SysListPanel                    sysListPanel;
        DialogField                     dialogMainItemId;
        DialogField                     dialogBomItemId;
        DialogField                     dialogActivationDate;
        SysLookupMultiSelectCtrl       ctrlMainItem;
    
        protected DialogField addDialogField(IdentifierName _methodName, Object _dataContract = this.dataContractObject())
        {
            DialogField ret;
    
            switch (_methodName)
            {
                case methodStr(XXX_MilkConsumptionReportContract, parmMainItemId):
                    dialogMainItemId = this.dialog().addField(extendedTypeStr(ItemId), extendedTypeStr(Name));
                    ret = dialogMainItemId;
                    break;
    
                default:
                    ret = super(_methodName, _dataContract);
                    break;
            }
    
            return ret;
        }
    
        public void postRun()
        {
            Query queryMainItem = XXX_MilkConsumptionReportUIBuilder::companyInfoQuery();
            super();
    
            ctrlMainItem = SysLookupMultiSelectCtrl::constructWithQuery(
                this.dialog().formRun(),
                dialogMainItemId.control(),
                queryMainItem
            );
    
            ctrlMainItem.setMandatory(true);
            ctrlMainItem.set(this.fetchSelectedMainItems(queryMainItem));
        }
    
        private static Query companyInfoQuery()
        {
            Query query = new Query();
    
            QueryBuildDataSource qbdsInventTable = query.addDataSource(tableNum(InventTable));
            QueryBuildDataSource qbdsEcoresProductTranslation = qbdsInventTable.addDataSource(tableNum(EcoResProductTranslation));
    
            qbdsEcoresProductTranslation.addLink(fieldNum(InventTable, Product), fieldNum(EcoResProductTranslation, Product));
    
            qbdsInventTable.fields().addField(fieldNum(InventTable, ItemId));
            qbdsEcoresProductTranslation.fields().addField(fieldNum(EcoResProductTranslation, Name));
    
            return query;
        }
    
        public void getFromDialog()
        {
            super();
    
            XXX_MilkConsumptionReportContract contract = this.dataContractObject();
            contract.parmMainItemId(con2List(ctrlMainItem.getSelectedFieldValues()));
        }
    
        private container fetchSelectedMainItems(Query _query)
        {
            QueryRun queryRun = new QueryRun(_query);
    
            XXX_MilkConsumptionReportContract contract = this.dataContractInfo().dataContractObject();
    
            container conRecIds;
            container conItemIds;
            container conMainIds = list2Con(contract.parmMainItemId());
    
            while (queryRun.next())
            {
                InventTable itemView = queryRun.get(tableNum(InventTable));
    
                if (conFind(conMainIds, itemView.ItemId))
                {
                    conRecIds  += itemView.RecId;
                    conItemIds += itemView.ItemId;
                }
            }
    
            info(strFmt("%1, %2", conRecIds, conItemIds));
            return [conRecIds, conItemIds];
        }
    }
    
     
  • Martin Dráb Profile Picture
    237,978 Most Valuable Professional on at
    I guess you just need to call set() with different values to change the selected values. Try it and you'll see if it works.
  • Saalim Ansari Profile Picture
    666 on at

    You're right that set() works for setting the selected values, but I noticed that it's only effective the first time when called from postRun(). Since postRun() runs only once when the dialog opens, the values are set initially.

     

    However, when I modify the item again, the SysLookupMultiSelectCtrl doesn’t update automatically — calling set() again in those cases has no effect

  • Martin Dráb Profile Picture
    237,978 Most Valuable Professional on at
    It does work in regular forms; you can find many examples in the standard application. Maybe dialogs are special, but maybe you just have a bug somewhere. Can you please prepare a minimal working example (without any unrelated code or custom objects) so we can test the code without duplicated effort of writing it on our own?
     
    Also, what happens if you create a new object and assign it to ctrlMainItem variable, instead of just callig set() of the existing object?

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Finance | Project Operations, Human Resources, AX, GP, SL

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 449 Super User 2025 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 422 Most Valuable Professional

#3
BillurSamdancioglu Profile Picture

BillurSamdancioglu 239 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans