How To Write A D365 Edit Method

Share this:

Most of the time the data you want to show on a form is stored in a field on a table. Using Display methods you can run code to determine what is shown. A limitation of a display method is that the value cannot be edited. A D365 Edit method, tied to a form control, lets you run code on both what the user inputs and what is displayed back to the user. In this article, I will explain how to write a D365 edit method and when to use one.

Display Methods Versus Edit Methods

On a Microsoft Dynamics 365 for Finance and Operations form, you can show a grid. And on that grid you can show multiple columns such as strings, numbers, dates, enums, and more.

Most of the time the controls in the grid have a DataSource property set. And this means that grid is showing you data that is retrieved from the DataSource on a form.

And again, most of the time, the DataField property is set on the form control. This means that the control will show you the value stored in the DataSource field specified. And editing the value in that form control will cause the value you entered to be stored in the DataSource field.

However, there are special cases when the value you wish to show is not stored explicitly in a field on the DataSource table. And in many of those cases, you can use a D365 Display method to run code and display a different value than what is stored in the field.

Although Display methods are effective in many cases, there is a limitation. Controls that use Display methods cannot be edited. They are for display only.

Unlike Display Methods, Edit methods do allow a user to enter in a value into the control. Additionally, code can be run on the value entered. And code can be run to determine what is shown back to the user. In effect, a D365 edit method can do everything a display method can do, and more.

How To Write A D365 Edit Method

Edit methods are very similar to x++ methods. However there are a few required pieces that make a method an edit method.

  1. Edit methods must use the keyword ‘edit‘ in the method definition.
  2. The method must take a first parameter that is of type boolean. The parameter should be named _set as a best practice.
  3. If the Edit method is defined on a table, then the second parameter of the method will be populated with the value the user entered into the form control. Therefore it needs to use an Extended Data Type that matches the one used on the form control. There will be no third parameter.
    If the Edit method is defined on a form Data Source, then the second parameter will be a table buffer that matches that of the form Data Source. And there will be third parameters that will be populated with the value the user entered into the form control. Therefore the third parameter needs to use an Extended Data Type that matches the one used on the form control.
  4. The method must return a value that can be displayed in the form control. Therefore the return type should match the type used on the form control.

Explaining Edit Methods

Below is an example Edit method. It is from the VendTable table in Microsoft Dynamics 365 for Finance And Operations. Notice the ‘edit’ keyword in the method definition. Additionally, notice that two parameters are passed in: ‘set‘ and ‘_reasonCode‘.

Display

When the form is shown to the user, the method will be called by the system. The system will set the parameter ‘set’ to false. This means that the method is essentially running in a ‘display’ mode. And there is no user input to process. In this situation, the system will call the ‘else’ statement, and run the code that I made the color orange.

The code that is orange will lookup the reason code in the VendOnHoldHistory table, based on the this.accountNum value stored on the currently selected record. Then it will take the value from the ‘ReasonCode’ field, and store it in a variable named _reasonCode. Finally, the system will return that value, and show that value on the form.

public edit ReasonCode editBlockedReasonCode(boolean set, ReasonCode _reasonCode)
    {
        VendOnHoldHistory vendOnHoldHistory;

        if (set)
        {
            ttsbegin;
            vendOnHoldHistory = VendOnHoldHistory::find(this.AccountNum, true);
            vendOnHoldHistory.ReasonCode = _reasonCode;
            vendOnHoldHistory.update();
            ttscommit;
        }
        else
        {
            _reasonCode = VendOnHoldHistory::find(this.AccountNum).ReasonCode;
        }

        return _reasonCode;
    }

Until now, this has worked very similar to a Display method so far. But now, let’s look at how a D365 edit method is different.

Edit

If the user enters a value into the control on the form, the system will call the edit method. And in this situation it will set the ‘set‘ parameter to true’. And it will set the _reasonCode parameter to be the value that the user entered in.

In this situation, the code inside the ‘if (set)‘ condition will be called. I have made this code the color blue.

The code written will first find the record in the VendOnHoldHistory table using the currently select record’s this.AccountNum value. Secondly the code sets the ReasonCode value on this table. Thirdly, the code calls the update() method to update the related record.

