AX – D365FO – Create a Simple and Detail – Tree Form

This article is dedicated to my colleague Andrew Nearness

This example shows how to create a “Simple and create Detail – Tree” Form

This is the result we want to obtain

First create Extended data types

Al0VendorActivityId of type Int64

Al0VendorActivityName of type String

Al0VendorActivityHierarchyId of type Int64

Then create “Al0VendorActivity” table

Add these fields :

  • VendorActivity
  • VendorActivityName
  • IsVendorActivity
  • ParentVendorActivityId
  • VendorActivityHierarchy

Insert a new field group, name it NameDescription and add “VendorActivityName” field inside

Add this code to the table

public class AL0VendorActivity extends common
{
    //Al0_0270_VendorPortal - BEGIN
    /// <summary>
    /// Find by RecId
    /// </summary>
    public static AL0VendorActivity find(Al0VendorActivityId _al0VendorActivityId, boolean _forUpdate = false)
    {
        AL0VendorActivity    aL0VendorActivity = null;

        if (_al0VendorActivityId)
        {
            aL0VendorActivity.selectForUpdate(_forUpdate);
            select firstonly * from aL0VendorActivity where aL0VendorActivity.RecId == _al0VendorActivityId;
        }

        return aL0VendorActivity;
    }

    //Al0_0270_VendorPortal - END

    //Al0_0270_VendorPortal - BEGIN
    /// <summary>
    /// Give a default name to the tree node
    /// </summary>
    /// <param name = "_hierarchyRecId"></param>
    /// <returns></returns>
    public static Al0VendorActivityName findNonExistNameInHierarchy(Al0VendorActivityHierarchyId _hierarchyRecId)
    {
        return AL0VendorActivity::findNonExistByString(
            tableNum(Al0vendorActivity),
            fieldNum(Al0vendorActivity, VendorActivityHierarchy),
            _hierarchyRecId,
            fieldNum(Al0vendorActivity, vendorActivityName),
            extendedTypeNum(Al0vendorActivityname),
            "@SYS134268", "@SYS136676"
        );
    }

    //Al0_0270_VendorPortal - END

    //Al0_0270_VendorPortal - BEGIN
    /// <summary>
    /// Give a default name to the tree node
    /// </summary>
    /// <param name = "_tableId"></param>
    /// <param name = "_matchingFieldId"></param>
    /// <param name = "_matchingFieldValue"></param>
    /// <param name = "_strFieldId"></param>
    /// <param name = "_strFieldType"></param>
    /// <param name = "_strValueExactMatch"></param>
    /// <param name = "_strValueFormatter"></param>
    /// <param name = "_excludedRecId"></param>
    /// <returns></returns>
    public static str findNonExistByString(
        tableId         _tableId,
        fieldId         _matchingFieldId,
        anytype         _matchingFieldValue,
        fieldId         _strFieldId,
        extendedTypeId  _strFieldType,
        str             _strValueExactMatch,
        str             _strValueFormatter,
        recId           _excludedRecId = 0
    )
    {
        DictTable dictTable = new DictTable(_tableId);
        Common  common      = dictTable.makeRecord();
        int idx = 0;
        anytype result, firstStringValue;
        int     edtMaxLen = new DictType(_strFieldType).stringLen();

        result = _strValueExactMatch;

        do
        {
            select firstonly crossCompany common
            where  common.(_strFieldId)      == result
                && common.(_matchingFieldId) == _matchingFieldValue
                && common.RecId              != _excludedRecId
            ;
            if (!common.RecId)
            {
                break;
            }

            // we must detect infinite loop:
            if (1 == idx)
            {
                firstStringValue = common.(_strFieldId);
            }
            else if ((idx > 0) && (firstStringValue == common.(_strFieldId)))
            {
                throw error(
                    strFmt("@SYS330468",
                        _tableId, tableId2name(_tableId),
                        _matchingFieldId, fieldId2name(_tableId, _matchingFieldId), _matchingFieldValue,
                        _strFieldId, fieldId2name(_tableId, _strFieldId),
                        idx, firstStringValue
                    )
                );
            }

            idx++;
            result = strFmt(_strValueFormatter, idx);
            // trim as necessary
            if (strLen(result) > edtMaxLen)
            {
                result = subStr(result, 1, edtMaxLen);
            }
        }
        while (true);

        return result;
    }
    //Al0_0270_VendorPortal - END

}

