Arter
Arter

Reputation: 2324

Angularjs datatables - rowCallback event

can someone help me with rowCallback. Problem is, I have a table, and you can click anywhere on table row for open info for clicked item. On first TD I set check box. But when I check checkbox, I don't want to open info. Here is image for better explanation enter image description here

my code

var vm = this;
    vm.selected = {};
    vm.selectAll = false;
    vm.toggleAll = toggleAll;
    vm.toggleOne = toggleOne;

    var titleHtml = '<input type="checkbox" ng-model="showCase.selectAll" ng-click="showCase.toggleAll(showCase.selectAll, showCase.selected)">';


    function getUserTokenFromLocalStorage(localStorage) {
        var authData = [];
        for (key in localStorage) {
            if (key == "ls.authorizationData") {
                authData = localStorage[key];
            }

        }

        var jsonObj = JSON.parse(authData);
        return jsonObj.token;
    };


    var vm = this;
    vm.message = '';
    vm.someClickHandler = someClickHandler;
    vm.dtOptions = DTOptionsBuilder.newOptions()
        .withOption('ajax', {
            // Either you specify the AjaxDataProp here
            // dataSrc: 'data',
            url: serviceBase + 'test',
            type: 'POST',
            headers: {
                'xtoken': 'Bearer ' + getUserTokenFromLocalStorage(localStorage)
            }
        })
        // or here
        .withDataProp('data')
        .withOption('processing', true)
        .withOption('serverSide', true)
        .withOption('rowCallback', rowCallback)
        .withOption('createdRow', function(row, data, dataIndex) {
            // Recompiling so we can bind Angular directive to the DT
            $compile(angular.element(row).contents())($scope);
        })
        .withOption('headerCallback', function(header) {
            if (!vm.headerCompiled) {
                // Use this headerCompiled field to only compile header once
                vm.headerCompiled = true;
                $compile(angular.element(header).contents())($scope);
            }
        })
        .withPaginationType('full_numbers')


    vm.dtColumns = vm.dtColumns = [
        DTColumnBuilder.newColumn(null).withTitle(titleHtml).notSortable()
        .renderWith(function(data, type, full, meta) {
            vm.selected[full.id] = false;
            return '<input type="checkbox" ng-model="showCase.selected[' + data.id + ']" ng-click="showCase.toggleOne(showCase.selected)">';
        }), //don't change state when click on this TD, only check checkbox.
        DTColumnBuilder.newColumn('id').withTitle('ID'),
        DTColumnBuilder.newColumn('type').withTitle('Type'),
        DTColumnBuilder.newColumn('city').withTitle('City'),
        DTColumnBuilder.newColumn('country').withTitle('Country'),
        DTColumnBuilder.newColumn('last_report_dt').withTitle('Last report'),
        DTColumnBuilder.newColumn('hardware_version').withTitle('HW version'),
        DTColumnBuilder.newColumn('rpi_image_version').withTitle('Image version'),
        DTColumnBuilder.newColumn('software_version').withTitle('Code version'),
        DTColumnBuilder.newColumn('internal_note').withTitle('Internal note'),
        DTColumnBuilder.newColumn(null).withTitle('Info').notSortable()
        .renderWith(function(data, type, full, meta) {
            vm.selected[full.id] = false;
            return '<a class="btn btn-default" ng-href="info/' + data.id + '">Info</a>';
        }),
    ];

    function toggleAll(selectAll, selectedItems) {
        for (var id in selectedItems) {
            if (selectedItems.hasOwnProperty(id)) {
                selectedItems[id] = selectAll;
            }
        }
    }

    function toggleOne(selectedItems) {
        for (var id in selectedItems) {
            if (selectedItems.hasOwnProperty(id)) {
                if (!selectedItems[id]) {
                    vm.selectAll = false;
                    return;
                }
            }
        }
        vm.selectAll = true;
    }


    function someClickHandler(info) {
        vm.message = info.id;
        $location.path('info/' + info.id);

    }

    function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
        // Unbind first in order to avoid any duplicate handler (see https://github.com/l-lin/angular-datatables/issues/87)
        $('td', nRow).unbind('click');
        $('td', nRow).bind('click', function() {
            $scope.$apply(function() {
                vm.someClickHandler(aData);
            });
        });
        return nRow;
    }


}

Upvotes: 3

Views: 2780

Answers (1)

davidkonrad
davidkonrad

Reputation: 85518

Have had this issue myself. I think your approach is a little bit backwards. You declare the td click handler inside rowCallback, just to be able to pass the id. Instead I will recommend this :

  1. Add a no-click class to the first column to prevent click :

    DTColumnBuilder.newColumn(null).withTitle(titleHtml).notSortable()
      .withClass('no-click')
      .renderWith(function(data, type, full, meta) {
         vm.selected[full.id] = false;
         return '<input type="checkbox" ng-model="showCase.selected[' + data.id + ']" ng-click="showCase.toggleOne(showCase.selected)">';
       }), 
    
  2. Change the rowCallback to do nothing but injecting the id as attribute to the row :

    function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
       $(nRow).attr('data-id', aData.id);
    }
    
  3. Create a delegated event handler on the td's to replace both the event handler inside rowCallback and your someClickHandler() :

    $('#tableid').on('click', 'tbody td:not(.no-click)', function() {
      var id = $(this).parent().attr('data-id');
      vm.message = id;
      $location.path('info/' + id);
    })
    

Upvotes: 3

Related Questions