web
You’re offline. This is a read only version of the page.
close
Skip to main content
Community site session details

Community site session details

Session Id :
Microsoft Dynamics 365 | Integration, Dataverse...
Unanswered

Infinite loop OnSave javascript

(0) ShareShare
ReportReport
Posted on by 2,909

I have the below code that checks two things on the Field Service Bookable Resource Booking Form which is a combination of two forms which is why I have to do a web API call and also works in Offline mode.

This is a continuation of this post in Field Service however I feel it's more generic javascript issue now.

The code is from Andrew Butenko in this post which I modified slightly.

The code basically checks OnSave:

  1.  If booking status is complete
    1. If Incident Type is Breakdown check Fault Category not Null
    2. All Service Tasks are complete

It all works except when I try to Save a Booking with Incident Type Breakdown and Fault Category is not null, it just gets an infinite loop.

In the debugger it runs through hits this: 

  • isValidationNeeded = false;

It then re-enters the OnSave function and exits when it hits

  • if (!isValidationNeeded) {
            isValidationNeeded = true;
            return;
        }
It is then when it just seems to loop through this section.
I expected that as executionContext.getEventArgs().preventDefault(); is further down it should just exit and Save.
When it is the service Tasks and WO is not Incident Type Breakdown it works perfectly and gracefully exits.
Could the new Async Save setting be effecting this?

 

var BookingForm = (function () {

    var SaveMode = {
        Save: 1,
        SaveAndClose: 2,
        SaveAndNew: 59,
        Autosave: 70
    };

    //this is variable that shows if validation was successfully passed or not
    var isValidationNeeded = true;
    
    function OnSave(executionContext) {
        //so if there are several save handlers and one of previous already called preventDefault
        //there is no need to do any validations anymore
        if (executionContext.getEventArgs().isDefaultPrevented()) {
            return;
        }

        //getting save mode from event
        var saveMode = executionContext.getEventArgs().getSaveMode();

        //if savemode is not one of listed - just quit the execution and let the record to be saved
        if (saveMode !== SaveMode.Save &&
            saveMode !== SaveMode.SaveAndClose &&
            saveMode !== SaveMode.SaveAndNew &&
            saveMode !== SaveMode.Autosave) {
            return;
        }

        //so if validation was successfully passed - flag is reset
        //and code just leaves the form alone and allows changes to be saved
        if (!isValidationNeeded) {
            isValidationNeeded = true;
            return;
        }

        //getting of the form context from execution context object
        var formContext = executionContext.getFormContext();

        
        // Get WO Guid
        var wo = formContext.getAttribute('msdyn_workorder').getValue()[0].id; // returns GUID

        
        // Fetch will return any service tasks that are incomplete and related to WO. Using FetchXml allows us to use same querey in online and offline mode
        let fetchXml = "?fetchXml=";


    var tasks = 0;
    if (formContext.getAttribute("bookingstatus") != null && formContext.getAttribute("bookingstatus") != undefined) 
    {
        var status = formContext.getAttribute("bookingstatus").getValue()[0].name;
        if(status == "Completed")
        {
            var faultcategory = formContext.ui.tabs.get(3).sections.get(0).controls.get(0).getAttribute("eye_faultcategory").getValue();
            var incidenttype = formContext.ui.tabs.get(3).sections.get(0).controls.get(0).getAttribute("msdyn_primaryincidenttype").getValue()[0].name;
            var workordertype = formContext.ui.tabs.get(3).sections.get(0).controls.get(0).getAttribute("msdyn_workordertype").getValue()[0].name;

            if (status == "Completed" && (incidenttype == "Breakdown" || incidenttype == "Trapped Passenger" || incidenttype == "Repairs") && faultcategory == null) {
                // executionContext.getEventArgs().preventDefault(); // Stop the Save
                formContext.ui.tabs.get(3).sections.get(0).controls.get(0).getAttribute("eye_faultcategory").setRequiredLevel("required");
            }
            //preventing of the save operation before async operation is started
            executionContext.getEventArgs().preventDefault();
            Xrm.WebApi.retrieveMultipleRecords("msdyn_workorderservicetask", fetchXml).then(    
                        function success(results) {
                            tasks = results.entities.length;
                            if(results.entities.length !== 0)
                            {
                                console.log(`In retrieve call ${tasks}`);
                                formContext.ui.setFormNotification("All WO service tasks need to be complete", "ERROR", "DurationErrorMessageId");
                            }
                            else
                            {
                                //othervice validation flag is set to "Passed"
                                isValidationNeeded = false;
                                //and save event is called again and notification cleared
                                formContext.ui.clearFormNotification("DurationErrorMessageId");
                                if (saveMode === SaveMode.Save || saveMode === SaveMode.Autosave) {
                                    formContext.data.entity.save();
                                } else if (saveMode === SaveMode.SaveAndClose) {
                                    formContext.data.entity.save("saveandclose");
                                } else {
                                    formContext.data.entity.save("saveandnew");
                                }
                            }
                        },
                        function (error) {
                            //if something went wrong - error message is shown to user
                            Xrm.Navigation.openAlertDialog({ text: error.message });
                        }
                     );
           } else {
                // Booking status not complete so clear notifications and allow save
                formContext.ui.clearFormNotification("DurationErrorMessageId");
                return;
           }
                }
             }
            
            return {
                OnSave: OnSave
            };
        } // BookingForm Function
    ) // BookingForm
();

I have the same question (0)
  • antc Profile Picture
    2,909 on at
    RE: Infinite loop OnSave javascript

    Also submitted in general forum.

    I spoke to soon all works except when I try to Save a Booking with Incident Type Breakdown and Fault Category is not null, it just gets an infinite loop.

    In the debugger it runs through hits this: 

    • isValidationNeeded = false;

    It then re-enters the OnSave function and exits when it hits

    • if (!isValidationNeeded) {
                isValidationNeeded = true;
                return;
            }
    It is then when it just seems to loop through this section.
    I expected that as executionContext.getEventArgs().preventDefault(); is further down it should just exit and Save.
    When it is the service Tasks and WO is not Incident Type Breakdown it works perfectly and gracefully exits.
    Could the new Async Save setting be effecting this?
  • Community Member Profile Picture
    on at
    RE: Infinite loop OnSave javascript

    Hi antc, 

    If Context.getEventArgs().preventDefaultOnError()  method is called, then the Async OnSave event will still wait for all the promises to settle, but the save will not occur. This means the logic in it will still execute successcallback and errorcallback.

    New Async OnSave Event in Dynamics 365 CRM | Microsoft Dynamics 365 CRM Tips and Tricks (inogic.com)

  • antc Profile Picture
    2,909 on at
    RE: Infinite loop OnSave javascript

    Hi Leah

    Thanks for the reply I have spent a bit of time on this but still not getting it. I don't understand why if it's the WO service tasks it works however if it's the fault category it doesn't.

    The console has warnings "UciError: Cannot save due to PreventDefault encountered." which I get however as the formContext.data.entity.save(); is hit shouldn't that then just exit and save like it does for the service task check? Why does it loop back?

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Abhilash Warrier – Community Spotlight

We are honored to recognize Abhilash Warrier as our Community Spotlight honoree for…

Leaderboard > Microsoft Dynamics 365 | Integration, Dataverse, and general topics

#1
Sahan Hasitha Profile Picture

Sahan Hasitha 231

#2
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 83 Super User 2025 Season 2

#3
BillurSamdancioglu Profile Picture

BillurSamdancioglu 68 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans