Pages

Thursday 3 April 2014

Form error notifications using Javascript in CRM 2013


In this post I am discussing some of the new exciting changes in the CRM 2013 SDK for client side JavaScript. In particular I highlight 4 new Xrm.page methods to do with placing notifications on a CRM 2013 form, and how to prevent auto-save via JavaScript.  To find out more, read on…

New JavaScript Methods in MS CRM 2013

Note: CRM 2013 is not due to be released until October 2013. The information provided in this blog might different from the final product.
As always, the best place to start on using JavaScript when coding for any Dynamics CRM version is the Microsoft MSDN site. In particular, “Use JavaScript with Microsoft Dynamics CRM“ contains a wealth of information about best practices for writing client side scripts  for Dynamics CRM. Be aware that this site currently only shows information for Dynamics CRM 2011. I would assume it’ll contain information specifically for Dynamics CRM 2013 after it is officially released in October.

Form Notification and Control Notifications in CRM 2013

Often customers require the ability to display messages to the user dynamically based on certain data entries on a form as the user is working on the form. This requirement is achieved previously by  JavaScript “alert” messages based on conditional checks of values in the fields displayed on the form. For instance, in Dynamics CRM 2011, the “alert” message in JavaScript will produce a “pop-up” message box displaying certain information. The user must click “OK” on the message box before continuing.
JSFormNotification-01
In Dynamics CRM 2013 however, in order to minimise the number of pop-up windows, the new SDK now includes 2 types of new notification on the form which you can add/remove via JavaScript:
Form Notification
  • Xrm.Page.ui.setFormNotification(message, level, uniqueid)
    This Xrm method displays a notification on the top of the record.
    Message: message string to be displayed in the notification.
    Uniqueid: string identifier for this message
    Level arguments:
    • “ERROR” (notification uses system error icon)
    • “WARNING” (notification uses system warning icon)
    • “INFO” (notification uses system info icon)
  • Xrm.Page.ui.clearFormNotification(uniqueid)
    This Xrm method removes the form notification set by  “setFormNotification”.
    Uniqueid: string identifier of the form notification to be removed.
Control Notification
  • Xrm.Page.getControl(fieldName).setNotification(message)
    This Xrm method displays a message near the specified control on the form
    FieldName: name of the field on the form you wish to get the control of
    Message: message string to be displayed in the notification
  • Xrm.Page.getControl(fieldName).clearNotification()
    This Xrm method removes the control notification
    FieldName: name of the field on the form you wish to get the control of
Note: Xrm methods is not the only way to display notifications to users in CRM 2013. You can also use e.g. CRM 2013 business rules.

Example

Suppose you have the following requirements from a customer: on the account form, we would like to:
  1. Display an information banner on this account when the “Credit Limit” field is filled in but the “Payment Terms” is not.
  2. Display a warning banner on this account if its “Credit Hold” is “Yes”.
  3. Display a message near the “SIC Code” field of an account if this field contains a value but the data does not start with “SIC-”.
Again, you can fulfill the above requirements in different ways now in CRM 2013 without writing a single line of JavaScript, but for the purpose of this post, I shall meet the requirements using Form Notifications for 1) and 2), and Control Notification for 3).
Requirement 1) involves interactions between 2 fields “credit limit” and “payment terms”. We need to work out when the form notification should be set and when it should be removed. E.g. let’s create a method called “CreditLimitFormNotification” that does the following:
  • Set form notification when “credit limit” is not null and “payment terms” is null
  • Clear form notification when “credit limit” is not null and “payment terms” is not null (i.e. user has set the payment terms on the account), or when “credit limit” is null (i.e. user has not set the payment terms).
In code, this would be:
CreditLimitFormNotification: function () {

    //If credit limit field has data but payment term has no data,
    //set a form notification to notify user that payment term should be filled in.
    //If credit limit has no data then clear the form notification

    var creditLimitValue = Xrm.Page.getAttribute("creditlimit").getValue();
    var paymentTermsOptionSet = Xrm.Page.getAttribute("paymenttermscode").getValue();

    if (creditLimitValue != null && paymentTermsOptionSet == null) {
        Xrm.Page.ui.setFormNotification(
            "The credit limit contains a value. Please ensure payment terms for this account is completed.",
            "INFO",
            "creditLimitNotification");
    }
    else if ((creditLimitValue != null &&   paymentTermsOptionSet != null)
            || creditLimitValue == null) {
        Xrm.Page.ui.clearFormNotification(
           "creditLimitNotification");
    }
}
Requirement 2) is simpler to work with. Let’s create a method called “CreditOnHoldFormNotification” that does the following:
  • Set form notification when “credit hold” is set to “Yes”. Clear form notification when “credit hold” is set to “No”.
CreditOnHoldFormNotification: function () {

    //If account's credit is on hold, set a form notification
    //If account's creidt is not on hold, clear form notification

    var creditOnHoldOptionSet = Xrm.Page.getAttribute("creditonhold").getValue();

    if (creditOnHoldOptionSet == true) {
        Xrm.Page.ui.setFormNotification(
            "This account's credit is on hold. Do not process any orders for this account.",
            "WARNING",
            "creditOnHoldNotification");
     }
     else if (creditOnHoldOptionSet == false) {
        Xrm.Page.ui.clearFormNotification(
            "creditOnHoldNotification");
     }
}
Requirement 3) can be met by another method called “SICCodeControlNotification” that does the following:
  • Set control notification when “SIC Code” is filled in but data does not match the required “SIC-”. Clears control notification if “SIC Code” is null or if “SIC Code” contains data that meets the required “SIC-” format.
