Dynamics CRM Model Driven Apps: How to use addOnSave

As a developer, we need to know what tools we can use to achieve our task as efficient as possible. One of the API that now we want to learn is addOnSave. In short, addOnSave is an API that we can call to register an event to save the event to prevent or allow the changes.

For our demo purpose, I create a new entity called Custom Document which has 2 important fields called Type (OptionSet) and Description. So basically we want to validate if the Type selected is Case 1, we want to check Description contains the string “Case 1” or not. If match then we will allow saving, else prevent the save. All of the cases in this demo are the same. But in reality, you sure have different validation checking for each case.

var Blog = Blog || {};
Blog.Form = Blog.Form || {};
Blog.Business = Blog.Business || {};
var OPTIONS = {
    'CASE_1': 772060000,
    'CASE_2': 772060001,
    'CASE_3': 772060002
};
(function() {
    this.onSave_Validate1 = function(context) {
        console.log('case 1');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 1') > -1;
        if(valid) return;
        context.getEventArgs().preventDefault();
    };
    this.onSave_Validate2 = function(context) {
        console.log('case 2');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 2') > -1;
        if(valid) return;
        
        context.getEventArgs().preventDefault();
    };
    this.onSave_Validate3 = function(context) {
        console.log('case 3');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 3') > -1;
        if(valid) return;
        
        context.getEventArgs().preventDefault();
    };
    this.registerType = function(context){
        var formContext = context.getFormContext();
        var type = formContext.getAttribute('cr0c0_type').getValue();
        if(type === OPTIONS.CASE_1){
            formContext.data.entity.addOnSave(Blog.Business.onSave_Validate1);
        }else if(type === OPTIONS.CASE_2){
            formContext.data.entity.addOnSave(Blog.Business.onSave_Validate2);
        }else if(type === OPTIONS.CASE_3){
            formContext.data.entity.addOnSave(Blog.Business.onSave_Validate3);
        }
    };
}).apply(Blog.Business);
(function() {
    this.form_OnLoad = function(context) {
        Blog.Business.registerType(context);
    };
    this.onType_Change = function(context) {
        Blog.Business.registerType(context);
    };
}).apply(Blog.Form);

Developer Notes

  • To register event on save, we use formContext.data.entity.addOnSave(event).
  • To prevent save, we use context.getEventArgs().preventDefault().

Here is the result:

If you check the log console. When the second time we click save on the form, you will see that the previous message (case 1) also prints again. It means that we registered both events (Event onSave_Validate3 and onSave_Validate2). If we keep changing the Type, our code will register the event based on how many times we change the Type. To avoid that, we need to do this:

var Blog = Blog || {};
Blog.Form = Blog.Form || {};
Blog.Business = Blog.Business || {};
var OPTIONS = {
    'CASE_1': 772060000,
    'CASE_2': 772060001,
    'CASE_3': 772060002
};
var events = events || {};
(function() {
    this.onSave_Validate1 = function(context) {
        console.log('case 1');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 1') > -1;
        if(valid) return;
        context.getEventArgs().preventDefault();
    };
    this.onSave_Validate2 = function(context) {
        console.log('case 2');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 2') > -1;
        if(valid) return;
        
        context.getEventArgs().preventDefault();
    };
    this.onSave_Validate3 = function(context) {
        console.log('case 3');
        var formContext = context.getFormContext();
        var description = formContext.getAttribute('cr0c0_description')
            .getValue() || '';
        var valid = description.indexOf('Case 3') > -1;
        if(valid) return;
        
        context.getEventArgs().preventDefault();
    };
    var eventMappings = {
        772060000: Blog.Business.onSave_Validate1,
        772060001: Blog.Business.onSave_Validate2,
        772060002: Blog.Business.onSave_Validate3
    };
    this.registerType = function(context){
        var formContext = context.getFormContext();
        var type = formContext.getAttribute('cr0c0_type').getValue();
        if(!type) return;
        for(var i in events){
            var event = events[i];
            formContext.data.entity.removeOnSave(event);
        }
        var selectedEvent = eventMappings[type];
        if(!selectedEvent) return;
        formContext.data.entity.addOnSave(selectedEvent);
        events[type] = selectedEvent;
    };
}).apply(Blog.Business);
(function() {
    this.form_OnLoad = function(context) {
        Blog.Business.registerType(context);
    };
    this.onType_Change = function(context) {
        Blog.Business.registerType(context);
    };
}).apply(Blog.Form);

The main changes in the code above are on the method registerType, we have obligation to call formContext.data.entity.removeOnSave(event) to remove unnecessary events. In the below picture, we can see case 3 and case 2 being called separately.

2 thoughts on “Dynamics CRM Model Driven Apps: How to use addOnSave

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.