Angularjs Grid Pro is a complete data grid for enterprise applications for angularjs framework - has all the features you ever need from a data grid.


It borrows all functionality of ParamQuery pro ( which is written in javascript/jQuery ) and is encapsulated in a directive for seamless integration with angularjs framework. For you as a developer, jQuery knowledge is optional and is not necessary for implementation of angularjs grid.


Next few sections would guide you to implement this grid with Angularjs framework.

 

Getting Started:

First of all include the additional dependencies in this order ( after the files mentioned in the include files section for ParamQuery grid):

  1. angular.min.js which can be downloaded from https://angularjs.org or point it to CDN: http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular.min.js
  2. ng.pqgrid.min.js which contains the module and directive of pqgrid for Angularjs.

Add the pq.grid module to our main module.

    angular.module('myApp', ['pq.grid'])

Define the grid options as model properties by adding it to $scope variable in our controller.

    controller('myCtrl', function($scope){
        $scope.gridModel = {
            width: "80%",
            height: 400,
            ...
        };
    });

We pass on the gridModel as options attribute to pq-grid directive in our HTML view.

<div ng-controller="myCtrl">
...
    <pq-grid options="gridModel" ></pq-grid>
...
</div>

When grid is initialized, it gets a new scope prototypically inherited from its parent scope and the grid instance is added as a property to new scope as $scope.grid which comes handy when we need to access grid api from any bindings or directives ( which have child scopes protypically inherited from grid's scope ) within in the grid. And vice versa, the scope of the grid can be obtained from grid instance as grid.$scope which is convenient when we need to access grid scope inside event handlers.

Controller As:

Dot notation or defining model variables as properties of objects is recommended over adding them directly to $scope to avoid problems with setting model variable values from child scopes that prototypically inherit from parent scopes. controllerAs offers a much cleaner solution by offering this variable inside the controller so that the model variables can be declared as properties of this variable.

Controller:

    controller('myCtrl', function(){
        var vm = this;
        vm.gridModel = {
            width: "80%",
            height: 400,
            ...
        };
    });

View:

<div ng-controller="myCtrl as vm">
...
    <pq-grid options="vm.gridModel" ></pq-grid>
...
</div>

Toolbar binding:

For toolbar binding, we set gridModel.ngModel.compileToolbar = true and add angularjs directives or expressions in gridModel.toolbar.items[].type or gridModel.toolbar.items[].attr properties.

Toolbar gets the grid scope.

ngModel: {compileToolbar: true},
toolbar: {
    items: [
        {
            type: 'select',
            label: 'Select number of frozen rows: ',
            attr: 'ng-model="vm.gridModel.freezeRows" ng-options="o as o for o in vm.options"'
        },
        { type: 'separator' },
        {
            type: 'checkbox',
            label: 'Exclude frozen rows while sorting',
            attr: 'ng-model="vm.sortAll"'
        }
    ]
}

Cell binding:

Every row in grid gets a new scope prototypically derived from the grid scope when either gridModel.ngModel.compileRows = true or there is a template property in any of the columns. The row scope has properties:

  • rd which is reference to the rowData of current row.
  • ri rowIndx of current row which is similar to $index in ng-repeat.
For cell binding, we add angularjs directives in column.template property. e.g.,

{
    title: "Company",
    dataIndx: "company",
    template: '<span ng-class="ri%2==0?\'bold_cls\':\'\'">{{rd.company}}</span>'
}

If we need column specific properties in the cell templates, then we use render callback and return template which has access to column specific properties e.g., colIndx, column, dataIndx through ui argument inside the render callback. Note that it's required to add compileRows: true to ngModel in this case.

{ title: "", align: 'center', editable: false,
    render: function( ui ){
        var width = ui.column.outerWidth, ci = ui.colIndx
        return '<button class="btn-primary btn" ng-click="vm.showMe(ri,rd,'+width+','+ci+')">Click Me</button>';
    }
}

Header cell binding:

Header of the grid is compiled with grid scope when gridModel.ngModel.compileHeader = true. For header cells binding, we add angularjs expressions in column.title property. e.g.,

{ title: "No of clicks: {{vm.ri}}", dataIndx: "company" }

If we need column specific properties, then we use callback variant of column.title which has access to column specific properties e.g., colIndx, column, dataIndx through ui argument.

{ align: 'center', editable: false, dataIndx: 'rank', sortable: false,
    title: function( ui ){
        return '<button class="btn-primary btn" ng-click="vm.showMe('+ui.column.outerWidth+')">Click Me</button>';
    }
},

Events binding:

Events of the grid can be subscribed to in 2 ways:

  1. Add inline event handlers as property of gridModel e.g.,

    //inline property of gridModel.
    beforeSort: function( evt, ui ){
    
    }

    The context this in this case is grid which emits the event.

  2. Specify event handler as attribute in directive and add event handler method in the controller e.g., to listen to beforeSort event.

    <!--Note: the event attribute name starts with on- and put in lower case separated by hyphens -->
    <pq-grid on-before-sort="vm.beforeSort(evt, ui, grid)" options="vm.gridModel" ></pq-grid>
    //add event handler in the controller.
    vm.beforeSort = function( evt, ui, grid ){
    
    }

    The context this in this case is controller. So to get access to grid that emits the event, we can pass grid as one of the parameters to the event. This way of event binding also ensures that at least one $root $digest takes place after call to event handler.

Whole data binding:

Two way data binding of the whole data in grid can be obtained by:

  • Assign data to an object property inside the controller i.e.,

    vm.myData = data;

    where vm is an object defined on the $scope or vm points to this variable inside the controller when used with controllerAs syntax.

  • Assign model property name along with object name in dot notation as a string e.g., 'vm.myData' to gridModel.dataModel.data.

    gridModel.dataModel = { data: 'vm.myData' };

Observe gridModel changes: rebind

When gridModel properties change after initialization of grid, rebind attribute indicates grid to observe for those changes and refresh view according to the changes. rebind is passed to grid directive as an attribute whose value is the name of a single or more options ( separated by empty space in latter case ) whose values are observed by the grid during every $digest. Note that it is supported only for scalar properties currently.

<pq-grid rebind="height selectionModel.type"></pq-grid>

rebind has special value all which indicate that the grid should observe all scalar properties of the gridModel.

<pq-grid rebind="all"></pq-grid>

Custom Editors:

Custom editors are implemented by writing a directive and assigning it to column.editorTemplate Directives are assigned a scope prototypically derived from grid scope and has following properties.

  • ui: An object having same ui properties received in callbacks of column.editor
Link function in the directives are supposed to attach editor object to scope having same properties as column.editor.

angular.module('pq.grid')
.directive('autocomplete', function(){
    return{
        restrict: 'AE',
        link: function($scope, $ele, attr){

            $scope.editor = {
                type: 'textbox',
                init: function(ui){
                    var $inp = ui.$cell.find("input");

                    //initialize the editor
                    $inp.autocomplete({
                        source: attr.options? $scope.$eval(attr.options): attr.url,
                        minLength: 0
                    }).focus(function () {
                        //open the autocomplete upon focus
                        $(this).autocomplete("search", "");
                    });
                }
            };
        }
    };
})

Custom Validations:

Custom validations are implemented by writing a directive and assigning it to column.validations[].template Directives are assigned a scope prototypically derived from grid scope and has following properties.

Link function in the directives are supposed to attach return property to scope signifying validation success or fail.

angular.module('pq.grid')
//validation directives.
.directive('inList',function(){
    return{
        restrict: 'E',
        link: function($scope, $ele, $attr){
            var ui = $scope.ui, value = ui.value, list = $scope.$eval($attr.options);
            if ( list.indexOf( value ) == -1) {
                ui.msg = value + " not found in list";
                $scope.return = false;
            }
        }
    };
})

Row detail or nested grids:

Row details are implemented by writing a directive and assigning it to detailTemplate. Directive is assigned a scope prototypically derived from grid scope and has following properties.

  • ui: An object having same ui properties received by detailModel.init callback.
Link function in the directive is supposed to compile detail template and return it.

angular.module('pq.grid')
.directive('pqGridDetail', ["$compile", function($compile){
    function link($scope, $ele){
        $scope.rd = $scope.ui.rowData;
        $ele = $compile( $ele )( $scope );

        //link should return the compiled $ele.
        return $ele;
    }
    return{
        template: function($ele, attr){
            //template requires one root element.
            return "<div>" + $("#"+attr.templateId).html() + "</div>";
        },
        terminal: true,
        restrict: 'AE',
        replace: true,
        link: link
    };
}]);

Copyright @ 2016-2022 Paramvir Dhindsa (http://paramquery.com)