65.9K
CodeProject is changing. Read more.
Home

Binding CDS Data using Knockout (More Tips)

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0 vote)

Sep 28, 2020

CPOL

1 min read

viewsIcon

3330

A couple of questions answered about binding CDS data using Knockout and a few more tips shared

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.