How to call custom actions in your CRM from JavaScript
Customer relationship management (CRM) software helps companies store information about customers and track client-company interactions throughout the relationship.
Out of the box, most products can create, update, delete, assign and “SetState” messages. With some programming knowledge, you can write custom business logic with plugins or workflows or JavaScript custom actions.
For example, if an entity record needs approval (and that’s not an out-of-the-box option), you could create a custom action to move the record through an approval workflow. And you could add a button for users to click to initiate the process.
With custom actions, you can create any message you need. Then you attach plugin code to the message to perform operations without restriction.
Here’s an example that gives you the basic formula to create whatever you need:
How to create a custom action from JavaScipt
Let’s say you want a button that, when clicked:
- Calls a custom action
- Runs a plugin
- Calls a web service to get the temperature for the account’s zip code
- Returns the information
- Displays it in a notification on the form
The result might look like this:
In this case, a plugin does the real work, and JavaScript handles the form notifications and calls the action. The process looks like this:
Two JavaScript libraries make this custom action easier: Notify.js and Process.js. Libraries help call custom actions, without lengthy XML Http requests. They simplify that work down to a function call with only a couple of parameters and provide callbacks for success and errors.
Components of the custom action
In this example, the components needed were:
- A custom action
- JavaScript web resource (to call the custom action)
- A custom ribbon button (to call the JavaScript)
- A plugin to call the weather web service
- notify.js library
- process.js library
The custom action was fairly simple in this example because it only required a couple of parameters. The custom action bypassed the parameters to and from the plugin and allowed us to register the plugin step against the custom action message.
Components of the JavaScript web resources
JavaScript manages the notifications and calls the custom action. It will validate the presence of a zip code, load the input parameters, and then call the custom action.
When the action completes, it will call the success callback and display the information on the form as a notification. While the action is working, there will be a notification on the form letting the user know something is happening.
Example code:
function CallAction() {
//Verify that we have a Zip Code
if (Xrm.Page.getAttribute("address1_postalcode").getValue() == null) {
Notify.add("Zip code is missing", "ERROR", "nozip", null, 5);
}
else {
//Display the notification that we are working on something
Notify.add("Processing Action...", "LOADING", "myProcessing");
//Load the input parameters
var inputParams = [
{ key: "ParamPostalCode", type: Process.Type.String, value: Xrm.Page.getAttribute("address1_postalcode").getValue() },
{ key: "Target", type: Process.Type.EntityReference, value: new Process.EntityReference(Xrm.Page.data.entity.getEntityName(), Xrm.Page.data.entity.getId()) }
];
//Call the custom action
Process.callAction("wipfli_GetWeather", inputParams, successCallback, errorCallback);
}
}
function successCallback(params) {
//Get the result from the plugin and display the information in a notification
var outputParamOne = params["OutputParamOne"];
Notify.add(outputParamOne, "INFO", "mySuccess", [{ type: "button", text: "Clear", callback: function () { Notify.remove("mySuccess"); } }]);
Notify.remove("myProcessing");
}
function errorCallback(error, trace) {
Notify.remove("myProcessing");
Notify.add("Error: " + error, "ERROR", "myError");
}
Components of the custom ribbon button
The ribbon button only has to call the “CallAction” function from the JavaScript. Use the Ribbon Workbench for CRM to create a custom button that points to a web resource and initiates the CallAction function.
Components of the plugin
The plugin will read the input parameters and then call the weather web service. Based on the response, it will format the information and return it in the output parameter.
Remember to register the plugin using the Plugin Registration Tool in the CRM SDK. Then, register a step on the GetWeather message.
Example code:
protected override void ExecuteCrmPlugin(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
//Get the parameters from the Action call
EntityReference accountRef = (EntityReference)localContext.PluginExecutionContext.InputParameters["Target"];
string paramPostalCode = (string)localContext.PluginExecutionContext.InputParameters["ParamPostalCode"];
string webAddress = @"http://api.openweathermap.org/data/2.5/weather?zip=" + paramPostalCode + ",us&mode=xml&units=imperial&appid={your specific APPID}";
string output = "";
try
{
using (WebClient client = new WebClient())
{
Byte[] responseBytes = client.DownloadData(webAddress);
String response = Encoding.UTF8.GetString(responseBytes);
localContext.TracingService.Trace("Response is: " + response);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(response);
XmlNodeList current = xmlDoc.SelectNodes("/current");
foreach (XmlNode xn in current)
{
output = xn["city"].Attributes["name"].Value + " is " + Math.Round(Double.Parse(xn["temperature"].Attributes["value"].Value), 0) + " " + xn["temperature"].Attributes["unit"].Value;
}
localContext.TracingService.Trace("OUTPUT IS: " + output);
}
}
catch (WebException exception)
{
string str = string.Empty;
if (exception.Response != null)
{
using (StreamReader reader =
new StreamReader(exception.Response.GetResponseStream()))
{
str = reader.ReadToEnd();
}
exception.Response.Close();
}
if (exception.Status == WebExceptionStatus.Timeout)
{
throw new InvalidPluginExecutionException(
"The timeout elapsed while attempting to issue the request.", exception);
}
throw new InvalidPluginExecutionException(String.Format(CultureInfo.InvariantCulture,
"A Web exception occurred while attempting to issue the request. {0}: {1}",
exception.Message, str), exception);
}
localContext.PluginExecutionContext.OutputParameters["OutputParamOne"] = output;
}
Additional libraries
The Notifiy.js and Process.js libraries need to be loaded on the form. To do this, include them as
form libraries in Form Properties.
With all the components in place, clicking the button should produce a weather notification.
How Wipfli can help
Custom actions can be used for nearly any purpose you can imagine. What problems do you need to solve? The Wipfli CRM team can help you select, implement or customize a CRM to solve nearly any business challenge. Contact us today to learn more or read more about our digital services.
Related content: