Salman Raza
Salman Raza

Reputation: 350

ng-click is not working with AngularJS and dataTables

I am using jQuery DataTable directive with angularJS which is working fine. The problem I am facing is adding javascript function to "TR" dynamically with "ng-click" which is not working. It seem's like dynamically added elements are not recognized by angular.

Can somebody help me out solving this problem.

Directive :

angular.module('ngdemo.directives', []).directive('myTable', function() {
    return function(scope, element, attrs) {

        // apply DataTable options, use defaults if none specified by user
        var options = {};
        if (attrs.myTable.length > 0) {
            options = scope.$eval(attrs.myTable);
        } else {
            options = {
                "bStateSave": true,
                "iCookieDuration": 2419200, /* 1 month */
                "bJQueryUI": true,
                "bPaginate": false,
                "bLengthChange": false,
                "bFilter": false,
                "bInfo": false,
                "bDestroy": true
            };
        }

        // Tell the dataTables plugin what columns to use
        // We can either derive them from the dom, or use setup from the controller           
        var explicitColumns = [];
        element.find('th').each(function(index, elem) {
            explicitColumns.push($(elem).text());
        });
        if (explicitColumns.length > 0) {
            options["aoColumns"] = explicitColumns;
        } else if (attrs.aoColumns) {
            options["aoColumns"] = scope.$eval(attrs.aoColumns);
        }

        // aoColumnDefs is dataTables way of providing fine control over column config
        if (attrs.aoColumnDefs) {
            options["aoColumnDefs"] = scope.$eval(attrs.aoColumnDefs);
        }

        if (attrs.fnRowCallback) {
            options["fnRowCallback"] = scope.$eval(attrs.fnRowCallback);
        }

        // apply the plugin
        var dataTable = element.dataTable(options);



        // watch for any changes to our data, rebuild the DataTable
        scope.$watch(attrs.aaData, function(value) {
            var val = value || null;
            if (val) {
                dataTable.fnClearTable();
                dataTable.fnAddData(scope.$eval(attrs.aaData));
            }
        });
    };
});

In My Controller:

app.controller('SourceCtrl', ['$scope', 'SharedFactory','$location','$compile', function ($scope, SharedFactory,$location,$compile) {
    $scope.columnDefs = [ 
         { 
             "mDataProp": "desc", 
             "aTargets":[0],
         },
         { "mDataProp": "name", "aTargets":[1] },
         { "mDataProp": "desc", "aTargets":[2] }
    ];

    $scope.overrideOptions = {
             "bServerSide": true,
             "iDisplayLength": 2,
             "sAjaxSource": "ajaxCall",
             "aaSorting": [[ 0, "desc" ]],
             "fnServerData": function ( sSource, aoData, fnCallback,oSettings ) {
                      var startIndex = SharedFactory.fnGetKey(aoData, "iDisplayStart");
                      var length = SharedFactory.fnGetKey(aoData, "iDisplayLength");
                      var sortAttr = 'sourceType';//fnGetKey(aoData,"iSortCol_0");
                      var sortDir = 'DESC';//fnGetKey(aoData,"sSortDir_0");
                      sSource="ajaxCall";
                      $.getJSON(sSource, function (aoData) { 
                          aoData.iTotalRecords = aoData.size;
                          aoData.iTotalDisplayRecords = aoData.size;
                          fnCallback(aoData);
                      });
            },
            "sAjaxDataProp": "aaData",
            "fnCreatedRow": function( nRow, aData, iDataIndex ) {
                $(nRow).attr('ng-click','selectRow()');
             }
     };

    $scope.selectRow = function() {
        alert("");
    };
}]);

Upvotes: 4

Views: 8181

Answers (1)

Alexander Kalinovski
Alexander Kalinovski

Reputation: 1409

Well, dynamically created stuff (especially jquery ui) doesn't know anything about angular. That's because angular make compilation of the nodes when processing. So there are few options there:

1) Before adding some dynamic content you can compile it. In this case angular can know about it and all feature like directives, binding etc. can work.

row.push($compile(content)($scope)[0].innerHTML);

In this sample we added compiled content to the row (cell). And the content can have any number of angular directives. But you should carefully pass on the correct scope to have the directives working as you expected.

Another way is just to deal with pure js. In this case you can just declare onclick handlers and inside of them make finding of the necessary scope and call the method on it:

angular.element('item').scope().handleClick(row);

And as the code is called from non-angular part you should wrap it into $scope.$apply:

$scope.handleClick = function(row) {
    $scope.$apply(function() {
        ... place handling logic here
    });
}

But I would better recommend to migrate to angular data grids (like ngGrid)

Upvotes: 4

Related Questions