Friday, April 16, 2021

How to design a custom grid using HTML Web Resource in Dynamic CRM

I came across a requirement where I was required to fetch data from outside dynamic crm using third party API and display related data in a sub-grid.

The sub-grid should have a look and feel close to dynamic crm sub-grid. So here it is what we came up with.


Will try to explain our implementation in 3 steps.

  1. HTML – to prepare the table skeleton.
  2. CSS – to apply formatting.
  3. JavaScript – to dynamically add row to the table based on data fetched.

1)   HTML – to prepare the table skeleton.

Some of the elements are highlighted and are self-explanatory.

<body onload="heloptyact.onload()">

<div style="position:absolute; top:0; left:0; right:0">

    <table id="tblDataList">

        <tbody>

            <tr>

                <th style="width:5%;text-align:center">Sr.</th>

                <th style="width:30%">Activity Name</th>

                <th style="width:42%">

                    Deliverables

                </th>

                <th style="width:8%;text-align:center">

                    Milestone

                </th>

                <th style="width:8%;text-align:center">

                    Value

                </th>

                <th style="width:7%">

                    <input class="helBtn" type="button" id="add" value="Add Activity" onclick="addNewActivity()">

                </th>

            </tr>

        </tbody>

        <tbody id="tblDataListbody"></tbody>

    </table>

</div>

</body>


2) CSS – to apply formatting.


<style>

    #tblDataList {

        font-family: 'Segoe UI', Helvetica, sans-serif;

        border-collapse: collapse;

        width: 100%;

        border: 1px solid #d6d6d6;

    }

 

    #tblDataListbody td {

        border-top: 1px solid #ddd;

        border-bottom: 1px solid #ddd;

        padding: 14px;

        font-size: 13px;

    }

 

    #tblDataList th {

        text-align: left;

        background-color: #F3F3F3;

        color: #505050;

        border-top: 1px solid #d6d6d6;

        border-bottom: 1px solid #d6d6d6;

        padding: 4px 8px 4px 8px;

        font-size: 12px;

        font-family: 'Segoe UI Semibold', Helvetica, sans-serif;

    }

 

    #tblDataList tr:nth-child(even) {

        background-color: white;

    }

 

    #tblDataList tr:hover {

        background-color: #F8FAFC;

    }

 

 

   .helBtn {

        padding: 6px 18px;

        font-size: 14px;

        font-weight: 600;

        font-family: 'Segoe UI';

        text-align: center;

        cursor: pointer;

        outline: none;

        color: white;

        background-color: #4dc6ff;

        border: none;

        border-radius: 8px;

        box-shadow: 0 2px #999;

    }

 

   .helBtn:active {

        background-color: #007ab3;

        box-shadow: 0 1px #666;

        transform: translateY(1px);

    }

 

   .helBtn:hover {

        background-color: #009de6;

    }

 

   .lbl {

        ​​​​​​​font-family: 'Segoe UI', Helvetica, sans-serif;

        font-size: 14px;

        width: 100%;

        text-align: center;

        color: red;

    }


        .helBtnGrey {

        padding: 6px 18px;

        font-size: 12px;

        font-weight: 500;

        font-family: 'Segoe UI';

        text-align: center;

        cursor: pointer;

        outline: none;

        color: black;

        background-color: #F0F0F0    ;

        border: none;

        border-radius: 8px;

        box-shadow: 0 2px #999;

        }


        .helBtnGrey:active {

            background-color: #D3D3D3;

            box-shadow: 0 1px #666;

            transform: translateY(1px);

        }


        .helBtnGrey:hover {

            background-color: #DCDCDC;

        }



</style>

3)   JavaScript – to dynamically add row to the table based on data fetched.

To simplify the demonstration, I fetched the data from within dynamic Crm using Xrm.WebApi and creating a table dynamically.

Here is a code which generate table row dynamically. Refer to the comments for more details.


bindOppActivity: function () 

{

    document.getElementById('tblDataListbody').innerHTML = '';

    var selClause = "?$select=hel_srno,hel_name,hel_milestone,hel_deliverablesvalue,hel_helixorgactivityname,hel_details,hel_opportunityactivitiesid,_hel_opportunityid_value";

    var filClause = "&$filter=_hel_opportunityid_value eq " + heloptyact.optyId;

    var ordClause = "&$orderby=hel_srno asc,hel_name asc";

 

window.parent.Xrm.WebApi.online.retrieveMultipleRecords("hel_opportunityactivities", selClause + filClause + ordClause).then(

function success(results)

{

    for (var i = 0; i < results.entities.length; i++) {

 

        var hel_deliverablesvalue_formatted = results.entities[i]["hel_deliverablesvalue@OData.Community.Display.V1.FormattedValue"];

        var hel_srno = results.entities[i]["hel_srno"];

        var hel_helixorgactivityname = results.entities[i]["hel_helixorgactivityname"];

        var hel_milestone_formatted = results.entities[i]["hel_milestone@OData.Community.Display.V1.FormattedValue"];

        var hel_name = results.entities[i]["hel_name"];

        var hel_primarykeyid = results.entities[i]["hel_opportunityactivitiesid"];

 

 

        var table = document.getElementById("tblDataListbody");

        var rowCount = table.rows.length;

        var row = table.insertRow(rowCount);

 

        row.insertCell(0).innerHTML = hel_srno;

        row.cells[0].setAttribute("style", "text-align:center");

 

        row.insertCell(1).innerHTML = hel_helixorgactivityname;

 

        // Creating a hyperlink to open record

        row.insertCell(2).innerHTML = '<a  href="#" \

                                        onclick="heloptyact.openOptyActivityRecord(\'' + hel_primarykeyid + '\')">' + hel_name + '</a>'

 

        row.insertCell(3).innerHTML = (hel_milestone_formatted == null) ? "" : hel_milestone_formatted;

        row.cells[3].setAttribute("style", "text-align:center");

 

        row.insertCell(4).innerHTML = (hel_deliverablesvalue_formatted == null) ? "" : hel_deliverablesvalue_formatted;

        row.cells[4].setAttribute("style", "text-align:right");

 

        // For Deleting the record, we are using a Delete icon web-resource and calling a method on it click event

        row.insertCell(5).innerHTML = '<input width="16px" height="17px" type="image" \

                                        src = "/WebResources/hel_/image/icon/delete/recyclebin.png" \

                                        value = "Delete" \

                                        onClick = "heloptyact.deleteOpportunityActivity(this, \'' + hel_primarykeyid + '\')" > ';

        row.cells[5].setAttribute("style", "text-align:right");

    }

},

function (error) {

    window.parent.Xrm.Utility.alertDialog(error.message);

}

);

 


deleteOpportunityActivity: function (obj, id) {

    window.parent.Xrm.WebApi.online.deleteRecord("hel_opportunityactivities", id).then(

        function success(result) {

            bindOppActivity();

 

        },

        function (error) {

            window.parent.Xrm.Utility.alertDialog(error.message);

        }

    );

},

 

 

openOptyActivityRecord: function (recordId) {

 

    var entityFormOptions = {};

    entityFormOptions["entityName"] = "hel_opportunityactivities";

    entityFormOptions["entityId"] = recordId;

    entityFormOptions["openInNewWindow"] = true;

 

    // Open the form.

    window.parent.Xrm.Navigation.openForm(entityFormOptions).then(

        function (success) {

            console.log(success);

        },

        function (error) {

            console.log(error);

        });

}

No comments: