Dynamics 365 provides un-customizable functionality out of the box such as the Close Opportunity functionality. If you want to customize or recreate this functionality, it has been time-consuming to replicate the pop-up… until now. Introducing Alert.js 3.0, the stylish Dynamics 365 solution to help you create your aesthetically pleasing pop-ups.
Alert.js is a product created by Magnetism Solutions to create nice, simplistic alerts that replicate the Dynamics 365 UI. We use this for many of our clients to quickly create tailored popups for their purposes. Documentation for Alert.js can be found here.
This blog is an insight on how to use Alert.js and to showcase its capabilities with minimal code.
You can download a trial version of Alert.js here or you can purchase a full license for Alert.js here. After this you will have to import the managed solution into your Dynamics 365 instance and reference the Alert.js file in your form or ribbon.
You simply add Alert.js to the form as shown below, just like any other web resource:
To add it in the ribbon you simply navigate to the ribbon work bench and reference it as shown below:
This is how you reference it and use it in other JavaScript files. Ensure that it sits above the function your button will execute.
Below is the code for the pop up, validation and sending the request to close the opportunity. Use this as you want and modify to fit your needs!
// Called from ribbon button, passing through first primary record ID function showCloseAsWon(opportunityId) { var alertButtons = [ // Keep the alert open to allow for validation of required fields new Alert.Button("OK", function (responses) { closeOpportunityAsWon(responses, opportunityId); }, true, true), new Alert.Button("CANCEL") ]; // Create the options for the alert var alertOptions = { title: "Close Opportunity", message: "Provide the following information about why this opportunity is being closed", height: 490, width: 450, id: "closeOpportunity", buttons: alertButtons }; // Create the options for each of the fields. You can add in custom HTML to the label var statusOptions = { id: "statuscode", label: "Status Reason" + "<span style='color:red'>*</span>", value: 3, // Default value options: [{ text: "Won", value: 3 }] }; var actualRevenueOptions = { id: "actualrevenue", label: "Actual Revenue" + "<span style='color:red'>*</span>", value: 0.0, type: "number" }; // Specify additional HTML attributes to add to the field var actualRevenueExtra = { step: "0.01" }; var closedDateOptions = { id: "closeddate", label: "Closed Date" + "<span style='color:red'>*</span>", value: new Date(), // Default to today type: "date" }; var competitorOptions = { id: "competitor", label: "Competitor", entityTypes: ["competitor"] }; var descriptionOptions = { id: "description", label: "Description" }; // Create all the fields with their specified options and attributes var fields = [ new Alert.OptionSet(statusOptions), new Alert.Input(actualRevenueOptions, actualRevenueExtra), new Alert.Input(closedDateOptions), new Alert.Lookup(competitorOptions), new Alert.MultiLine(descriptionOptions) ]; new Alert(alertOptions).showPrompt(fields); } // This is the callback for the OK button function closeOpportunityAsWon(promptResponse, opportunityId) { // promptResponse is an array, containing the entered values, e.g.: // 0: { id: "statuscode", value: 0 } // 1: { id: "actualrevenue", value: null } // 2: { id: "closeddate", value: null } // 3: { id: "competitor", value: null } // 4: { id: "description", value: null } // Get the values from the prompt responses var status = promptResponse.filter(a => a.id == "statuscode")[0].value; var actualRevenue = promptResponse.filter(a => a.id == "actualrevenue")[0].value; var closedDate = promptResponse.filter(a => a.id == "closeddate")[0].value; var competitor = promptResponse.filter(a => a.id == "competitor")[0].value; var description = promptResponse.filter(a => a.id == "description")[0].value; // Check if any of the required fields are not entered, then display an error if (status == null || actualRevenue == null || closedDate == null) { var requiredFields = []; if (status == null) { requiredFields.push("Status Code"); } if (actualRevenue == null) { requiredFields.push("Actual Revenue"); } if (closedDate == null) { requiredFields.push("Closed Date"); } var options = { title: "Validation Error", message: "The following fields are required to close the opportunity: " + requiredFields.join(", "), icon: "ERROR", id: "errorAlert" }; new Alert(options).show(); } else { // Close the main alert once all required fields are validated new Alert({ id: "closeOpportunity" }).hide(); // Call the WebApi to win the opportunity // Use the example by Microsoft found here to make a request similar to this: var opportunityClose = { "opportunityid@odata.bind": "/opportunities(" + cleanIdField(opportunityId) + ")", "description": description, "subject": "Subject here...", "actualrevenue": actualRevenue, "actualend": closedDate } var winOpportunityReq = { OpportunityClose: opportunityClose, Status: 3, // Won getMetadata: function () { return { boundParameter: null, parameterTypes: { "OpportunityClose": { "typeName": "mscrm.opportunityclose", "structuralProperty": 5 // Entity Type }, "Status": { "typeName": "Edm.Int32", "structuralProperty": 1 // Primitive Type } }, operationType: 0, // Action operationName: "WinOpportunity", } } }; Xrm.WebApi.online.execute(winOpportunityReq).then( function (result) { if (result.ok) { console.log("Status: %s %s", result.status, result.statusText); // Perform other operations as required } }, function (error) { console.log(error.message); // Handle error conditions }); } } // Strip off the curly braces for WebApi requests function cleanIdField(id) { id = id.replace("{", ""); id = id.replace("}", ""); return id; }
With the custom popup that tells you a required field is missing:
Alert.js is a simple and easy to use solution to replicate popups by Microsoft, this is one example of millions that you could create. I suggest you download the trial and let it work its magic!