Is it possible to have a select drop down inside of the AngularJS ng-grid?

All we need is an easy explanation of the problem, so here it is.

I have coded the following:

$scope.gridOptions = {
    data: 'myData',
    enableCellEdit: true,
    multiSelect: false,
    columnDefs: [
        { field: 'Id', displayName: 'Id' },
        { field: 'Name', displayName: 'Name', enableCellEdit: true, editableCellTemplate: cellEditableTemplate },
        { field: 'Description', displayName: 'Description', enableCellEdit: true, editableCellTemplate: cellEditableTemplate }
    ]
};

The myData actually contains four colums Id, Name, Status and Description. Where status is a simple javascript array with three types of status called myStatus.

Is it possible for me to somehow link in the data from myStatus to a field in the ng-grid so I can then select a new value from a select drop down?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Here is output of some experiment.

http://plnkr.co/edit/W1TkRgsp0klhqquxaiyc?p=preview

It seems that you can put select in cell template.
And you can make use of row object to retrieve whatever
you need.
I used row.rowIndex to property access to the original data.

template example:

<div>
  <select ng-model="myData[ row.rowIndex ].myStatus">
    <option ng-repeat="st in statuses">{{st}}</option>
  </select>
</div>

(It would be beutiful if we can write to ogirinal data through row
object. I do not know how.)

Method 2

The way tosh shimayama are doing it, will not allow for sorting the table in any other order than the model array.

This is kind of an ugly way to do it, but I took a quick look in the source code for ng-grid and found that they use regexp to insert the ng-model. So by using the same variable, COL_FIELD, in your code you can make ng-grid insert the correct model.

<div>
  <select ng-model="COL_FIELD">
    <option ng-repeat="status in statuses">{{status}}</option>
  </select>
</div>

Here is a plunker with a working example:
http://plnkr.co/edit/Yj2qmI?p=preview

Method 3

A more complete/tidier way to do this in ng-grid 2.x I’ve included in a plunker here: http://plnkr.co/edit/VABAEu?p=preview, leveraging content from another similar question on stackoverflow here: AngularJS and ng-grid – auto save data to the server after a cell was changed

In summary, my format for the editable field template looks like so:

      $scope.statuses = {1: 'active', 2: 'inactive'};
      $scope.cellSelectEditableTemplate = '<select ng-class="\'colt\' + col.index" 
         ng-input="COL_FIELD" ng-model="COL_FIELD" 
         ng-options="id as name for (id, name) in statuses" 
         ng-blur="updateEntity(row)" />';

I’ve provided a blog post that has a more thorough walkthrough of the end-to-end code: http://technpol.wordpress.com/2013/12/06/editable-nggrid-with-both-dropdowns-and-selects/

Ng-grid (ui-grid) 3.0 is close to being released, and offers different ways to do editable grids. I have a post on that here: http://technpol.wordpress.com/2014/08/23/upgrading-to-ng-grid-3-0-ui-grid/

Method 4

I can’t take credit for the entire solution. I just put the pieces together. My goal was to preserve three-way binding.

Template should look something like this:

        $scope.cellSelectEditableTemplate = '<select ng-class="\'colt\' + col.index" ng-input="COL_FIELD" ng-model="COL_FIELD" ng-options="value.id as value.label for value in OptionsList}" />';

COL_FIELD of course essential to keep the reference to correct cell.

You can capture the change natively:

$scope.$on('ngGridEventEndCellEdit', function (evt) {
            console.log(evt.targetScope.row.entity);
            WaitListArray.$save(evt.targetScope.row.entity)
                .then(function (ref) {
                    console.log('saved');
                });
        });

In this case WaitListArray is my Firebase/AngularFire Array for the table. Using this method, I was able to preserve my tree-way binding.

Field (ng-options):

{
  field: 'status',
  displayName: 'Status',
  enableCellEditOnFocus: true,
  editableCellTemplate: $scope.cellSelectEditableTemplate,
  cellFilter: 'mapStatus:OptionsList'
}

I added filter to replace id with label for my dropdown values.

.filter('mapStatus', function() {
  return function(input, OptionsList) {
    var _out = 'unknown';
    angular.forEach(OptionsList, function(value, key) {

      if (value && value.id == input) {
        _out = value.label;
      }
    });
    return _out;

  };
})

In the above, OptionsList is my dropdown values array
example: {id:1,label:”label1″}

I found this solution highly reusable. Hopefully, it saves time for someone.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply