Using jqgrid with popover from angular ui bootstrap

I should start with the words that I’m not angular developer and I have never used popover before. So the code which I post below could be not good enough from the angular point of view. Nevertheless it works and it do what you need. Having working code you can improve it probably.

The demo display popover on click on the custom button, which stay opened. Additionally alert message will be displayed from the JavaScript function bound using ng-click:

enter image description here

It uses the following HTML markup

<body ng-app="myApp" ng-controller="MyController">
    <ng-jq-grid config="config" data="data"></ng-jq-grid>
</body>

and the following JavaScript code which contains from three parts. In the first one do the standard thing

var myApp = angular.module("myApp", ["ui.bootstrap"]);

it’s important just don’t forget to include "ui.bootstrap" module required for popover.

In the second part one use myApp.directive with $compile as parameter, which are used for compiling the grid twice: once before placing an empty <table> on the HTML page (in <ng-jq-grid>...</ng-jq-grid>) and once more inside of loadComplete:

myApp.directive("ngJqGrid", function ($compile) {
    return {
        restrict: "E",
        scope: {
            config: "=",
            data: "="
        },
        link: function (scope, element, attrs) {
            var $grid;

            scope.$watch("config", function (newValue) {

                element.children().empty();
                $grid = angular.element("<table></table>");
                element.append($compile($grid)(scope));

                element.append($grid);
                angular.extend(newValue, {
                    autoencode: true,
                    iconSet: "fontAwesome",
                    cmTemplate: { autoResizable: true }, 
                    autoResizing: { compact: true },
                    autoresizeOnLoad: true,
                    loadComplete: function () {
                        $compile(this)(scope);
                    }
                });

                angular.element($grid)
                    .jqGrid(newValue)
                    .jqGrid("navGrid")
                    .jqGrid("filterToolbar");
            });
            scope.$watch("data", function (newValue, oldValue) {
                $grid.jqGrid("clearGridData");
                $grid.jqGrid("setGridParam", {data: newValue});
                $grid.trigger("reloadGrid");
            });
        }
    };
});

I used free jqGrid 4.8 in the demo, so one don’t need to generate and id for the <table> element. If you have to use an old version of jqGrid then you should replace the line

$grid = angular.element("<table></table>");

to something like

$grid = angular.element("<table id='" + $.jgrid.jqID() + "'></table>");

The options autoResizing and autoresizeOnLoad are specific for free jqGrid and follows setting of the width of the columns based on the width of the data in the column. The options are described in the readme and in the wiki.

In the last part of the code I use myApp.controller to initialize $scope.config and $scope.data with initial data.

myApp.controller("MyController", function ($scope) {
    $scope.config = {
        myClick: function (rowid) {
            alert("Test buton is clicked on rowid=" + rowid);
        },
        colNames: ["Client", "", "Date", "Closed", "Shipped via", "Amount", "Tax", "Total", "Notes"],
        colModel: [
            { name: "name", align: "center", width: 65, editrules: {required: true},
                searchoptions: { sopt: ["tcn", "tnc", "teq", "tne", "tbw", "tbn", "tew", "ten"] }},
            { name: "myLink", align: "center",
                formatter: function (cellvalue, options, rowObject) {
                    return "<button class="btn btn-primary" popover-placement="top" popover="" +
                         rowObject.note + "" ng-click='config.myClick(" + options.rowId + ")'>Test</button>";
                }},
            { name: "invdate", width: 125, align: "center", sorttype: "date",
                formatter: "date", formatoptions: { newformat: "d-M-Y" },
                editoptions: { dataInit: initDateEdit },
                searchoptions: { sopt: ["eq", "ne", "lt", "le", "gt", "ge"], dataInit: initDateSearch } },
            { name: "closed", width: 70, template: "booleanCheckboxFa" },
            { name: "ship_via", width: 105, align: "center", formatter: "select",
                edittype: "select", editoptions: { value: "FE:FedEx;TN:TNT;IN:Intim", defaultValue: "IN" },
                stype: "select", searchoptions: { sopt: ["eq", "ne"], value: ":Any;FE:FedEx;TN:TNT;IN:IN" } },
            { name: "amount", width: 75, template: "number" },
            { name: "tax", width: 52, template: "number", hidden: true },
            { name: "total", width: 60, template: "number" },
            { name: "note", width: 60, sortable: false, edittype: "textarea" }
        ]
    };
    $scope.data = [
        { id: "11",  invdate: "2007-10-01", name: "test",   note: "note",   amount: 0, tax: 0, closed: true,  ship_via: "TN", total: 0 },
        { id: "21",  invdate: "2007-10-02", name: "test2",  note: "note2",  amount: 351.75, tax: 23.45, closed: false, ship_via: "FE", total: 375.2 },
        { id: "31",  invdate: "2007-09-01", name: "test3",  note: "note3",  amount: 400, tax: 30, closed: false, ship_via: "FE", total: 430 },
        { id: "41",  invdate: "2007-10-04", name: "test4",  note: "note4",  amount: 200, tax: 10, closed: true,  ship_via: "TN", total: 210 },
        { id: "51",  invdate: "2007-10-31", name: "test5",  note: "note5",  amount: 300, tax: 20, closed: false, ship_via: "FE", total: 320 },
        { id: "61",  invdate: "2007-09-06", name: "test6",  note: "note6",  amount: 400, tax: 30, closed: false, ship_via: "FE", total: 430 },
        { id: "71",  invdate: "2007-10-04", name: "test7",  note: "note7",  amount: 200, tax: 10, closed: true,  ship_via: "TN", total: 210 },
        { id: "81",  invdate: "2007-10-03", name: "test8",  note: "note8",  amount: 300, tax: 20, closed: false, ship_via: "FE", total: 320 },
        { id: "91",  invdate: "2007-09-01", name: "test9",  note: "note9",  amount: 400, tax: 30, closed: false, ship_via: "TN", total: 430 },
        { id: "101", invdate: "2007-09-08", name: "test10", note: "note10", amount: 500, tax: 30, closed: true,  ship_via: "TN", total: 530 },
        { id: "111", invdate: "2007-09-08", name: "test10", note: "note11", amount: 500, tax: 30, closed: false, ship_via: "FE", total: 530 },
        { id: "121", invdate: "2007-09-10", name: "test12", note: "note12", amount: 500, tax: 30, closed: false, ship_via: "FE", total: 530 }
    ];
});

The custom formatter looks like

formatter: function (cellvalue, options, rowObject) {
    return "<button class="btn btn-primary" popover-placement="top" popover="" +
         rowObject.note + "" ng-click='config.myClick(" +
         options.rowId + ")'>Test</button>";
}

I hope that I commented the most important parts of the code.

Leave a Comment