Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Binding CDS Data using Knockout (More Tips)

0.00/5 (No votes)
27 Sep 2020CPOL1 min read 3.3K  
A couple of questions answered about binding CDS data using Knockout and a few more tips shared
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.
Image 1

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:

Image 2

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)