4

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("");
    };
}]);
Vintesh
  • 1,657
  • 1
  • 24
  • 31
Salman Raza
  • 320
  • 1
  • 8
  • 23

1 Answers1

4

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)

Alexander Kalinovski
  • 1,409
  • 1
  • 13
  • 19
  • Thanks Alex that was really helpful. It actually solved my problem. Is there any problem to use datatable and not ngGrid ? – Salman Raza Mar 30 '14 at 06:46
  • No special problem with that. I just prefer to use clean angularjs stuff which is more flexible when integrating in your application. If you need you can use datatable (we used it too but then we decided to migrate to an angularjs grid directives). Another alternatives: ng-table, smart-table etc. – Alexander Kalinovski Mar 30 '14 at 06:54
  • Alex, I am using jQuery also with angular JS in my project. Such as toggle the class, hide show the divs. So is it a good approach to use jquery like this with angularJS ? – Salman Raza Mar 31 '14 at 10:47
  • All of this is supported in AngularJS. So instead of jquery you can use ng-show, ng-hide, ng-class, ng-style etc. But for some time you may still need to handle this manually (for ex. inside of the directives) but they are rare cases. – Alexander Kalinovski Mar 31 '14 at 12:50
  • This doesn't work for me. I'm trying to run a function when clicking on a link in the table. I have content = 'stuff' and from the render function for that column I return $compile(content)($scope)[0].outerHTML (innerHTML gives anything under the anchor). doStuff() is defined on the scope but does not get called. – crowmagnumb Aug 17 '15 at 22:08