Augmented classes on Tables [ExtensionOf]

Recently I posted a Trick to create a display method on sys Tables using overlaying. In further researches, due to necessity, I bumped into a new and more robust way of doing the same.

The purpose of this post is to explain a possibility to facilitate the manipulation of Table Methods on Augmented classes.

Augmented classes are necessarily  Final classes defined by the use of the Attribute ExtensionOf on its declaration, in my example I’m augmenting the Table ProjForeCastOnAcc.

//Begin: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018
[ExtensionOf(tableStr(ProjForecastOnAcc))]
final class ProjForecastOnAcc_Extension
{
}
//End: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018

This allows us to interact with the class as if it were the actual table, So we have access to fields, methods, and properties from the original table.

I created this new display method on it, notice that at line ‘8’  of the following code, I’m mentioning one field from the original table by using the reserved word “this”, although the current object is not the actual table. All fields, methods, and properties from the original table can be accessed this way as if we were in the actual object.

//Begin: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018
[ExtensionOf(tableStr(ProjForecastOnAcc))]
final class ProjForecastOnAcc_Extension
{
[SysClientCacheDataMethodAttribute]
public display ProjGrantName grantName()
{
return ProjGrant::findByGrantId(this.ProjGrantId).GrantName;
}
}
//End: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018

X++ Executing Table methods from Augmented classes

This feature allows us to access these new methods as if they were located in the original table wherever a buffer is created. The next code is a non-related Class making use of the new Display Method on the Augmented class, notice line 12 of the following code:

//Begin: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018
class ProjForecastOnAcc_Ext_Test
{
static void main(args args)
{
ProjForecastOnAcc forecastOnAcc;
while select forecastOnAcc
where forecastOnAcc.ProjGrantId
{
info(strfmt("%1 - %2",
forecastOnAcc.ProjGrantId,
forecastOnAcc.grantName()));/*New method on ProjForecastOnAcc_Extension*/
}
}
}
//End: Felipe Nogueira - AXAPTAHUT , Apr 9th 2018

Form usage of display methods from Augmented classes

The way of mentioning the extended methods on Forms is still the same as in the old trick. You must have the correct DataSource, then insert the full name of the Augmented Class together with the desired display method name to the field’s property “Data Method”, like this:

  • DataSource: ProjForecastOnAcc
  • DataMethod: ProjForecastOnAcc_Extension::grantName

ExtensionOf1

If done correctly, this solution should work without any issues.

Follow us and get exclusive AX DEV content weekly

Hope it might be helpful,
Thanks,
Felipe Nogueira

 

Customizing Hierarchical Grid Common (Project WBS Grid) Dynamics 365

Hello DAX DEV,

I recently was given a task which the purpose was to disable some fields, buttons and change the calculation of the Project WBS Hierarchical Grid Control in Dynamics 365.

With the requirement of using Extensions and Overlaying and not customizing any SYS objects, the following topics explain a little bit about the necessity, its implications and how it turned out to be possible.

The WBS form Path is: Project management and accounting > Projects > All projects > PLAN (Button Group) > Work breakdown structure (Menu item button)

WBS Original

The highlighted control is not a regular Grid, it is a Hierarchical Grid Common. After debugging it a lot, I found out that the grid is almost entirely controlled by a JavaScript file mentioned on the properties of this Grid control:

Property box Original

Note issue#1: JS path property cannot be altered on this form nor on a form extension, It’ll always pop up this warning and cancel the operation:

errorJS

Note issue#2: It is impossible to overwrite the “Object” Property on a display menu item extension, It’ll always pop up this warning:

MenuItemDisplayError

Scenario difficulties:

  1. As mentioned, it is a requirement that all the changes are limited to new objects and/or extensions only, we cannot customize existing elements from MS Models.
  2. All Grid calculations happen on this JavaScript file, not on any X++ based Object.
  3. The Proj WBS Form and its extension do not allow any change to the property  “JavaScript Extension file” on the Hierarchical Grid Common  Issue#1.
  4. It is impossible to overwrite the Object Property of a display Menu Item Extension Issue#2.
  5. Javascript files are stored in the Application explorer as Resources and Microsoft did not release yet the functionalities of extensions or overlaying for Resources.

Solution :

  1. Duplicate the JS file,  with the same code but with a different name.
    • Further changes to the behavior of the Grid will be manipulated in this JS file.
  2. Duplicate the form & Create a new Menu Item Display for it.
    • In this new form duplicated from “ProjWorkBreakdownStructure” , find the Hierarchical Grid and Change its property “Javascript Extension Files” to your new JS resource name.
      • Issue 1, Only by duplicating the form AX will allow the user to alter the “Javascript Extension Files” property of the Hierarchical Grid Common control.
      • Issue 2, By default, the property object cannot be altered on a Display Menu Item extension, so a new menu item is needed to access the duplicated form.
  3. Overlay the Init Method of the original Sys Form
    • Create a new “FormHelper” class, and overlay the init Method from Form ProjWorkBreakdownStructure, then use X++ to get the args object from the Original Form execute the form methods run* and close, Then open the menuItem of the duplicated form and send the original args object to it.
      • (*) It is indispensable to execute the method Run before closing the original form, so AX won’t crash.