Create a Form and apply the “Simple and create Detail – Tree”

Insert “ActivityLookup” group under “FormTreeGroupControl” and add a new Reference Group under it

Name it “ActivityFindReferenceGroup”

Override these 4 form methods

Now add this code to the Form class

[Form]
public class Al0VendorActivity extends FormRun
{
    CCFormTreeDatasource treeDatasource;

    /// <summary>
    /// Run event
    /// </summary>
    public void run()
    {
        FormControl hostControl;
        super();

        this.InitTree();
    }

    /// <summary>
    /// InitTree event
    /// </summary>
    void InitTree()
    {
        treeDatasource = new CCFormTreeDatasource(Al0VendorActivity_ds,
        Tree,fieldnum(Al0VendorActivity,RecId),
                    fieldnum(Al0VendorActivity,ParentVendorActivityId),
                    fieldnum(Al0VendorActivity,VendorActivityname),
                    false, false
                    );
        // Create First Record
        treeDatasource.initRoot("@Al0AM:Al0_0270_VendorPortal_01",1,0);
    }

    /// <summary>
    /// ExpandAndSelectRec event
    /// </summary>
    /// <param name = "ChildId"></param>
    /// <returns></returns>
    int ExpandAndSelectRec(Al0VendorActivityId  ChildId)
    {
        int                 node;
        AL0VendorActivity   TreeItemGroupTable;
        Al0VendorActivityId IdTree;

        select firstonly TreeItemGroupTable
         where TreeItemGroupTable.RecId == ChildId;

        if (TreeItemGroupTable)
        {
            node = this.ExpandAndSelectRec(TreeItemGroupTable.ParentVendorActivityId);
            tree.expand(node, FormTreeExpand::EXPAND);
            IdTree   = tree.getItem(node).data();

            while (ChildId != IdTree)
            {
                node    = tree.getNextVisible(node);
                IdTree  = tree.getItem(node).data();

                Al0VendorActivity al0VendorActivityCurr = AL0VendorActivity::find(IdTree);
                str treeNodeNewText = al0VendorActivityCurr.VendorActivity + "," + al0VendorActivityCurr.VendorActivity;

                FormTreeItem formTreeItem = tree.getItem(node);
                formTreeItem.text(treeNodeNewText);

                tree.setItem(formTreeItem);
            }
        }
        else
        {
            node = tree.getRoot();
        }

        tree.select(node);
        return node;
    }

    /// <summary>
    /// Expand and select
    /// </summary>
    /// <param name = "ChildId"></param>
    void ExpandAndSelect(Al0VendorActivityId ChildId)
    {
        tree.lockWindowUpdate(true);
        this.ExpandAndSelectRec(ChildId);
        tree.lockWindowUpdate(false);
    }

    /// <summary>
    /// 
    /// </summary>
    void exit()
    {
        element.closeSelect(treedatasource.selectedData());
    }

    /// <summary>
    /// Intercept System buttons onclick() events
    /// </summary>
    /// <param name = "_taskId"></param>
    /// <returns></returns>
    public int task(int _taskId)
    {
        #Task

        int ret;

        switch (_taskId)
        {
            case #taskNew:
                this.insertTreeNode();
                break;
            case #taskDeleteRecord:
                this.deleteTreeNode();
                break;
            default:
                ret = super(_taskId);
        }

        return ret;
    }

    /// <summary>
    /// Delete tree node
    /// </summary>
    void deleteTreeNode()
    {
        AL0VendorActivityId      ItemGroup;

        ItemGroup = AL0VendorActivity.ParentVendorActivityId;
        //////////////////////////////////////////////////////////////
        //Delete Tree Node
        treeDatasource.delete();

        //////////////////////////////////////////////////////////////
        element.refreshTree(ItemGroup);
    }

