Add a method dynamically in ax 2012 component

2.6k Views Asked by At

I want to add a method dynamically to a component in ax 2012, how can I do this through code? Is it possible?

2

There are 2 best solutions below

0
Alex Kwitny On BEST ANSWER

Here is a job I wrote that demonstrates a bunch of different ways of doing what you're wanting:

static void Job79(Args _args)
{
    TreeNode        treeNode = TreeNode::findNode(@'\Classes\Activities');
    SysDictClass    sysDictClass = new SysDictClass(treeNode.applObjectId());
    FormRun         formRun = new FormRun(new Args(formStr(AifAction)));
    Form            form = new Form(formStr(AifAction));
    ClassBuild      classBuild;
    SysDictTable    sysDictTable = new SysDictTable(tableNum(AccountSumMap)); // Maps are treated like tables
    SysDictMethod   sysDictMethod;
    int             i;
    MemberFunction  method;
    str             methodSource = 'public static str getTime()\n{\n\treturn "3/3/2015";\n}';


    // Find if class has a method
    if (sysDictClass.hasObjectMethod('delete'))
    {
        info("Found object method delete");
    }

    if (sysDictClass.hasStaticMethod('main'))
    {
        info("Found static method main");
    }

    // Find if form has a method
    if (formHasMethod(formRun, 'init'))
    {
        info("Found form method 'init'");
    }


    if (form.AOTfindChild('methods').AOTfindChild('refreshGrid') != null)
    {
        info("Found 'refreshGrid' method on AifAction");
    }


    if (sysDictClass.hasStaticMethod('getTime') == false)
    {
        classBuild = new ClassBuild(sysDictClass.name());

        treeNode = classBuild.addMethod('getTime', methodSource);

        if (classBuild.classNode().AOTcompile())
        {
            classBuild.classNode().AOTsave();
            info("Added method getTime, compiled, and saved");
        }
        else
        {
            info(strFmt("Unable to compile method 'getTime' with source code '%1', restoring class...", treeNode.AOTgetSource()));
            // Delete the non-compiling method
            if (treeNode)
                treeNode.AOTdelete();

            classBuild.classNode().AOTsave();
        }

    }
    else
    {
        info("Method 'getTime' already exists");
    }

    if (sysDictTable.isMap())
    {
        if (sysDictTable.doesMethodExist('getTime') == false)
        {
            treeNode = sysDictTable.treeNode().AOTfindChild('methods').AOTadd('getTime');
            method = sysDictTable.treeNode().AOTfindChild('methods').AOTfindChild('getTime');
            method.AOTsave();
            method.AOTsetSource(methodSource, true);
            method.AOTsave();


            if (sysDictTable.treeNode().AOTcompile())
            {
                sysDictTable.treeNode().AOTsave();
                info(strFmt("Added 'getTime' to AccountSumMap"));
            }
            else
            {
                info(strFmt("Unable to compile method 'getTime' with source code '%1', restoring class...", treeNode.AOTgetSource()));

                // Delete the non-compiling method
                if (treeNode)
                    treeNode.AOTdelete();

                sysDictTable.treeNode().AOTsave();
            }
        }
    }
}
0
user3226663 On
private void findOrCreateTimeStamp(
        SysVersionControlTmpItem                _item)
{
    str                             timeStamp;
    UtilElements                    utilElement;
    SysDictClass                    dictClass;
    ClassBuild                      classBuild;
    SysVersionControlTmpItem        item            = _item;
    str                             methodName      = "csGetVersion";
    int                             time            = timenow();
    TreeNode                        treeNode        = TreeNode::findNode(item.ItemPath);

    utilElement = treeNode.utilElement();            

    timeStamp   = date2Str(
                        today(),
                        321,
                        DateDay::Digits2,
                        DateSeparator::Slash, 
                        DateMonth::Digits2,
                        DateSeparator::Slash,
                        DateYear::Digits4,
                        DateFlags::None);

    timeStamp   = timeStamp + "_"                                           +
                        num2str0(time div 3600, 2, 0, 0, 0) + "_"           +
                        num2Str0(time mod 3600 div 60, 2, 0, 0, 0) + "_"    +
                        num2Str0(time mod 3600 mod 60, 2, 0, 0, 0);

    if (utilElement.recordType == UtilElementType::Class)
    {
        dictClass   = new SysDictClass(className2Id(utilElement.name));
        classBuild  = new ClassBuild(utilElement.name, true);

        if (dictClass.hasStaticMethod(methodName))
        {
            //Override method here, since the method already exists in the component.
            classBuild.overrideMethod(methodName,
                                        @"public static str csGetVersion()" +
                                        "{"                                 +
                                            "return '" + timeStamp + "';"   +
                                        "}"); 
        }
        else
        {
            //Make a new method here since it does'nt exist in the component.
            classBuild.addMethod(methodName,
                                        @"public static str csGetVersion()" +
                                        "{"                                 +
                                            "return '" + timeStamp + "';"   +
                                        "}"); 
        }

        classBuild.classNode().AOTcompile();    
    }
}

The above method is created by referring to previous answer and other professionals. It validates if the method exists in the class first. If found it overrides else creates new method. For other elements like Tables, Forms and Maps we can implement in the similar way.