SICCodeControlNotification: function () {

    //If SIC Code is not null and data does not start with "SIC-", set control notification
    //If SIC Code is null or if SIC Code meets formating requirements, clear control notification

    var sicCodeValue = Xrm.Page.getAttribute("sic").getValue();

    if (this.SICInCorrectFormat(sicCodeValue) == false) {
        Xrm.Page.getControl("sic").setNotification("SIC Code format should begin with SIC-");
    }
    else {
        Xrm.Page.getControl("sic").clearNotification();
    }
}
Where the SIC Code Format check can be easily done by using regular expressions: e.g.
SICInCorrectFormat: function (value) {

    //Match value must start exactly with "SIC-"
    if (value != null) {
        var regexpPattern = /^SIC-/;

        if (value.match(regexpPattern) == null) {
            return false;
        }
    }
    return true;
}
Once the code is ready, I hook the following to the account form:
  • Account form “OnLoad” event: “CreditLimitFormNotification”, “CreditOnHoldFormNotification”.
  • Account form’s attribute “SIC Code” “OnChange” event: “SICCodeControlNotification”.
Now when I open an account form that has e.g. “Credit Limit” of £10000 but no “Payment Terms”, “Credit Hold” set to “Yes”, or “SIC Code” not in the correct format, I see the following form and control notifications.
JSFormNotification-02

Got-Cha’s on Form Notifications and Control Notifications

In the brave new world of CRM 2013, alas, very little is as simple as it first appears. The above 3 requirements have been met, but your customer might not be very happy with your work. Here is why:
  • Form and Control Notification by themselves are non-blocking event. It’s all very well to display “Credit On Hold” form notification or “SIC Code” format control notifications, however there is no JavaScript included in this discussion to block a user from saving the field values into database. E.g. a user can still go ahead and save a “SIC Code” that does not conform to the “SIC-” format requirement. Depending on whether this is included in your customer’s requirement, it can mean more JavaScript development to protect database values by e.g. block the account form’s manual save event and auto save events if “SIC Code” is not in the correct format. An “ERROR” form notification can be displayed to ensure the user is aware of this formatting issue.
  • Auto save in CRM 2013 causes the form to reload. CRM 2013 auto-saves a form every 30 seconds (you can turn it off but it’s not recommended by Microsoft). In the discussion above, I have only hooked the “SIC Code” control notification method to the “OnChange” event of “SIC Code”, and the “Credit Limit” and “Credit On Hold” methods to be “OnLoad” event of the account form. This means:
  1. A user might change e.g. “Payment Terms” or sets “Credit Hold” to “No” and expects the form notification to be immediately removed. This will not happen and notification is not removed until the form auto-saves (or user manually saves the form), and it triggers an auto-refresh of the form.
  2. A user sees a control notification near “SIC Code” but suddenly the form auto-saves which triggers the “OnLoad” of the form. As the SIC Code notification is only attached to the “OnChange” event of the field, the control notification disappears when form reloads.
  3. Similarly, a user might delete the “Payment Terms” field when “Credit Limit” contains data. User might expect an immediate form notification pop up to warn them to reset “Payment Terms” but this wouldn’t happen as the Form Notification methods are currently hooked on to the Account form “OnLoad” events.
While the code is correct, it is apparent that understanding which events to hook the methods to become very important. To address the above missing functionality, we need to trigger the following methods for the events:
  • Account form “OnLoad” event: “CreditLimitFormNotification”, “CreditOnHoldFormNotification”
  • Account form’s attribute “SIC Code” “OnChange” event: “SICCodeControlNotification”
  • Account form’s attribute “Credit Limit” “OnChange” event: “CreditLimitFormNotification”
  • Account form’s attribute “Credit Hold” “OnChange” event: “CreditOnHoldFormNotification”
  • Account form’s attribute “Payment Terms” “OnChange” event: “CreditLimitFormNotification”

Preventing Manual/Auto-Save with JavaScript in CRM 2013

Given the above example, how can we prevent manual/auto-save if “SIC Code” fails the formatting validation?
To address this, Xrm now has a new “Save Mode” of 70 which denotes a form’s auto-save event. This means we need a JavaScript function that passes in the form’s “econtext”, check for its “save mode”, prevent auto/manual-save if “SIC Code” validation fails. To do this, we need the following Xrm methods:
  • econtext.getEventArgs().getSaveMode()
    A return value of 1 denotes manual save or Xrm save
    A result value of 70 denotes auto-save
  • econtext.getEventArgs().preventDefault()
    This method prevents the “save” action.
Now all we have to do is put this logic into a JavaScript method that is triggered on the “OnSave” event of the Account form. Don’t forget to pass the form’s context as the first parameter when setting this up in CRM! Additionally, the method will show an “Error” form notification on the account warning users that they cannot save this form until the SIC Code formatting issue is resolved.
// Hook this method to the Account form "OnSave" event
// Pass execution context as first parameter when registering on form's OnSave event
OnFormSave_Account: function (econtext) {

    var eventArgs = econtext.getEventArgs();
    if (eventArgs.getSaveMode() == 70 //autosave
        || eventArgs.getSaveMode() == 1) //manual save or Xrm save
    {
        if (this.SetSICCodeFormNotification() == true) {
            //Prevent auto/manual save
            eventArgs.preventDefault();
        }
    }
}
Now when you type a value in “SIC Code” on the Account form and you either save manually or auto-save triggers in the background, this JavaScript method will fire to show an ERROR form notification and blocks this save action.
JSFormNotification-03
When the user corrects this formatting issue and manually save/autosave again, both the form and control notification for “SIC Code” will disappear and saving action will succeed.
JSFormNotification-04

No comments:

Post a Comment