Category: Blog
Close Opportunity in D365 CE with Alert.js 2.1
There is an article on Magnetism about how to use Alert.js 3.0 to mimic an opportunity close dialog. This is an example of how to use the open-source Alert.js 2.0 to mimic the opportunity close function. Alert.js 3.0 is $1200 and I definitely recommend it if you have the budget, but if not, you can still use 2.0 to do achieve similar functionality
So without further chit chat, here is what you do.
- Download and install Alert.js 2.1 on your CRM instance.
- Put the Opportunity entity in a solution without any sub-components.
- Create a JavaScript web resource and call it OpportunityClose.js or whatever you want to call it.
- Put the code listed below in the OpportunityClose.js
- Download and open Ribbon Workbench in XrmToolBox or your CRM instance.
- Add a button as seen in Image 1.
- Add a command as seen in Image 2.
- Create an Enable Rule and add it to the command as seen in Image 3.



// Called from ribbon button, passing through first primary record ID function showCloseAsWon(firstPrimaryItemId, primaryControl) { var context = primaryControl.context; var pid = firstPrimaryItemId.replace( /[{}]/g, '' ); var title = "Close Opportunity"; debugger; //Build Status Reason Option Set values var options = ""; var req = new XMLHttpRequest(); req.open("GET", context.getClientUrl() + "/api/data/v9.1/stringmaps?$select=attributevalue,value&$filter=attributename eq 'statuscode' and objecttypecode eq 'opportunity'", false); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("Prefer", "odata.include-annotations=\"*\""); req.onreadystatechange = function() { if (this.readyState === 4) { req.onreadystatechange = null; if (this.status === 200) { var results = JSON.parse(this.response); for (var i = 0; i < results.value.length; i++) { var attributevalue = results.value[i]["attributevalue"]; var value = results.value[i]["value"]; var opt = "<option "+"id='" + value +"' value='"+ attributevalue.toString() +"'>"+ value +"</option>"; options = options.concat(opt); } } else { options = "<option value='5'>Lost</option>"; } } }; req.send(); var style = "<style>" + ".header { padding-top: 10px;}" + "p { font-size: 14px; }" + ".alert-label { line-height: 22px; margin-top: 8px; } " + ".alert-textarea { width: 76%; height: 160px; border:1px solid #AAA; padding: 2%; } " + ".alert-select { padding: 4px 8px; width: 60%; } " + ".alert-button { padding: 10px 20px; font-size: 14px; background-color: white; border: 1px solid #AAA; margin: 10px 10px 0 0; min-width: 100px; } " + ".alert-button:hover { background-color: #EEE; } " + ".alert-button:focus { background-color: #DDD; } " + "</style>"; var subtitle = "<div class='header'>" + "<p><strong>Provide the following information about why this opportunity is being closed.</strong></p>" + "</div>"; var status = "<div class='container'>" + "<div id='stdiv'><p class='alert-label'>Status</p>" + "<div><select class='alert-select' name='status' id='st' onchange='javascript: var s=1==this.value?document.querySelector("#srdiv").style.display=\"none\":document.querySelector(\"#srdiv\").style.display=\"inherit\";' onfocusout='javascript: statusValue = this.value;'>" + "<option id='Lost' value='2'>Lost</option>" + "<option id='Won' value='1'>Won</option>" + "</select></div></div>" + "<input type='hidden' value=" + pid + " id='op'></input>"; var reason1 = "<div id='srdiv'><p class='alert-label'>Status Reason</p>" + "<div><select class='alert-select' name='selLoseStatus' id='sr' onfocus='javascript: reasonValue = this.value;' onfocusout='javascript: reasonValue = this.value;'>"; var reason2 = "</select></div></div>"; var description = "<div id='dsdiv'><p class='alert-label'>Description</p>" + "<div><textarea class='alert-textarea' id='ds' onfocus='javascript: descValue = this.value;' onfocusout='javascript: descValue = this.value;' placeholder='Enter description here'></textarea></div>" + "</div>" + "<div id='alert-message'></div></div>"; var close1 = "<button onclick=\"javascript: "; var clop = "var context,st=document.querySelector('#st').value,sr=1==st?-1:document.querySelector('#sr').value,ds=document.querySelector('#ds').value,id=document.querySelector('#op').value,op=1==st?'Win':'Lose',opportunityclose={'opportunityid@odata.bind':'/opportunities('+id+')',description:ds},parameters={OpportunityClose:opportunityclose,Status:sr};context='function'==typeof GetGlobalContext?GetGlobalContext():Xrm.Page.context;var req=new XMLHttpRequest;req.open('POST',context.getClientUrl()+'/api/data/v9.1/'+op+'Opportunity',!1),req.setRequestHeader('OData-MaxVersion','4.0'),req.setRequestHeader('OData-Version','4.0'),req.setRequestHeader('Accept','application/json'),req.setRequestHeader('Content-Type','application/json; charset=utf-8'),req.onreadystatechange=function(){if(4===this.readyState)if(req.onreadystatechange=null,204===this.status)Xrm.Page.data.refresh(!0);else{var e=this.responseText;console.log(e)}},req.send(JSON.stringify(parameters));" + "Alert.hide();"; var close2 = "\" value='Close' class='alert-button' name='Close Opportunity' aria-label='Close Opportunity'>Close Opportunity</button>"; var notnow = "<button onclick='javascript: Alert.hide()' class='alert-button' name='Not Now' aria-label='Not Now'>Not Now</button>"; var message = style + subtitle + status + reason1 + options + reason2 + description + notnow + close1 + clop + close2; var buttons = [ ] var width = 480; var height = 540; var baseUrl = context.getClientUrl(); var preventCancel = false; var icon = "INFO"; var padding = 30; Alert.show(title, message, buttons, icon, width, height, baseUrl, preventCancel, padding); }
Web Development In 2020 – A Practical Guide – Traversy Media
How to Replicate Close Opportunity in Dynamics 365 using Alert.js | Magnetism Solutions | NZ (Auckland, Wellington, Christchurch & Dunedin)
Preview the new schedule board in Dynamics 365 Field Service | Microsoft Docs
What’s new in D365 2020 Wave 1 release for front-end developers – Andrew Butenko’s Blog
Using the New Modal Dialog to Open Forms in Dynamics 365 using Xrm.Navigation.navigateTo – Carl de Souza
Dynamics 365 for the .NET Developer – Andrew Campey – YouTube
Icon packs to match D365 CE UCI entities
Icon packs to match D365 CE UCI entities on flaticon.com
- News
- HR
- IoT
- Social Websites
- Airport Symbols
- Minimal Interface
- Contacts
- Locations and Navigation
- Multimedia Devices
- Speedometers
- Minimal SEO
- Real Estate
- Web Interface
There are ton more on flaticon.com which you can pick from. Modify the SVG to be a shade of #999999 to get a good match on color, and pick from lineal designs aren’t too concentrated.
Send data from WordPress (and other PHP sites) to Dynamics CRM/CE
On of the easiest ways to capture data from WordPress and other PHP based sites and send it to Dynamics CRM/365CE has to be the PHP Toolkit created by AlexaCRM. They have two tools available for use for free.
WordPress Plugin for Dynamics CRM
If you have a WordPress site, connecting to Dynamics CRM/D365CE is a 10-minute exercise. Install the WordPress plugin on your site, create a form in Dynamics with a distinct name, add a page in WordPress and put the following shortcode snippet in the code editor.
[msdyncrm_twig]
{% form entity="contact" name="Contact Card" mode="create" %}{% endform %}
[/msdyncrm_twig]
In the code above, replace the “Contact Card” with the name of your form in CRM. That’s it!
Other PHP based sites
If you have any other PHP based site like Joomla or Drupal, you can use the PHP Toolkit to connect Dynamics CRM/365CE to your site. Put the toolkit libraries into a libraries folder and you can call them from any page since it’s PHP. AlexaCRM has made examples available on their GitHub page.