Understanding Process Triggers and Business Rule internals

One of the less utilised/understood feature of Business Rule is Process Triggers. In this post, I will explain what a process trigger is and how you can use this in the context of business rule.

The Basics

Business Rule is basically a workflow that has a different UI compared to the standard workflow editor. You can quickly find all the business rules in your CRM instance by running this query.

Business Rules

Internals – How does Business Rules work

You can basically skip this part, if you are not interested in understanding the internals on how a business rules work. When you create a business rules you basically have all these components that make the business rules run seamlessly:

  1. The client side code that runs on the form
  2. The server side workflow defined in xaml
  3. Process trigger -> This dictates when the business rule logic should execute

When you design a business rule, it is automatically translated into a workflow xaml that executes on the server side and JavaScript code that executes on the client side.

Now, let us take a simple example of a business rule that sets the “Salutation”, when “Gender” is changed. Here is the business rule

Business Rule Definition

When you save this business rule, this is automatically translated into JavaScript, code that can run on the client side. Below is the JavaScript code that is generated by CRM, for this business rule:

function pbl_109af564df34e51180eac4346bc576e8() {
    try {
        var v0 = Xrm.Page.data.entity.attributes.get('gendercode');
        var v1 = Xrm.Page.data.entity.attributes.get('salutation');
        if (((v0) == undefined || (v0) == null || (v0) === "") || ((v1) == undefined || (v1) == null || (v1) === "")) {
            return;
        }
        var v2 = (v0) ? v0.getValue() : null ;
        if ((v2) === (1)) {
            v1.setValue('Mr');
        } else if ((v2) === (2)) {
            v1.setValue('Ms');
        }
    } catch (e) {
        Mscrm.BusinessRules.ErrorHandlerFactory.getHandler(e, arguments.callee).handleError();
    }
}

Below is the JavaScript code this calls the “pbl_109af564df34e51180eac4346bc576e8” function that contains the logic for the business rule.

Mscrm.BusinessRulesScript.Initialize = function() {
    Mscrm.BusinessRulesScript.AttributesOnChangeHandlers = {};
    Mscrm.BusinessRulesScript.ControlsOnClickHandlers = {};
    (function() {
        var onchangehandler = function() {
            pbl_109af564df34e51180eac4346bc576e8();
        }
        ;
        Mscrm.BusinessRulesScript.AttributesOnChangeHandlers['gendercode'] = onchangehandler;
        var attributeObject = Xrm.Page.data.entity.attributes.get('gendercode');
        if (attributeObject != null && attributeObject != undefined) {
            attributeObject.addOnChange(onchangehandler);
        }
    })();
    pbl_109af564df34e51180eac4346bc576e8();
};

From the above, triggering code we can see that the business rule is going to run when the form is opened, as the function “pbl_109af564df34e51180eac4346bc576e8” is called when the business rule is initiated. The function also executes when “Gender” is changed.

If you want to know what the generated JavaScript code for the business rule is, just get the “ClientData” field in the “Workflow” entity. You cannot get this field from Advanced Find. You can either use FetchXML Builder (a XrmToolBox tool) or LINQPad. Below is the fetchxml query, I used.

FetchXml

If you also get the “xaml” field on the workflow entity, you can see the markup server side workflow logic that will execute.

Process Trigger

Process Trigger dictates the events that will trigger the execution of business rule. There are three events:

  1. Load
  2. Change
  3. Save

“Load” and “Change” are the standard triggers when the business rule is created through the UI. “Save” is a special handler. It can only be set using the SDK and not through the UI. It behaves little differently compared to “Load”. The JavaScript code that is generated for “Save” is little different compared to the code that is generated for “Load”. Here is the LINQ query I used for getting process triggers for this workflow.

LINQPad

Now let us update the “load” trigger to “save”, so that the generated JavaScript for the business rule will run only on “Form Save” event and not on “Form Load”. Here is the simple snippet I ran to do this, after I got the ids of the process trigger in the previous LINQ Query. These process triggers are for the “load” events associated to our business rule. You have to deactivate the business rule, before you update the process trigger for the business rule.

Process Trigger Update

Now comes the important bit: Activate the business rule from the Advanced Find results (first screenshot). Don’t activate the business rule from the standard business rule window. If you activate the business rule from the standard UI, your process trigger will reset back to “load”

ActivateDont Activate

Now that the trigger is set to “Save”, lets compare the generated JavaScript code.

Compare Load and Save

As we can see, in the case of “save” process trigger, the client side business rule code runs only on “Save”. I like this, because I don’t want the business rule to run on “load” and confuse the user with “Unsaved changes” message. I will demonstrate this with a scenario.

Scenario: User opens a contact record, which doesn’t have the “Salutation” field set. Gender contains a valid value. The process trigger is “load”

Form OnLoad

As you can see from the above screenshot, the business rule ran immediately on form load, and set the Salutation to “Mr”. Hence, you have a unsaved changes message, on the bottom right. I am not very happy with this result because, it is not obvious to the user what changed and what caused the change. I want more control, so I want this rule to run only after “Save”. Now look at the same form, when the trigger is “Save”

Form OnSave

As you can see, the “Salutation” field is not set immediately. It will be set only

  1. When the form is saved OR
  2. When the “Gender” field is changed

One more thing: Every time when you deactivate and reactivate a business rule, new process triggers records are created, and so you have to get the correct ids when you update the “event” attribute.

I hope you can now understand the internals of business rule and how to use process trigger to control its behaviour.

References:

  1. TechNet: Create and edit business rules
  2. MSDN – Create or edit how business rules are initiated

 

 

14 comments

  1. Its good article and helps to understand the Business Rules in CRM, but i have a question that you have just changed on load BR to on save but i want to write a BR that triggers only on changes not on on load, on save is it possible can you help me how to achieve it.

    Thanks in Advance.

    • I tested this scenario today. Below are the steps

      1. Unpublish the business rule
      2. Use the linq query in the first screenshot to identify the process triggers for your business rule
      3. Delete the “load” processtrigger record using the SDK
      4. Activate the business rule from the advanced find results, not from the business rule UI
      5. Check once again in LinqPad that your business rule has only one trigger

      The business rule should run only on change, and not on load.

  2. Love the in-depth walk through of your article. The scenario at the end I’m sure many of us CRM devs could relate to.
    I have one question. From what entity/column do you extract the calling code below:
    Mscrm.BusinessRulesScript.Initialize = function() { …};

    THank you.

  3. Thanks for the great post! I’ve got a solution now for the “Why does it say there are unsaved changes? I didn’t make any changes” question from clients!

  4. This is awesome! Thanks for the great post Natraj! I’ve also had questions from clients “Why does it say there are unsaved changes???”

  5. Hello Natraj,

    Is it possible to trigger the business rule through a JavaScript code. I have a business rule created for a field [Field A] that hides/shows other fields [Field B, Field C] based on its value. Here the problem is when I set the field A value through JavaScript, business rule is not triggering may be it is not recognizing it is an on change event. But when I manually update the field A value business rule is triggering [On change event]. Any idea how to resolve this issue. I mean how can I trigger the business rule when the field A value is updated by JavaScript code [This should happen before save]. I know this can be fixed by implementing the business rule logic inside JavaScript but our end users want to use business rule instead of JavaScript.

  6. Hi Natraj,
    Does this work in D365 online instance. I am not able to view formscript.js to debug my BR.
    Thanks

Leave a comment