    /// <summary>
    /// Insert tree node
    /// </summary>
    void insertTreeNode()
    {
        AL0VendorActivity  insItemGroupTable;
        int idx = Tree.getSelection(); //Get current selected record 
        AL0VendorActivity selectedTreeItem = AL0VendorActivity::find(Tree.getItem(idx).data());
        Al0VendorActivityHierarchyId al0VendorActivityHierarchyId = 1;

        //////////////////////////////////////////////////////////////
        //Create Tree Node
        insItemGroupTable.clear();
        if(selectedTreeItem)
        {
            insItemGroupTable.ParentVendorActivityId = selectedTreeItem.RecId;
        }
        else
        {
            insItemGroupTable.ParentVendorActivityId = al0VendorActivityHierarchyId;
        }

        insItemGroupTable.VendorActivity       = AL0VendorActivity::findNonExistNameInHierarchy(al0VendorActivityHierarchyId);
        insItemGroupTable.VendorActivityName   = AL0VendorActivity::findNonExistNameInHierarchy(al0VendorActivityHierarchyId);
        insItemGroupTable.IsVendorActivity     = NoYes::Yes;
        insItemGroupTable.VendorActivityHierarchy = al0VendorActivityHierarchyId; 
        insItemGroupTable.insert();
        //////////////////////////////////////////////////////////////

        element.refreshTree(insItemGroupTable.RecId);
    }

    /// <summary>
    /// Refresh Tree event
    /// </summary>
    /// <param name = "_ItemGroupId"></param>
    void refreshTree(Al0VendorActivityId  _ItemGroupId)
    {
        Al0VendorActivity_ds.query().dataSourceName("Al0VendorActivity").clearRanges();

        element.InitTree();
        element.ExpandAndSelect(_ItemGroupId);

    }

    [Control("ReferenceGroup")]
    class ActivityFindReferenceGroup
    {
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public Common lookupReference()
        {
            Common ret;
        
            ret = super();
        
            return ret;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public boolean modified()
        {
            boolean ret;
        
            ret = super();
            
            if (treeDatasource)
            {
                element.expandAndSelect(ActivityFindReferenceGroup.value());
            }


            return ret;
        }

        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public Common resolveReference()
        {
            Common ret;
        
            ret = super();
        
            return ret;
        }

    }

    [Control("Tree")]
    class Tree
    {
        /// <summary>
        /// Expanding event
        /// </summary>
        /// <param name = "_Idx"></param>
        /// <param name = "_action"></param>
        /// <param name = "_data"></param>
        /// <returns></returns>
        boolean expanding(int idx, FormTreeExpand action, anytype data)
        {
            boolean ret;
            ret = super(idx, action, data);

            treeDatasource.expanding(idx, action, data); // expand node

            Return ret;
        }

        /// <summary>
        /// mouseUp event
        /// </summary>
        /// <param name = "_x"></param>
        /// <param name = "_y"></param>
        /// <param name = "_button"></param>
        /// <param name = "_Ctrl"></param>
        /// <param name = "_Shift"></param>
        /// <returns></returns>
        public int mouseUp(int x, int y,
           int button, boolean ctrl, boolean shift)
        {
            super(x, y, button, ctrl, shift);
            return 1;
        }

        /// <summary>
        /// MouseDblClick event
        /// </summary>
        /// <param name = "_x"></param>
        /// <param name = "_y"></param>
        /// <param name = "_button"></param>
        /// <param name = "_Ctrl"></param>
        /// <param name = "_Shift"></param>
        /// <returns></returns>
        public int mouseDblClick(int _x, int _y,
              int _button, boolean _Ctrl, boolean _Shift)
        {
            int ret;
            ret = super(_x, _y, _button, _Ctrl, _Shift);

            element.exit();

            return ret;
        }

        /// <summary>
        /// Selection changed event
        /// </summary>
        /// <param name = "_OldItem"></param>
        /// <param name = "_NewItem"></param>
        /// <param name = "_how"></param>
        public void selectionChanged(FormTreeItem _OldItem, FormTreeItem _NewItem, FormTreeSelect _how)
        {
            super(_OldItem, _NewItem, _how);

            if (treeDatasource)
            {
                treeDatasource.selectionChanged(_OldItem, _NewItem);
            }
        }

    }

}

One thought on “AX – D365FO – Create a Simple and Detail – Tree Form

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...