I've spent some time pulling together the bits of this for ng-grid 2.x. I still have a problem with having to click twice to edit a row, but I think that's a bootstrap issue, not an ngGrid issue, it doesn't happen in my sample code (which doesn't have bootstrap yet).
I've also implemented similar logic in a tutorial for ui-grid 3.0, which is still beta but will soon become the preferred version. This can be found at: http://technpol.wordpress.com/2014/08/23/upgrading-to-ng-grid-3-0-ui-grid/, and provides a much easier and cleaner api for this functionality.
For the 2.x version, to illustrate all the bits, I've created a running plunker that has an editable grid with both a dropdown and an input field, uses the ngBlur directive, and uses a $timeout to avoid duplicate saves on the update: http://plnkr.co/edit/VABAEu?p=preview
The basics of the code are:
var app = angular.module('plunker', ["ngGrid"]);
app.controller('MainCtrl', function($scope, $timeout, StatusesConstant) {
$scope.statuses = StatusesConstant;
$scope.cellInputEditableTemplate = '<input ng-class="\'colt\' + col.index" ng-input="COL_FIELD" ng-model="COL_FIELD" ng-blur="updateEntity(row)" />';
$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)" />';
$scope.list = [
{ name: 'Fred', age: 45, status: 1 },
{ name: 'Julie', age: 29, status: 2 },
{ name: 'John', age: 67, status: 1 }
];
$scope.gridOptions = {
data: 'list',
enableRowSelection: false,
enableCellEditOnFocus: true,
multiSelect: false,
columnDefs: [
{ field: 'name', displayName: 'Name', enableCellEditOnFocus: true,
editableCellTemplate: $scope.cellInputEditableTemplate },
{ field: 'age', displayName: 'Age', enableCellEdit: false },
{ field: 'status', displayName: 'Status', enableCellEditOnFocus: true,
editableCellTemplate: $scope.cellSelectEditableTemplate,
cellFilter: 'mapStatus'}
]
};
$scope.updateEntity = function(row) {
if(!$scope.save) {
$scope.save = { promise: null, pending: false, row: null };
}
$scope.save.row = row.rowIndex;
if(!$scope.save.pending) {
$scope.save.pending = true;
$scope.save.promise = $timeout(function(){
// $scope.list[$scope.save.row].$update();
console.log("Here you'd save your record to the server, we're updating row: "
+ $scope.save.row + " to be: "
+ $scope.list[$scope.save.row].name + ","
+ $scope.list[$scope.save.row].age + ","
+ $scope.list[$scope.save.row].status);
$scope.save.pending = false;
}, 500);
}
};
})
.directive('ngBlur', function () {
return function (scope, elem, attrs) {
elem.bind('blur', function () {
scope.$apply(attrs.ngBlur);
});
};
})
.filter('mapStatus', function( StatusesConstant ) {
return function(input) {
if (StatusesConstant[input]) {
return StatusesConstant[input];
} else {
return 'unknown';
}
};
})
.factory( 'StatusesConstant', function() {
return {
1: 'active',
2: 'inactive'
};
});
When you run this plunker, and the lose focus fires, you should see on the console the update trigger firing.
I also included a README.md in the plunker with some thoughts on things that gave me difficulty, reproduced here.
The functionality here is that I have a list of people, those people
have names, ages and statuses. In line with what we might do in a real
app, the status is a code, and we want to show the decode. Accordingly
we have a status codes list (which might in a real app come from the database),
and we have a filter to map the code to the decode.
What we want are two things. We'd like to be able to edit the name in
an input box, and to edit the status in a dropdown.
Comments on things I've learned on this plunk.
At the gridOptions level, there are both enableCellEditOnFocus and
enableCellEdit. Don't enable both, you need to pick. onFocus means
single click, CellEdit means double click. If you enable both then
you get unexpected behaviour on the bits of your grid you didn't want
to be editable
At the columnDefs level, you have the same options. But this time you
need to set both CellEdit and onFocus, and you need to set cellEdit to
false on any cells you don't want edited - this isn't the default
The documentation says that your editable cell template can be:
<input ng-class="'colt' + col.index" ng-input="COL_FIELD" />
actually it needs to be:
<input ng-class="'colt' + col.index" ng-input="COL_FIELD" ng-model="COL_FIELD" />
To trigger a save event when we lose focus, we've created an blur directive,
the logic for which I found in stackoverflow: AngularJS and ng-grid - auto save data to the server after a cell was changed
This also means changing each editable cell template to call ng-blur, which
you can see at the end of the editable cell template
We get two blur events when we leave the field (at least in Chrome), so we
use a timer so that only one of them is processed. Ugly, but it works.
I've also created a blog post that does a more thorough walkthrough of this code: http://technpol.wordpress.com/2013/12/06/editable-nggrid-with-both-dropdowns-and-selects/