Experiencing a challenge with D365/JavaScript integration: Seeking assistance in adding an OnSave event to prevent users from saving a form

I have successfully created a JavaScript OnSave event that scans a grid of a "Sales Quota Distribution" entity on an "Opportunity" entity form, looking for duplicates in the "Resource" field. When a duplicate is found, a warning message is displayed. Everything is functioning as expected, but I am now trying to enhance the OnSave event to prevent the user from saving the form if there are no duplicate resources. How can I achieve this?

Here is the current code snippet:

function GetTotalResourceCount(executionContext) {
    console.log("function started");
    var execContext = executionContext;
    var formContext = executionContext.getFormContext();
    var resourceyescount = 0;
    try {
        var gridCtx = formContext._gridControl;
        var grid = gridCtx.getGrid();
        var allRows = grid.getRows();
        //get rows - use the getControl method and pass the grid name.
        //var gridContext = formContext.getControl("s_qd");
        //        if (formContext.getGrid().getTotalRecordCount() == 0) {
        //           setTimeout(function () { GetTotalResourceCount(execContext); }, 2000);
        //           return;
        //       }
        var duplicatesFound = 0;
        //loop through rows and get the attribute collection
        allRows.forEach(function (row, rowIndex) {
            var thisRow = row.getData().entity;
            var thisRowId = thisRow.getId();
var thisResource = "";
var thisResourceName = "";
var thisResourceID = "";
            console.log("this row id=" + thisRowId);
            var thisAttributeColl = row.getData().entity.attributes;
            thisAttributeColl.forEach(function (thisAttribute, attrIndex) {
                var msg = "";
                if (thisAttribute.getName() == "new_resource") {
                    thisResource = thisAttribute.getValue();
thisResourceID = thisResource[0].id;
thisResourceName = thisResource[0].name;
                }
            });

            // Loop through every row and find one with
            // thatresource == thisResource &&
            // thatrow ID != thisRowId
            var allRows2 = formContext.getGrid().getRows();
            //loop through rows and get the attribute collection
            allRows2.forEach(function (row, rowIndex) {
                var thatRow = row.getData().entity;
                var thatRowId = thatRow.getId();
                var thatAttributeColl = row.getData().entity.attributes;
var thatResource = "";
var thatResourceName = "";
var thatResourceID = "";
                thatAttributeColl.forEach(function (thatAttribute, attrIndex) {
                    if (thatAttribute.getName() == "new_resource") {
                        thatResource = thatAttribute.getValue();
thatResourceID = thatResource[0].id;
thatResourceName = thatResource[0].name;
                        if (thatResourceID == thisResourceID && thatRowId != thisRowId) {
                            duplicatesFound++;
                            var msg = "Duplicate resource " + thatResource;
                        }
                    }
                });
            });
        });

        if (duplicatesFound > 0) {
            console.log("duplicate found");
            Xrm.Utility.alertDialog("WARNING: There are duplicate resources in the Sales Quota Distribution grid.");
        }
    } catch (err) {
        console.log('Error occurred :' + err)
    }
}

Any assistance on how to achieve this additional functionality would be highly appreciated. Thank you! https://i.sstatic.net/A1U4q.png

Answer №1

Another option is to utilize the setNotification method on a control. By doing so, you can prevent the form from being saved.

According to the documentation:

Applying an error notification on a control will halt the saving of the form.

For example:

formContext.getControl('your_attributename').setNotification('This message will appear', 'optional id');

Answer №2

If you're looking to handle the save event gracefully in your application, you can utilize the preventDefault method from the Client API reference. Here are a few examples to guide you:

Javascript – Prevent Save

Cancelling save event based on the result of async operation

Below is some code snippet that demonstrates how to prevent the save event by adding just two lines:

Assuming your function

GetTotalResourceCount(executionContext)
is triggered on the onSave Event.