Lastly the system returns the value in the variable _reasonCode. In this example the _reasonCode was not changed by the code. It is the same value. But there are other situations where a developer might decide to return a different value than the one that was passed in.

Example Use Cases

There are several common use cases for using a D365 Edit method. I will explain a few here. But there are a lot more, depending on how the developer needs the form to work.

First, even though a D365 Edit method can be used to simulate the same functionality of a form control that is tried directly to a Data Source, this would not be a good use case. Instead, a developer should just set the Data Source and Data Field properties on the form control. Then they are done, without needing to write an edit method.

Show and Update a Related Field

Edit methods can be used to find a related record, update a value on a related record, and then display that value back to the user. And while this can also be done by adding an additional Data Source to the form, and joining to it, using an Edit method is sometimes easier. And depending on the situation it can actually result in better performance.

The example above shows this use case. The ReasonCode field is not stored on the VendTable. Only the AccountNum field is. But the AccountNum field can be used to find the related record, where the ReasonCode is stored. And using an Edit method, the reason code can be shown and edited, almost as if it was stored on the VendTable record itself.

Display A Value Differently To The User

Perhaps you have a phone number that you would like the user to be able to enter in whatever format they wish. But then always display the phone number using dashes between each group of numbers.

Or perhaps you have a field that you want the user to be able to enter, but then always display a masked version of the value back. In the below example, from the MCRSalesLine table, the entered and stored gift card number is shown back to the user as a masked value.

/// <summary>
    /// Gets and sets the gift card number and returns it masked.
    /// </summary>
    /// <param name="_set">
    /// A <c>boolean</c> value that determines whether or not the user
    /// has modified the gift card number.
    /// </param>
    /// <param name="_retailGiftCardId">
    /// The new gift card card number.
    /// </param>
    /// <returns>
    /// The masked gift card number if one is set; otherwise, a blank string.
    /// </returns>
    [SysClientCacheDataMethodAttribute(true)]
    public edit RetailGiftCardId editMaskedGiftCardId(boolean _set,
                                                        RetailGiftCardId _retailGiftCardId)
    {
        if (_set)
        {
            this.GiftCardNumber = _retailGiftCardId;
        }
        if (_retailGiftCardId)
        {
            return MCRGiftCard::maskCardNum(_retailGiftCardId);
        }
        else
        {
            return '';
        }
    }

