Angular ngGrid select row on page load
Asked Answered
P

4

12

My question is an extension to thisquestion

Getting select rows from ng-grid?

plunker - http://plnkr.co/edit/DiDitL?p=preview

I need a row to be selected on page load and I need to avoid listening to 'ngGridEventData'

calling $scope.gridOptions.selectRow(2, true); in the controller body fails since the grid has not been loaded.

avoiding listening to ngGridEventData is due to the fact that I need the controller to listen to an event triggered before and based on that I need to select the nggrid row.

any ideas?

Purview answered 29/8, 2013 at 7:29 Comment(0)
B
4

For me, none of the answers worked (i use ng-grid v2.0.14).

The selected answer works probably because data is either not big or is not loaded through an ajax call otherwise you can't select a row "before" ngGridEventData since the event is fired when the rows are rendered and you can't select a row if it hasn't been rendered yet.
Should any of these conditions fail or the grid take too much time than usual to render then the selected answer will not work.

I have a scrollable grid with about 2000 rows, but I haven't any restriction on listening to the ngGridEventData so i worked on that, although it has a weird behavior for me: The ngGridEventData fires exactly 4 times for me, twice before data arrives from the ajax call and twice after.
I used this jquery plugin http://benalman.com/projects/jquery-throttle-debounce-plugin/ (it can be used even without jQuery though) to make it so that the function was called only once.

And since this is not enough, the "selectRow/selectItem" function triggers the "afterSelectionChange" event twice (the first time with the wrong row, for some reason). This is what i had to do to make sure that the event is fired only once and only for the correct row.

This is what happens for me:

  • ngGridEventData (no afterSelectionChange triggers, probably because there are no rendered rows)
  • ngGridEventData (no afterSelectionChange triggers, probably because there are no rendered rows)
  • Ajax call to retrieve data
  • delay (probably rendering)
  • ngGridEventData
  • afterSelectionChange x2
  • ngGridEventData
  • afterSelectionChange x2

So i had to use this:

  • debounce to make sure the function is called only once during the delay (the timeout is low since the calls are close to one another in pair, and the rendered rows checks makes sure the first call is not the one being used)
  • check that the rendered rows are > 0 to make sure the first 2 events are not triggered on slow sistems (or slow connection) where the delay and data load might take some time
  • Optionally use rowItem.selected to avoid another "bug" since the afterSelectionChange event fires twice even when selecting a row (once for the row being unselected and once for the selected row)
  • use the fireOnlyOnce variable to avoid calling twice the afterSelectionChange function.

Here's a sample code:

$scope.fireOnlyOnce=true;
$scope.gridOptions = {
    //Stuff
    afterSelectionChange: function (rowItem) {
        if($scope.fireOnlyOnce){
            if(rowItem.selected){
                //Do stuff
            }
        } else {
            $scope.fireOnlyOnce=true;
        }
    }
};

$scope.$on('ngGridEventData', jQuery.debounce(100, function (row, event){   
    var renderedRows = row['targetScope'].renderedRows.length;
    if(renderedRows>0){
        $scope.fireOnlyOnce=false;
        $timeout(function(){$scope.gridOptions.selectRow(2, true)});
    }
}));
Billow answered 10/4, 2015 at 14:30 Comment(0)
S
14

Add $timeout to your Controller and do this:

$timeout(function() { 
    $scope.gridOptions.selectRow(2, true); 
});

Example: http://plnkr.co/edit/hDv7b8?p=preview

Shaniceshanie answered 15/10, 2013 at 21:12 Comment(7)
Why does there have to be timeout? Any info about it in angular docs?Farm
I need to put because the?Farm
Oops. You need to put it in a $timeout because the grid is not initialized when the Controller is created. Another way would be to make a directive.Shaniceshanie
Ick. Code smell. If the timer is too short, it won't work as the grid will be undefined. If too long, the user will be waiting to see the selection take place. I have been googling and haven't found a good solution, but I certainly won't be using this one. Any professional presenting that for code review would not get a very god annual appraisal. The solution should be event driven, with the event signifying that the grid has been fully populated. Maybe in ng-grid v3?Gudrunguelderrose
@Gudrunguelderrose The "timer" will be neither too short nor too long. Note that no number parameter is being passed into the $timeout Angular service. This service returns a promise that gets resolved in the next digest loop after the delay. When the delay is 0 (which is the default) it means the very next digest loop. This is a typical use case for the $timeout service, and when in the body of a controller like this, it's specifically telling Angular "Let the controller and everything else finish bootstrapping, then resolve this promise (i.e. run this callback)".Justiceship
@Gudrunguelderrose It looks wrong, but it's not. That's frameworks for you, they all have their quirks. (I know it's been two years, so sorry about that, but you were being very opinionated! I would hope the people doing the code review would know their way around the framework they're using...)Justiceship
Thanks for the update (better late than never ;-). That project is abandoined, but I an just about to add a grid to a new project, so will thake this into account. Thanks (+1).Gudrunguelderrose
L
6

A solution without timeout can be found here: https://github.com/angular-ui/ui-grid/issues/2267 and here: Pre-Select rows on load with angular-ui-grid

