In this post, I am answering a couple of questions about querying CDS entity data and displaying it in a model-driven app web resource, and also sharing a few more tips.
This post is the second in a series of querying CDS entity data and displaying it in a model-driven app web resource. A few days ago, I wrote first post in this series CDS Data Binding using Knockout. Here, I am answering a couple of questions and sharing a few more tips.
Though I have fetched data using WebApi and J-Query, any mechanism that returns object array will work. Yes, we can use FetchXml
for querying data too.
The second thing is we can query data from multiple related entities using expand oData
function. In this scenario, query returns cases with customer details. Customer can be an account or a contact:
var query = "/api/data/v9.1/incidents?$select=title&$expand=customerid_account($select=name),
customerid_contact($select=fullname)";
While doing data binding a few times, I got an error:
Cannot ready property ‘name’ of undefined
The reason was in data, few records don’t have customerid_account
(parent object was null
). To solve this, I have used if
binding (Knockout offer different bindings) which checks and only bind the data if the object is not null
.
<td>
<!--ko if:customerid_account -->
<span id="accountNamee" data-bind="text:customerid_account.name"> </span>
<!--/ko-->
</td>
Knockout ‘with
’ binding can also be used for this:
<td>
<!--ko with:customerid_contact -->
<span id="contactName" data-bind="text:fullname"></span>
<!--/ko-->
</td>
We can do few tricks by using if
and ifnot
(else
) bindings too. The query above is a perfect example, we either have customerid_account
or customerid_contact
, not both. My requirement was to display combined data from both fields as one:
Here is the complete sample code:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.js"
type="text/javascript"></script>
<script src="../../../ClientGlobalContext.js.aspx" type="text/javascript"></script>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
crossorigin="anonymous">
<script>
$(document).ready(function () {
var query = "/api/data/v9.1/incidents?
$select=title&$expand=customerid_account($select=name),
customerid_contact($select=fullname)";
var oDataUrl = top.Xrm.Page.context.getClientUrl() + query;
var _data = null;
$.getJSON(oDataUrl)
.done(function (data) {
if (data != undefined && data.value.length > 0) {
ko.applyBindings(new AppViewModel(data));
debugger;
}
})
.fail(function (error) {
debugger;
});
});
function AppViewModel(data) {
var self = this;
self.Results = ko.observableArray([]);
ko.utils.arrayForEach(data.value, function (d) {
self.Results.push(d);
});
}
</script>
</head>
<body>
<div style="overflow-x:auto;">
<h4 class="text-center">List of Cases</h4>
<table id="tblContainer"
class="table table-sm table-striped table-hover table-borderless">
<thead>
<th>Title</th>
<th>Account</th>
<th>Contact</th>
<th>Client</th>
</thead>
<tbody data-bind="foreach: Results">
<tr>
<td><span id="title" data-bind="text:title"></span></td>
<td>
<!--ko if:customerid_account -->
<span id="accountNamee" data-bind="text:customerid_account.name">
</span>
<!--/ko-->
</td>
<td>
<!--ko with:customerid_contact -->
<span id="contactName" data-bind="text:fullname"></span>
<!--/ko-->
</td>
<td>
<!--ko if:customerid_account -->
<span id="accountNamee" data-bind="text:customerid_account.name">
</span>
<!--/ko-->
<!--ko with:customerid_contact -->
<span id="contactName" data-bind="text:fullname"></span>
<!--/ko-->
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
I hope you find this useful.