Friday, October 24, 2014

OnChange part 3: Where is the clearOnChange method?

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

My first article in this series covered problems when trying to remove design-time defined onChange events in run-time using removeOnChange.

The second one covered problems with context awareness after manipulating event handlers using addOnChange.

To sum up the difficulties described in the two previous articles, it would be very useful to be able to say

Ok, I cannot remove the design-time event handlers, and there are some issues with manually added event handlers. So please, remove everything to give me a clean slate!

But there is no method to clear an attribute from all current event handlers.

To be able to remove an event handler, you must know its exact syntax. And you just can't remove event handlers that were introduced design-time.

It seems that introducing addOnChange and removeOnChange had a good intention and was a nice try, but they definitely didn't go all the way.

Wednesday, October 22, 2014

OnChange part 2: addOnChange with context awareness

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

My first article in this series covered problems when trying to remove design-time defined onChange events in run-time.

This article will cover some issues with "context awareness" that you may encounter when using addOnChange to alter the events firing from changes in the form.

A javascript web resource for a form typically has some event handlers and some business logic methods, all contained in a javascript "namespace" according to recommendations in the SDK, see section Namespaced library names.

It may look something like this:

Cinteros.JR.account = {

    // ---- Event handlers ---- //

    formLoad: function () {
        var attribute = Xrm.Page.getAttribute("numberofemployees");
        attribute.removeOnChange(Cinteros.JR.account.numberofemployees_onChange);
        attribute.addOnChange(Cinteros.JR.account.numberofemployees_onChange_with_vat);
    },

    numberofemployees_onChange: function () {
        var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
        var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
        var salaryCost = this.multiply(avgSalary, empCount);
        Xrm.Page.getAttribute("jr_salarycost").setValue(salaryCost);
    },

    numberofemployees_onChange_with_vat: function () {
        var avgSalary = Xrm.Page.getAttribute("jr_avgsalary").getValue();
        var empCount = Xrm.Page.getAttribute("numberofemployees").getValue();
        var vat = Xrm.Page.getAttribute("jr_vat_level").getValue();
        var salaryCost = this.multiply(avgSalary, empCount);
        var netsalaryCost = salaryCost - this.multiply(salaryCost, vat);
        Xrm.Page.getAttribute("jr_salarycost").setValue(netsalaryCost);
    },

    // ---- Business logic methods ---- //

    multiply: function (a, b) {
        return a * b;
    }
}

Notice how the internal method multiply is called by using syntax

  this.multiply(a, b);
This indicates that it is a method in the same (current) "namespace". This works fine and as expected when the event handler (numberofemployees_onChange in this case) has been added in the form customizations.

But when the event handler is added using attibute.addOnChange, it is not the call to the method that is passed to the function, but rather the "contents" of it. This in turn does not have a clue about my namespace, when executed.

Monday, October 20, 2014

OnChange part 1: Remove design-time event handlers

The Microsoft Dynamics CRM SDK comes with lots of functionality to affect how CRM behaves on the client side.
In a couple of articles I will discuss the opportunities ventilate my frustration over run-time event handling manipulation.

Events reacting to changes in fields can be defined design-time by making customizations to forms, and run-time by adding onChange event handlers by calling attribute.addOnChange(eventHandler).
To change the behavior run-time, there is also a method to remove designated event handlers by calling attribute.removeOnChange(eventHandler).
Read more about this in the SDK.

It is however not possible to remove event handlers that were added design-time.

The definition of methods addOnChange and removeOnChange are quite straight forward. You pass a function pointer to the method you want to add or remove. Much like you do when you define event handlers design-time.

account.name.onchange

In a scenario where a field is designed to have a specific event handler and you want to remove it to be replaced by another one, you would think that you call removeOnChange with the method name as entered in the customizations.

Sample form library:

Cinteros.JR.account = {
    formLoad: function () {
        var nameAttribute = Xrm.Page.getAttribute("name");
        nameAttribute.removeOnChange(Cinteros.JR.account.name_onChange);
        nameAttribute.addOnChange(Cinteros.JR.account.name_onChange_special);
    },

    name_onChange: function () {
        // Do standard things with name attribute
        Xrm.Utility.alertDialog("Normal function"); 
    },

    name_onChange_special: function () {
        // Do special things with name attribute
        Xrm.Utility.alertDialog("Special function"); 
    }
}

I discovered that the call to removeOnChange had no effect in this scenario. But the addOnChange added the new method as event handler. So I started digging using the F12 debugger in my browser. What does the function really do? And why does it fail silently?