Client API - lookupObjects
New Client API
Lately, I'm exploring Client API that came with Dynamics 365 v9.0 and I can tell you that it has a bunch of cool stuff that is not used that frequently by the Dynamics community.
My top 3 namespaces are:
- Xrm.Navigation (alert and confirm dialogs)
- Xrm.Panel (side panel that makes some integrations look seamless)
- Xrm.Utility (a bunch of new things)
In this post, I will show you one use case of a feature that made me so happy, because I always had a struggle when I tried to make look & feel of Dynamics lookup fields in my custom web resources.
This feature is of course Xrm.Utility.lookupObjects
The struggle
Every time I wanted to use lookup input field in my custom web resources I had the same problem. Which kind of control to use to present the lookup input field?
Sometimes I went the autocomplete route, but I had problems with validating the wrong values (user searched something and left the value that was not found in the textbox) or I went the dropdown route which was not that good option because it lacks a search option, but it forces user to choose the right value.
Solution
New API call Xrm.Utility.lookupObjects solved my problem and saved me some (BIG) amount of time. That new function allows you to open lookup browser with entities that you want to search for and returns the object containing record GUID, entity type of the record and a name of the record.
Example
My goal was to create a simple example that will display what you can do with the new function.
The goal is to create a popup window on a contact entity that will allow you to pick some system user in the popup and initiate a task entity creation that will have picked user as the owner of the task and the current contact in the regarding field.
I hope that example is simple enough to show you everything that is relevant while using this function.
Before we start making the solution I wanted to note that I really like Alert.js solution that makes popup windows in Dynamics so much easier. It has some downsides of course, but for the most challenges, it does a great job.
First, we need to make a simple HTML web resource that will be popped up. HTML code is shown in the code box below.
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="../js/lookupSelector.js"></script>
<link rel="stylesheet" type="text/css" href="../css/lookupSelector.css.css">
</head>
<body>
<div>
<span class="label-text">User </span><input class="lookup-text" type="text" id="name" placeholder="Search for systemuser">
<input type="hidden" id="id">
<input type="hidden" id="entityType">
</div>
<div id="button-box">
<button onclick="createTask()">Create task</button>
</div>
<script type="text/javascript">init();</script>
</body>
</html>
After we have created the HTML file we need to create a JS file that will invoke the actual logic.
function openLookupDialog() {
var crmWindow = parent.Alert.getCrmWindow();
var lookupParameters = {};
lookupParameters.entityTypes = ["systemuser"];
lookupParameters.defaultEntityType = "systemuser";
lookupParameters.allowMultiSelect = false;
crmWindow.Xrm.Utility.lookupObjects(lookupParameters).then(populateLookupValue, null);
}
function populateLookupValue(entity) {
var name = entity[0].name;
var id = entity[0].id;
var entityType = entity[0].typename;
$("#name").val(name);
$("#id").val(id);
$("#entityType").val(entityType);
debugger;
}
function createTask() {
var userId = $("#id").val().replace("{", "").replace("}", "");
var contactId = parent.Alert.getCrmWindow().Xrm.Page.data.entity.getId().replace("{", "").replace("}", "");
var contactName = parent.Alert.getCrmWindow().Xrm.Page.getAttribute("fullname").getValue()
var entity = {};
entity["regardingobjectid_contact@odata.bind"] = "/contacts(" + contactId + ")";
entity["ownerid@odata.bind"] = "/systemusers(" + userId + ")";
entity.subject = "Call " + contactName;
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: parent.Alert.getCrmWindow().Xrm.Page.context.getClientUrl() + "/api/data/v9.0/tasks",
data: JSON.stringify(entity),
beforeSend: function(XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("OData-MaxVersion", "4.0");
XMLHttpRequest.setRequestHeader("OData-Version", "4.0");
XMLHttpRequest.setRequestHeader("Accept", "application/json");
},
async: true,
success: function(data, textStatus, xhr) {
parent.Alert.hide();
},
error: function(xhr, textStatus, errorThrown) {
Xrm.Utility.alertDialog(textStatus + " " + errorThrown);
}
});
}
function init() {
$("#name").focus(openLookupDialog);
}
There are 2 functions that are interesting here:
- openLookupDialog
- populateLookupValue
Function openLookupDialog is called when the user focuses the input element with name ID and it opens the lookup dialog.
There are few parameters that we need to pass to the openLookupDialog function.
Parameters:
- entityTypes - list of strings containing entity names
- defaultEntityType - string value of default entity
- allowMultiSelect - bool value that controls multiple select
This is a minimum set of parameters that you need to pass to make this function work, but there are also other parameters that are mentioned in the official docs page.
The second function is populateLookupValue function that is called as success callback in the previous function. The parameter that is passed into this callback is a list of entities selected in the lookup dialog, but in our case, it returns only a single value because allowMultiSelect is set to false.
Each object inside that list has 3 values: id, name and typename which can be used in data operations after selection.
We use those values (or just a ID part) to create a task after valid record is selected.
Finally when we have the HTML and JS sorted we can add some CSS to get a Dynamics look and feel.
button {
color: #444444;
background-color: #FFFFFF;
height: 24px;
font-family: Segoe UI, Tahoma, Arial;
border: 1px solid #C6C6C6;
background-image: none;
margin-top: 10px;
width: auto;
min-width: 84px;
white-space: nowrap;
font-size: 12px;
line-height: 16px;
text-align: center;
cursor: pointer;
background-repeat: repeat-x;
padding-left: 10px;
padding-right: 10px;
margin-left: 8px;
}
button:hover {
background-color: #B1D6F0;
}
body {
margin: 0;
}
#button-box {
position: absolute;
right: 0;
bottom: 0;
}
.label-text {
float: left;
width: 20%;
color: #828181 !important;
font-size: 14px;
font-family: Segoe\000020UI, Tahoma, Arial;
border: none;
}
.lookup-text {
width: 80%;
color: #1160B7;
font-size: 14px;
font-family: Segoe\000020UI, Tahoma, Arial;
border: none;
}
.lookup-text:hover {
border: 1px gray solid;
}
After everything is done right we can test our code and see the result. The result is shown in the next 3 steps.
STEP 1
STEP 2
STEP 3
Conclusion
I hope that this example will help you when you will face the problem with using lookups in your custom web resources and as you can see it's not that complex to use the new lookupObjects function in your solutions.
I like this function a lot because it gives the users similar UX as they are used to while using Dynamics.