Skip to main content

AX 2012 - sysOperation Framework - Use controller class to open dialog from AX form

In my previous post on sysOperation framework Example I described how the sysOperation framework can be used for the batch functionality in contrast to RunBaseBatch framework. In this post I will explain how you can use sysOperation Framework classes to open a dialog from a AX form using contract and controller classes and then run logic in Service class.

In this example I added a new menu item "Example" on projProjectsListPage form which will call controller class. This example is create project transactions using service calls at the end.








First we need to create a contract class which holds parameters (dialog fields value or user input). To keep it simple I only added two parameters ProjId (Project Id) and ProjContractId (Project Contract Id). That's the model part of MVC pattern and view part is automatically created by using these data member attributes.
[DataContractAttribute]
class FF_ExampleContract
{
    ProjId              projId;
    ProjInvoiceProjId   projContractId;
}
[DataMemberAttribute,
SysOperationLabelAttribute(literalStr("Selected Project Id")),
SysOperationHelpTextAttribute(literalStr("Selected Project Id from projects")),
SysOperationDisplayOrderAttribute('1')
]
public ProjId parmProjId(ProjId _projId = projId)
{
    projId = _projId;
    return projId;
}
[DataMemberAttribute,
SysOperationLabelAttribute(literalStr("Selected Project contract Id")),
SysOperationHelpTextAttribute(literalStr("Selected Project Contract Id from projects")),
SysOperationDisplayOrderAttribute('2')
]
public ProjInvoiceProjId parmProjContractId(ProjInvoiceProjId _projContractId = projContractId)
{
    projContractId = _projContractId;
    return projContractId;
}

Let's move to controller part of sysOperation framework and create a new controller class.

For this example I don't need to have batch tab on dialog, so I set return value to FALSE in canGoBatch() method.
class FF_ExampleController extends SysOperationServiceController
{
    Common callerRecord;
}
public static void main(Args _args)
{
    FF_ExampleController controller;
    controller = FF_ExampleController::newFromArgs(_args);
    controller.parmShowDialog(true);
    controller.initFromCaller();
    controller.startOperation();
    controller.refreshCallerRecord();
}
public static FF_ExampleController newFromArgs(Args _args)
{
    FF_ExampleController        controller;
    IdentifierName              className;
    IdentifierName              methodName;
    SysOperationExecutionMode   executionMode;
    [className, methodName, executionMode] = SysOperationServiceController::parseServiceInfo(_args);
    if (_args.record())
    {
        executionMode = SysOperationExecutionMode::Synchronous;
    }
    controller = new FF_ExampleController(className, methodName, executionMode);
    controller.parmArgs(_args);
    controller.parmCallerRecord(_args.record());
    return controller;
}
public LabelType parmDialogCaption(LabelType _dialogCaption = "")
{
    LabelType caption;
    // This appears as the window name
    caption = "Create project transaction";
    return caption;
}
protected void new(
    IdentifierName _className = classStr(FF_ExampleService),
    IdentifierName _methodName = methodStr(FF_ExampleService, example),
    SysOperationExecutionMode _executionMode = SysOperationExecutionMode::ReliableAsynchronous
    )
{
    super(_className, _methodName, _executionMode);
}
private void initFromCaller()
{
    #define.dataContractKey('_contract')
    FF_ExampleContract contract;
    ProjTable       projTable;
    contract = this.getDataContractObject(#dataContractKey) as FF_ExampleContract;
    switch (this.parmCallerRecord().TableId)
    {
        case tableNum(ProjTable) :
            projTable = this.parmCallerRecord() as ProjTable;
            contract.parmProjId(projTable.ProjId);
            contract.parmProjContractId(projTable.ProjInvoiceProjId);
            break;
    }
}
public boolean canGoBatch()
{
    return false;
}
public Common parmCallerRecord(
    Common _callerRecord = callerRecord
    )
{
    callerRecord = _callerRecord;
    return callerRecord;
}
/// <summary>
///    Refreshes the calling form data source.
/// </summary>
protected void refreshCallerRecord()
{
    FormDataSource callerDataSource;
    if (this.parmCallerRecord() && this.parmCallerRecord().dataSource())
    {
        callerDataSource = this.parmCallerRecord().dataSource();
        callerDataSource.research(true);
    }
}

In the new method of controller class it is eventually calling service class method. We could create a method in controller class itself and refer that method into the new method of controller class to process business logic. This seems to be a lot for controller class, first to handle all parameters and then process business logic, recommended way is to separate the business logic in service class and another advantage of having service class is, these operations can also be used in web services (AIF) operations. That's the separate topic and we will talk about it later...

Let's create new service class and add entry point method to process business logic.
class FF_ExampleService
{
    FF_ExampleContract contract;
}
[SysEntryPointAttribute]
public void createProjectTransaction(FF_ExampleContract _contract)
{
    ProjId                  projId;
    ProjInvoiceProjId       projContractId;
    contract            = _contract;
    projId          = contract.parmProjId();
    projContractId  = contract.parmProjContractId();
    /*
   
    .... create project transactions
   
    */
}

Have we achieved what we aimed at start?

We are almost there, just need to add a new action menu item and assign controller & service class to it.




















That's it!!! run the menu item and see how it works...




Click on Example menu item from Project list page, it opened a dialog with correct title 'Create project transactions' and with correct Project Id passed from calling form (ProProjectsListPage). 

Happy Dax!ng...

Comments

Popular posts from this blog

The Dual Write implementation - Part 1 - Understand and Setup

What is Dual-write? Tightly couples – complete at one transaction level Near real time Bi-directional Master data and business documents – Customer records you are creating and modifying and at this document we are talking about sales orders or quotes and invoice. Master data could be reference data e.g. customer groups and tax information Why Dual-write and why not Data Integrator? Data Integrator is Manual or Scheduled One directional Now, Let's deep dive and understand what is required for Dual-write setup and from where to start. First thing first, check you have access to https://make.powerapps.com/ Choose right environment of CDS (CE) Make sure you have access to the environment too, click on gear icon and Admin Center  Look for required environment and Open it, you must have access as going forward you are going to configure dual write steps in the environment user the same user you are logged in now. Now, go back to power platform admin center and...

D365FO: Entity cannot be deleted while dependent Entities for a processing group exist. Delete dependent Entities for a processing group and try again.

Scenario: There are times when you want to delete an entity from target entity list and when you do so, you face an error message which does not tell you where exactly the entity has been used.  "Entity cannot be deleted while dependent Entities for the processing group exist. Delete dependent Entities for a processing group and try again. " Solution: Browse the environment by appending this part  /?mi=SysTableBrowser&TableName=DMFDefinitionGroupEntity&cmp=USMF   at the end.  For example; if the environment URL is  https://daxture.sandbox.operations.dynamics.com then the complete URL will be https://daxture.sandbox.operations.dynamics.com/?mi=SysTableBrowser&TableName=DMFDefinitionGroupEntity&cmp=USMF Filter for Entity and it will give you the DefinitionGroup where the entity has been added or used in data management import/export projects. Get the DefinitionGroup name and search in the export/import projects under data management and either del...

Dual-write connection set error: An item with the same key has already been added

If you happen to see this error message then you have duplicate records in cdm_company entity in CDS environment. Check for cdm_companycode field this is normally not allowed but have a look and delete the ones with duplicates.