The requirement

One of our clients uses Dynamics 365 Field Service to manage the planning of their inspectors. One of the requirements is that when a planner approves a Booking that is complete, they get a confirm dialog to prompt if they are sure the Booking is fully completed. This is necessary to prevent that there is no incomplete data being sent to their ERP system.

So, at first sight, this was going to be pretty easy to tackle. Just add some custom scripting for the OnChange handler of the Approved field and pop up a confirm dialog box with the native Dynamics 365 method Xrm.Navigation.openConfirmDialog().

if (typeof (Thrives) === "undefined") { Thrives = {}; }

Thrives.BookingManager = {

    /* Members */
    FormContext: null,

    /* Form Functions */

    ApprovedOnChange: function (executionContext) {
        this.FormContext = executionContext.getFormContext();
        this.BookingStatusApprovalCheck(this.FormContext);
    },

    /* Methods */
    BookingStatusApprovalCheck: function (formContext) {
        var confirmStrings = {
                    cancelButtonLabel: 'Cancel',
                    confirmButtonLabel: 'Confirm',
                    subtitle: 'Are you sure you want to approve this booking?',
                    text: 'This action can NOT be undone.',
                    title: 'Booking Approval'
                };

        Xrm.Navigation.openConfirmDialog(confirmStrings).then(
            function (success) {
                if (success.confirmed) {
                    formContext.data.entity.save();
                } else {
                    formContext.getAttribute("thr_approved").setValue(false);
                    formContext.getControl("thr_approved").setDisabled(false);
                }
            },
            function (error) {
                Xrm.Navigation.openAlertDialog({ text: error.message });
            }
        );    
    }
}

The test

So that’s that. Now let’s put it to the test!
Let’s open a Booking and try to approve it by switching the two-option field to Yes.

Dynamics 365 prevent autosave

Nice! It seems to be working fine.

Now, let’s assume that the planner forgot something and hits the Cancel button.

Dynamics 365 prevent autosave

The problem

Uh-oh.. It seems that while our planner was reading the dialog box, the auto save functionality of Dynamics 365 kicked in and incomplete data is sent to ERP. This of course with all of its consequences!

Let’s see what the Microsoft docs have to say on how we could prevent this auto save functionality.

With the native eventArgs.getSaveMode() method we can determine which type of saving is being executed and prevent it with the eventArgs.preventDefault() if necessary.

function preventAutoSave(executionContext) {
    var eventArgs = executionContext.getEventArgs();

    if (eventArgs.getSaveMode() == 70 || eventArgs.getSaveMode() == 2) {
        eventArgs.preventDefault();
    }
}

But, registering this function on the OnSave handler would result in the auto save always being disabled on the Booking form. And that’s also not what we are looking for. We only want to disable it while our confirm dialog is showing.

So how can we prevent auto save in dynamics 365 you ask?

To fix this, all i did was tweak the function mentioned in the docs a little bit and add an extra property to our BookingManager.

I named it “DisableAutoSave” and defaulted it to false. Now, we set it to true when we call our BookingStatusApprovalCheck method. While the confirm dialog is showing and the auto save kicks in, we simply check if our newly added property is true or false.

Thrives.BookingManager = {

    /* Members */
    FormContext: null,
    EventArgs: null,
    DisableAutoSave: false,

    /* Form Functions */
    ApprovedOnChange: function (executionContext) {
        this.FormContext = executionContext.getFormContext();
        this.BookingStatusApprovalCheck(this.FormContext);
    },
    FormOnSave: function (executionContext) {
        this.EventArgs = executionContext.getEventArgs();

        if (this.DisableAutoSave) {
            this.EventArgs.preventDefault();
        }
    },

    /* Methods */      
    ...
}

When the user clicks Confirm, we make sure the DisableAutoSave is set back to false and the data gets saved. On the other hand, when the Cancel button is clicked, we will also set DisableAutoSave to false but revert the Approved field to No and do not save the form.

Thrives.BookingManager = {

    /* Members */
    ...

    /* Form Functions */
    ...

    /* Methods */
    BookingStatusApprovalCheck: function (formContext) {
        var _this = this;
        this.DisableAutoSave = true;

        var confirmStrings = {
                    cancelButtonLabel: 'Cancel',
                    confirmButtonLabel: 'Confirm',
                    subtitle: 'Are you sure you want to approve this booking?',
                    text: 'This action can NOT be undone.',
                    title: 'Booking Approval'
                };               

        Xrm.Navigation.openConfirmDialog(confirmStrings).then(
            function (success) {
                if (success.confirmed) {
                    _this.DisableAutoSave = false;
                    formContext.data.entity.save();
                } else {
                    formContext.getAttribute("thr_approved").setValue(false);
                    formContext.getControl("thr_approved").setDisabled(false);
                }
            },
            function (error) {
                Xrm.Navigation.openAlertDialog({ text: error.message });
            }
        );    
    }
}