Here is an additional example I wrote. The Edit method removes everything but the numbers, for an entered phone number. The code then stores only the numbers in the field on the table. Finally the system reads the value from the table, adds formatting back to the phone number, and displays a formatted value back. In this case, the user will always use the phone number shown in the format of (###) ####-### which is easier for the eye to read.

    public edit Phone editPhone(boolean _set, Phone _phone)
    {
        Phone phoneWithFormatting;
        if (_set)
        {
            this.Phone = rsmVehicle::removeFormattingFromPhoneNumber(_phone);
        }

        phoneWithFormatting = rsmVehicle::addFormattingBackToPhoneNumber(this.Phone);
        
        return phoneWithFormatting;
    }

    public static Phone removeFormattingFromPhoneNumber(Phone _phone)
    {
        Phone phoneWithoutFormatting;

        //Remove everything except numbers.
        str pattern = @"[^\d]";
        phoneWithoutFormatting = System.Text.RegularExpressions.Regex::Replace(_phone, pattern, "");

        return phoneWithoutFormatting;
    }

    public static Phone addFormattingBackToPhoneNumber(Phone _phone)
    {
        Phone phoneWithFormatting;
        Phone phoneWithoutFormatting;

        //Remove everything except numbers.
        str pattern = @"[^\d]";
        phoneWithoutFormatting = System.Text.RegularExpressions.Regex::Replace(_phone, pattern, "");

        if (phoneWithoutFormatting != "")
        {
        //Add formatting back to phone number
        phoneWithFormatting = strFmt("(%1) %2-%3"
                                        ,subStr(phoneWithoutFormatting, 1, 3)
                                        ,subStr(phoneWithoutFormatting, 4, 4)
                                        ,subStr(phoneWithoutFormatting, 8, 3));
        }
        else
        {
            phoneWithFormatting = "";
        }

        return phoneWithFormatting;
    }

Validating the Input

The data input by the user is usually best validated in the validateWrite() method of the table or Data Source. But I have also seen it added to an edit method, when the Data Source isn’t present on the form. For example, look at this code from the MCRCustPaymTable tabl.

/// <summary>
    /// Sets or returns the gift card Id associated to the
    ///     current payment.
    /// </summary>
    /// <param name="_set">
    /// A <c>Boolean</c> used to determine if this method is
    ///     displaying or modifying the gift card Id.
    /// </param>
    /// <param name="_retailGiftCardId">
    /// RetailGiftCardId of the selected or displayed <c>RetailGiftCardTable</c> record.
    /// </param>
    /// <returns>
    /// The last four digits of the related gift card Id.
    /// </returns>
    public edit RetailGiftCardId editRetailGiftCardId(boolean _set, RetailGiftCardId _retailGiftCardId)
    {
        RetailGiftCardTable retailGiftCardTable;

        if (_set)
        {
            retailGiftCardTable = RetailGiftCardTable::findCrossCompany(_retailGiftCardId, conNull());
            //Gift card must exist.
            if (!retailGiftCardTable)
            {
                error(strFmt("@MCR11010", _retailGiftCardId));
                this.PaymInfoRecId = 0;
                this.PaymInfoTableId = 0;
            }
            else
            {
                this.PaymInfoRecId = retailGiftCardTable.RecId;
                this.PaymInfoTableId = retailGiftCardTable.TableId;
            }
        }
        if (this.PaymInfoRecId
            && this.PaymInfoTableId == tableNum(RetailGiftCardTable))
        {
            return this.getGiftCardNumberMasked();
        }

        return '';
    }

In this case, code is run to check to see if the record is found on any table, regardless of the company. And if it is not, then it returns an error.

Recap Of Use Cases

There are of course many use cases for a D365 Edit method. I recommend looking at the base Microsoft code for other examples. But the most common scenarios I have found, fall into one of these three categories. I find this helpful to describe in case you are wondering if it makes sense in your scenario to use an Edit method or not.

  1. Something needs to be updated or created on a related record. And something needs to be read from a related a record.
  2. Something different needs to be shown to the user than what is explicitly stored in the table field. Sometimes this means masking data, decrypting data, formatting the data, or concatenating data from multiple fields.
  3. Validating the entered value, or changing the entered value.

Where To Add An Edit Method

Similar to Display methods, Edit methods can be added to multiple objects in D365 F&O. They can be added to table methods, form methods and form data source methods. They cannot be used on Report Data sources.

When an Edit method is created on a form object, only that form can use that edit method.

Therefore, it is recommended that you add the Edit method to a table whenever possible. Adding the method to a table, allows the Edit method to be used by any form that has a Data Source that uses that table. This allows for your code to be reused in a lot more places.

Add An Edit Method To A Form

The next step in learning about how to write a D365 edit method is to learn how to connect your edit method to a form control.

First, create a new control on the grid of your form.

Right click on the control and select ‘Properties‘.

Se the ‘Data Source‘ property to be the name of the Data Source on the form, whose underlying table contains the display method.

Finally, instead of setting the ‘Data Field‘ property, set the ‘Data Method‘ property to be the name of your editmethod.

That is it. Now, for each record in the grid, the edit method will be run. The edit method ‘this’ variable will contain the current record being displayed. And when a user enters a value into the form control, that value will be passed in to the Edit method. And the ‘set’ parameter will be set to true. The system will run the code you have written in the method to produce a result that is shown in the form control.

Cautions When Using Edit Methods

There are some things that you should be aware of when using a D365 Edit method.

Whenever an edit method is used on a form, the edit method needs to be run once for every record shown on the form. This can have a performance impact. If the edit method you have written is time-consuming to run, the form will not be able to show the data quickly. And this will cause the user experience to suffer.

To mitigate this, instead of putting the edit method on a control that is on a grid. You can put the edit method on another tab, which is not always shown to the user. The edit method will only be run for controls that are being shown to the user.

In addition, the filter functionality on a grid control cannot be used on a column that uses an edit method. This is an important limitation to pay attention to. Therefore, if it is a requirement that the user be able to filter the control, then you need to not use an Edit Method. And instead join in Data Sources, or store the value off into a field that can be used.

The reason for this is because in order for the system to filter the results of an edit method, the edit method would need to be run against every record in the table. And this would be a huge performance impact. Whereas, one of the things that makes Edit Methods practical, is that they are only run on records the users is viewing.

Caching Edit Methods

One way that the performance of a edit method can be improved is to cache the edit method. Microsoft Dynamics 365 for Finance and Operations uses a lot of caching to improve the performance of the forms. However, all edit methods are not cached automatically.

Old Way Of Caching A Method

In order to cache the edit method, first override the ‘init’ method on the form.

Next, add the a line of code in this format:

<Data Source Name>_ds.cacheAddMethod(tableMethodStr(<TableName>, <Edit Method Name>));

For example, there is code on the SalesTable form, to cache the display method named ‘editContactPersonName’. You can find it in the ‘init’ method. It looks like this.

salesTable_ds.cacheAddMethod(tableMethodStr(SalesTable, editContactPerson));

The code uses the method cacheAddMethod on the form Data Source. The name of display method is passed into the method. The code uses the global function ‘tableMethodStr’ to get the name of the method. This global function takes the name of the table, and the name of the method as parameters. This is useful, because if the name of the method ever changes, a compile error will be thrown until this code is changed. Whereas a hard-coded string would only fail at runtime.

Please see additional Microsoft documentation here.

New Way Of Caching A Method.

There is a new way of Caching a method. Instead of overriding the ‘init’ method on a form, and adding a call to ‘cacheAddMethod’, the new way is much simpler. Simply add this attribute just above your method definition in code.

[SysClientCacheDataMethodAttribute(true)]

Summary

In this article I showed you how to write a D365 edit method. I explained that an edit method is just like a normal method, except that it uses the ‘edit’ keyword. Most of the time, Edit methods should be added to Table objects in the Application Explorer. And then they are tied to a form control by setting the Data Source and Data Method properties on the control.

Edit methods are very useful. They make it much easier to show and update values on related records. And they allow code to be run and values to be shown that are not stored in any table. Edit methods can be really useful for changing the format of what is displayed to the user without changing the value that is saved in the database.

There is a performance impact to using edit methods. And you cannot filter on edit methods. So developers should keep these limitations in mind before using them.

Peter Ramer
Peter Ramer is a part of the Managed Application Services team at RSM working on Microsoft Dynamics 365. He focuses on the Retail and Commerce industries. When he is not solving problems and finding ways to accelerate his clients' business, he enjoys time with his three kids and amazing wife.

Share this:

6 thoughts on “How To Write A D365 Edit Method

Add yours

  1. Hi Peter,
    Could you tell me why we don’t have to use update method in edit method? I mean
    for example have this in editMaskedGiftCardId method:
    this.GiftCardNumber = _retailGiftCardId;

    and not this:
    this.GiftCardNumber = _retailGiftCardId;
    this.update();

    1. Thanks for you question. When a form loads it reads data from a table and puts it in a data source which is the data in memory. And then the form shows the data from that datasource. From there, as a user you can modify the data in the fields but the system does not actually write or update the data right away. It just keeps it in that data source memory. And this is true of the edit method as well. Then, finally, when you either deliberately press the save button or you select a different record on the form, the system will take the data in the data source and then insert or update the data in the table.
      So, ultimately the reason you don’t call update in an edit method is that the overall system is designed to not write the data back to the table right after you change it. Instead, it waits until you leave the record and then does the update for you. This reduces the number of times the system has to interact with the database hard drive. This helps performance.

  2. Good day. Thanks for this mini series , it has really take n me from a complete noob to mid level D 365 dev now.

    My question is supposed i have a form real control, that any time it value changes, i want to use the new value to re calculate a display method column on a grid. What will be the approach?

    Thanks

    1. That’s really just what display methods do. While not 100% accurate, you can pretend that display methods run continuously, and so if a value used in them changes, then the output of your display method will change immediately as well.

  3. Can you please help me some code sample for this. I have tried lot of solution including using FormObserve attribute on the local variable but i did not get much success.
    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