class ProjWorkBreakdownStructureFormHelper
{
/// <summary>
/// Method closes ProjWorkBreakdownStructure and opens the
/// custom form newProjWorkBreakdownStructure with the same args.Record()
/// </summary>
/// <param name="args"></param>
[PostHandlerFor(formStr(ProjWorkBreakdownStructure), formMethodStr(ProjWorkBreakdownStructure, init))]
public static void ProjWorkBreakdownStructure_Post_init(XppPrePostArgs _args)
{
Object formRun = _args.getThis();
Args args = formRun.args();
formRun.run();
formRun.close();
new MenuFunction(menuItemDisplayStr(newProjWorkBreakdownStructure),MenuItemType::Display).run(args);
}
}
  1. Alter the new JS file to perform the changes needed. In my case they were:
    • Removing 3 fields from the GRID: 
      • Around line 1300 of the JS file, there is a function called “getColumns” where the object “columnsArray” is located. This object can be manipulated and controls the Columns visibility and order

WBSCollumnsArray

    • Removing 2 Buttons from Grid’s Action pane:
      • Close to line 1500 of the JS file there is a function called  “_initToolbarContainer” that receives an object “container”, this container controls the buttons visibility and order.

wbsToolbars

    • Altering the Grid’s calculation on field changed: 
      • Approximately at line 525 of the JS file, there is a function called “cellValueChanged” that is executed whenever there’s a data modification on any field of the Grid, This function has a switch case with one separated case for each field. All the data calculation and grid responsiveness happen here, so any change in the logic needs to be done here. 

WBSCalculationJS1

      • Perform the change on the Grid’s calculation by manipulating the new JS file:
      • Some of the cases of the switch case trigger a calculation of values. To do the required modifications it was necessary to change those cases, comment some specific lines and call the newly created function “calcResourceNum” that unifies the calculation with the expected calculation rule.

WBSCalculationJS2

After altering the JS file, the behavior of the Grid was exactly as expected, the unnecessary fields and buttons were removed, and the new calculation rule was placed.

Developer important note – Minor Threat to MS HotFixes: 

There is a drawback to this solution, from my perspective it is currently insoluble, that is: Because it was impossible to manipulate the JS path property on the Form Extension Issue#1 and it is also impossible to alter the Object Property of a Display menu Item Issue#2, It was necessary to create a form duplicate and a PostHandler to catch the regular form Init method, close it and open the duplicate Form by code with the same arguments.

With this solution in place, if Microsoft releases a new hotfix that includes changes to this form, at first, the change will not take place automatically. It will only take place if the HF changes are also replicated manually to the duplicated form or after removing the old duplicate and creating a new duplicate with the same name, Doing step 2 of the solution again to catch up with the latest MS HotFix changes to this form.

Follow us and get exclusive AX DEV content weekly

Thank you for reading, I hope it had been helpful,
Felipe Nogueira

Display Method on Sys Tables Using Overlaying D365

Hello DAX DEV,

Before going to the trick I’ll explain a little bit about Overlaying and extensions on Ax Objects:

Intro About Extensions:

One of the great feature added to Microsoft Dynamics 365 is the concept of Overlaying and Extensions, available for most objects, like tables, forms, data types, menu items, queries and so forth.

To guarantee the integrity of the original code from Microsoft many AX objects can now have their behavior or properties overwritten by this new set of elements instead of manipulating the actual Sys Code.

It is still possible to customize original objects, but this is not a best practice, so much so that most D365 Development Administrators have disabled this possibility on DAX DEV servers, to force developers to manipulate Sys Objects only by extensions and overlaying.

Tables extensions are very useful to create structural changes, like altering field dataTypes, Labels, adding new fields, creating relationships, indexes, events interceptions and so on, but you cannot create or alter table methods on a table extension, so when this is required, the limitation presents a problem.

ProjTableExt
The solution consists on creating a new Static Class, that will work as source code for your Sys Table and here’s an example of a display method for table ProjBudget that will be used later on ProjBudget Form [Extension].

SOLUTION

THERE'S A NEW AND BETTER WAY OF DOING THIS. CHECK NOW ON AXAPTAHUT
 Augmented classes on Tables [ExtensionOf]
  1. First, you need to create a new Static class that will act as the extended source code for the table using the naming pattern TableName_Extension (trick: you can add project suffixes to the  class name but it is important that the class be static)
  2. Then add a public static display method receiving the table as a parameter.
    • static class ProjTable_Extension
      {
      [SysClientCacheDataMethodAttribute(true)]
      public static display DirMemo projValGroupId(ProjTable _projTable)
      {
      DirMemo ret;
      container conGroupId;
      ProjValProjCategorySetUp projValCategorySetup;
      while select GroupId from projValCategorySetup
      where projValCategorySetup.ProjId == _projTable.ProjId
      {
      conGroupId += projValCategorySetup.GroupId;
      }
      ret = con2Str(conGroupId,",");
      return ret;
      }
      }
  3. Then, on the Form or Form extension, that has that table, you’ll add the display method in a slightly different manner than usual. After creating field control where it necessary, you should set the correct “Data Source” property and here’s another trick, you should input an expression to the Data Method property mentioning the static class and the static display method you’ve created
    • Data Method Pattern: TableName_Extension::DisplayMethodName
    • Here’s the example:
      • DataSource: ProjTable
      • DataMethod: ProjTable_Extension::projValGroupId
    • DisplayonFormsExt

After performing those steps, your display method should work without any issues.

Hope it might be helpful,

 

Follow us and get exclusive AX DEV content weekly

Thanks,
Felipe Nogueira

https://gist.github.com/FNogger/5443793f18676e6e77e150e61ed6b1b8.js