function GetTotalResourceCount(executionContext) {
    // Function started
    var execContext = executionContext;
    var formContext = executionContext.getFormContext();
    var resourceyescount = 0;
    try {
        // Accessing grid control
        var gridCtx = formContext._gridControl;
        var grid = gridCtx.getGrid();
        var allRows = grid.getRows();
        var duplicatesFound = 0;

        // Loop through rows and check for duplicate resources
        allRows.forEach(function (row, rowIndex) {
            // Get attributes of current row
            var thisRow = row.getData().entity;
            var thisRowId = thisRow.getId();
            var thisResource = "";
            var thisResourceName = "";
            var thisResourceID = "";
            
            // Process attributes of current row
            var thisAttributeColl = row.getData().entity.attributes;
            thisAttributeColl.forEach(function (thisAttribute, attrIndex) {
                if (thisAttribute.getName() == "new_resource") {
                    thisResource = thisAttribute.getValue();
                    thisResourceID = thisResource[0].id;
                    thisResourceName = thisResource[0].name;
                }
            });

            // Compare with other rows to find duplicates
            var allRows2 = formContext.getGrid().getRows();
            allRows2.forEach(function (row, rowIndex) {
                var thatRow = row.getData().entity;
                var thatRowId = thatRow.getId();
                var thatAttributeColl = row.getData().entity.attributes;
                var thatResource = "";
                var thatResourceName = "";
                var thatResourceID = "";
                thatAttributeColl.forEach(function (thatAttribute, attrIndex) {
                    if (thatAttribute.getName() == "new_resource") {
                        thatResource = thatAttribute.getValue();
                        thatResourceID = thatResource[0].id;
                        thatResourceName = thatResource[0].name;
                        if (thatResourceID == thisResourceID && thatRowId != thisRowId) {
                            duplicatesFound++;
                        }
                    }
                });
            });
        });

        // Display alert for duplicates and prevent default save event
        if (duplicatesFound > 0) {
            console.log("Duplicate found");
            Xrm.Utility.alertDialog("WARNING: There are duplicate resources in the Sales Quota Distribution grid.");
            var saveEvent = executionContext.getEventArgs();
            saveEvent.preventDefault();
        }
    } catch (err) {
        console.log('Error occurred: ' + err);
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Arranging a variety of array objects based on unique identifiers

Previously, I successfully combined two arrays into one and sorted them by the created_at property using the sort() method. let result = [...item.messages, ...item.chat_messages] result.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) it ...

Error: The function $scope.apply is invalid and cannot be executed

I am attempting to display the contacts list after retrieving it using rdflib.js. The data is being loaded and stored in the list within the scope. However, I am running into an issue where the $scope is not updating, and it appears that I may be calling ...

Having trouble identifying the data variable. Uncaught ReferenceError: edu_id has not been defined

How can I successfully pass the edu_id from an AJAX request to my Laravel controller? Utilizing anchor tags <a href="javascript:void(0);" onclick="showEditEducation(some_specific_id);" title=""><i class="la la-pencil"></i></a> Im ...

Implementing image rendering functionality in Vue.js

So here's what's going on: I developed a horror movie bucket list app for my bootcamp final project. The minimum viable product received positive feedback, and I obtained my certification. However, now that I've graduated, I want to enhance ...

Is there a way to dynamically change the helperText of a Material UI TextField using its current value through code?

I'm currently attempting to dynamically change the helperText of a Material UI TextField based on the value entered into the field. Below is my current implementation: const defaultScores = { STR: 10, DEX: 10, CON: 10, INT: 10, WIS: 10, CH ...

What is the process for including points to the scoreboard?

I am currently working on a simple JavaScript game as my very first project. The game involves clicking a button to generate random numbers for both the user and computer, and the winner is determined by the larger number. I have set up a scoreboard to kee ...

What makes Next.js API so special?

As I delve into Next.js, I find myself grappling with the concept of server-side rendering (SSR) and API usage. When is it appropriate to utilize the API folder within pages versus deploying my own server along with a database? Would there be any conflic ...

Issue with updating overall expenditure functionality

I'm currently in the process of developing a straightforward shopping cart with the help of simpleCart.js. Up until now, I've managed to successfully showcase items, add them to the basket, and proceed to checkout. However, my next challenge inv ...

A guide on trimming content with v-if in Vue.js

Recently, I attempted to trim the response value within a Vue condition. I require this functionality to apply the condition when the value is null or empty. <li v-if="item[0].otrodl4.trim() == ''" class="progress-step"> ...

Is there a way to target a sibling element of another element by using its identifier in Cypress?

My current task involves clicking a checkbox within a list of table rows. The only way I can think of reaching this level is by targeting the span tag along with its corresponding name. cy.get('tr > td > span').contains('newCypressTes ...

Fetching locales asynchronously in nuxt.js using i18n and axios: A step-by-step guide

I am facing an issue with getting the location asynchronously. Whenever I try to implement my code, it results in a "Maximum call stack size exceeded" error. How can I resolve this issue? Previously, I attempted to retrieve the location by using the axios ...

The error message 'Blob is undefined' pops up when trying to use react-media-recorder in an Astro project

I'm currently working on a project that involves Astro and React components, and I'm attempting to integrate react-media-recorder. The code I have is quite simple, just a React component placed within an Astro page: import { useReactMediaRecorde ...

Please ensure all three of the last checkboxes are ticked before finalizing submission

Here is the list of checkboxes for my PHP form. I am trying to figure out how to write a script that will only allow the form to be submitted if the last three checkboxes are checked. I have tried looking at similar questions but haven't found the sol ...

How to Retrieve a Remote File in Angular using $http.get() with OAuth Authentication

I have a unique situation where my users possess private files that require downloads by authenticated users. The server I am using initially downloads a file from S3 utilizing its own set of S3 app_id and secret_token credentials. Once the file has been d ...

Reliable Dropdown Navigation Bars

Once I have successfully implemented three dynamic drop down menus using the combination of jQuery, AJAX, and PHP, the next challenge arises. After populating the dropdown menus based on user selections (e.g., selecting a value in the first dropdown menu ...

What is the process for sending an InMemoryUploadedFile to my S3 storage?

My upload form is quite simple and includes an image as a FileField: def post(request): if request.user.is_authenticated(): form_post = PostForm(request.POST or None, request.FILES or None) if form_post.is_valid(): inst ...

Ways to efficiently display elements in a grid in real-time

Attempting to design a layout where each row consists of 3 cards using Bootstrap's Grid layout for responsiveness. The challenge lies in the fact that the card data is stored in JSON format, and the length of the JSON Object array may vary, leading t ...

Incorporate a collection of product titles along with their short forms in JavaScript/jQuery

Seeking guidance as a newcomer to JS. I have encountered the need for two different views in an application I am working on - one displaying full product names and the other showing only their abbreviations. Instead of hard-coding this information, I wish ...

What is the best method for checking if a template has successfully rendered in an Iron:Router route during a mocha test?

I am working on testing if a specific template has rendered in my meteor app for a particular route. My current setup involves iron:router, practicalmeteor:mocha, and I'm using Blaze for rendering. There are a couple of challenges that I am facing: ...

Modifying script variables using the Chrome console

There is a button on the website that looks like this: https://i.sstatic.net/G7PBF.png Clicking on this button triggers the following script: https://i.sstatic.net/rIdLW.png function count(){ let downloadTimer; var timeleft = 30; downloadTimer = setInte ...