$scope.gridOptions = {
...
                onRegisterApi : function (gridApi) {
                    $scope.gridApi = gridApi;
                    $scope.gridApi.grid.modifyRows($scope.gridOptions.data);
                    $scope.gridApi.selection.selectRow($scope.gridOptions.data[0]);
                }
            };

Apparently modifyRows requires v3.0.0-rc.22+

Lindsy answered 23/12, 2015 at 10:53 Comment(0)
B
4

For me, none of the answers worked (i use ng-grid v2.0.14).

The selected answer works probably because data is either not big or is not loaded through an ajax call otherwise you can't select a row "before" ngGridEventData since the event is fired when the rows are rendered and you can't select a row if it hasn't been rendered yet.
Should any of these conditions fail or the grid take too much time than usual to render then the selected answer will not work.

I have a scrollable grid with about 2000 rows, but I haven't any restriction on listening to the ngGridEventData so i worked on that, although it has a weird behavior for me: The ngGridEventData fires exactly 4 times for me, twice before data arrives from the ajax call and twice after.
I used this jquery plugin http://benalman.com/projects/jquery-throttle-debounce-plugin/ (it can be used even without jQuery though) to make it so that the function was called only once.

And since this is not enough, the "selectRow/selectItem" function triggers the "afterSelectionChange" event twice (the first time with the wrong row, for some reason). This is what i had to do to make sure that the event is fired only once and only for the correct row.

This is what happens for me:

  • ngGridEventData (no afterSelectionChange triggers, probably because there are no rendered rows)
  • ngGridEventData (no afterSelectionChange triggers, probably because there are no rendered rows)
  • Ajax call to retrieve data
  • delay (probably rendering)
  • ngGridEventData
  • afterSelectionChange x2
  • ngGridEventData
  • afterSelectionChange x2

So i had to use this:

  • debounce to make sure the function is called only once during the delay (the timeout is low since the calls are close to one another in pair, and the rendered rows checks makes sure the first call is not the one being used)
  • check that the rendered rows are > 0 to make sure the first 2 events are not triggered on slow sistems (or slow connection) where the delay and data load might take some time
  • Optionally use rowItem.selected to avoid another "bug" since the afterSelectionChange event fires twice even when selecting a row (once for the row being unselected and once for the selected row)
  • use the fireOnlyOnce variable to avoid calling twice the afterSelectionChange function.

Here's a sample code:

$scope.fireOnlyOnce=true;
$scope.gridOptions = {
    //Stuff
    afterSelectionChange: function (rowItem) {
        if($scope.fireOnlyOnce){
            if(rowItem.selected){
                //Do stuff
            }
        } else {
            $scope.fireOnlyOnce=true;
        }
    }
};

$scope.$on('ngGridEventData', jQuery.debounce(100, function (row, event){   
    var renderedRows = row['targetScope'].renderedRows.length;
    if(renderedRows>0){
        $scope.fireOnlyOnce=false;
        $timeout(function(){$scope.gridOptions.selectRow(2, true)});
    }
}));
Billow answered 10/4, 2015 at 14:30 Comment(0)
G
2

Ok, the answer was awarded long ago, but I still think that it has a code smell (no offence to the poster, but it is sub-optimal.

What I did was use the grid's ngGridEventData event.

You have to be careful, since it fires multiple times (once for each row added), but, since we know the size of the data which will populate the gird and, since the event, allows us to examine how many rows have been rendered, we can tell when the last row is rendered, meaning that the grid is not fully displayed (NOTE: I did not test this with scrolling grids, where some rows may not be visible, could someone please confirm if it works in hat case? I personally never use scrolling grids (it's a browser page, not a Desktop).

Something like this:

    $scope.$on('ngGridEventData', function (row, event) 
               {   
                   if (event == $scope.vehicleTypeGridOptions.gridId)
                   {
                       console.info('@+@ vehicleTypeGridOptions  grid updated');
                       var renderedRows = row['targetScope'].renderedRows.length;
                       console.info('renderedRows = ' + renderedRows + '; num data rows = ' + $scope.vehicleTypesGridData.length);                       

                       if (renderedRows == 0)
                       {
                           return;
                       }

                       // if grid rowcount = dat length then it's fully displayed
                       if (renderedRows == $scope.vehicleTypesGridData.length) 
                       {
                           console.log('vehicleTypeGrid fully rendered. Select row zer0, then populate vehicleDescriptionGrid');
                           console.info('Select row zer0');                                
                           $scope.vehicleTypeGridOptions.selectItem(0, true);   // Grid rendered, select first row
                           // console.table($scope.vehicleTypeGridOptions.selectedItems);
                           var vehicle_type =     $scope.vehicleTypeGridOptions.selectedItems[0].vehicle_type;
                           console.info(vehicle_type);                               
                       }
                   }
Gudrunguelderrose answered 3/5, 2014 at 9:34 Comment(1)
I can confirm it won't work on scrolling grids. the event will fire only for the rows shown (actually i'm not sure it fires for each row. for me it fired 4 times: twice with 0 rows rendered and twice with 6 rows rendered, then it stopped triggering)Billow

© 2022 - 2024 — McMap. All rights reserved.