/*! * ui-grid - v4.4.6 - 2018-04-06 * Copyright (c) 2018 ; License: MIT */ (function () { 'use strict'; /** * @ngdoc overview * @name ui.grid.edit * @description * * # ui.grid.edit * *
* gridApi.edit.on.afterCellEdit(scope,function(rowEntity, colDef){})
*
* @param {object} rowEntity the options.data element that was edited
* @param {object} colDef the column that was edited
* @param {object} newValue new value
* @param {object} oldValue old value
*/
afterCellEdit: function (rowEntity, colDef, newValue, oldValue) {
},
/**
* @ngdoc event
* @name beginCellEdit
* @eventOf ui.grid.edit.api:PublicApi
* @description raised when cell editing starts on a cell
*
* gridApi.edit.on.beginCellEdit(scope,function(rowEntity, colDef){})
*
* @param {object} rowEntity the options.data element that was edited
* @param {object} colDef the column that was edited
* @param {object} triggerEvent the event that triggered the edit. Useful to prevent losing keystrokes on some
* complex editors
*/
beginCellEdit: function (rowEntity, colDef, triggerEvent) {
},
/**
* @ngdoc event
* @name cancelCellEdit
* @eventOf ui.grid.edit.api:PublicApi
* @description raised when cell editing is cancelled on a cell
*
* gridApi.edit.on.cancelCellEdit(scope,function(rowEntity, colDef){})
*
* @param {object} rowEntity the options.data element that was edited
* @param {object} colDef the column that was edited
*/
cancelCellEdit: function (rowEntity, colDef) {
}
}
},
methods: {
edit: { }
}
};
grid.api.registerEventsFromObject(publicApi.events);
//grid.api.registerMethodsFromObject(publicApi.methods);
},
defaultGridOptions: function (gridOptions) {
/**
* @ngdoc object
* @name ui.grid.edit.api:GridOptions
*
* @description Options for configuring the edit feature, these are available to be
* set using the ui-grid {@link ui.grid.class:GridOptions gridOptions}
*/
/**
* @ngdoc object
* @name enableCellEdit
* @propertyOf ui.grid.edit.api:GridOptions
* @description If defined, sets the default value for the editable flag on each individual colDefs
* if their individual enableCellEdit configuration is not defined. Defaults to undefined.
*/
/**
* @ngdoc object
* @name cellEditableCondition
* @propertyOf ui.grid.edit.api:GridOptions
* @description If specified, either a value or function to be used by all columns before editing.
* If false, then editing of cell is not allowed.
* @example
*
* function($scope, triggerEvent){
* //use $scope.row.entity, $scope.col.colDef and triggerEvent to determine if editing is allowed
* return true;
* }
*
*/
gridOptions.cellEditableCondition = gridOptions.cellEditableCondition === undefined ? true : gridOptions.cellEditableCondition;
/**
* @ngdoc object
* @name editableCellTemplate
* @propertyOf ui.grid.edit.api:GridOptions
* @description If specified, cellTemplate to use as the editor for all columns.
*
* function($scope, triggerEvent){
* //use $scope.row.entity, $scope.col.colDef and triggerEvent to determine if editing is allowed
* return true;
* }
*
*/
colDef.cellEditableCondition = colDef.cellEditableCondition === undefined ? gridOptions.cellEditableCondition : colDef.cellEditableCondition;
/**
* @ngdoc object
* @name editableCellTemplate
* @propertyOf ui.grid.edit.api:ColumnDef
* @description cell template to be used when editing this column. Can be Url or text template
*
* $scope.gridOptions = {
* columnDefs: [
* {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
* editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
* ],
*
*
*/
/**
* @ngdoc property
* @name editDropdownRowEntityOptionsArrayPath
* @propertyOf ui.grid.edit.api:ColumnDef
* @description a path to a property on row.entity containing an
* array of values in the format
* [ {id: xxx, value: xxx} ], which will be used to populate
* the edit dropdown. This can be used when the dropdown values are dependent on
* the backing row entity.
* If this property is set then editDropdownOptionsArray will be ignored.
* @example
*
* $scope.gridOptions = {
* columnDefs: [
* {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownRowEntityOptionsArrayPath: 'foo.bars[0].baz',
* editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
* ],
*
*
*/
/**
* @ngdoc service
* @name editDropdownOptionsFunction
* @methodOf ui.grid.edit.api:ColumnDef
* @description a function returning an array of values in the format
* [ {id: xxx, value: xxx} ], which will be used to populate
* the edit dropdown. This can be used when the dropdown values are dependent on
* the backing row entity with some kind of algorithm.
* If this property is set then both editDropdownOptionsArray and
* editDropdownRowEntityOptionsArrayPath will be ignored.
* @param {object} rowEntity the options.data element that the returned array refers to
* @param {object} colDef the column that implements this dropdown
* @returns {object} an array of values in the format
* [ {id: xxx, value: xxx} ] used to populate the edit dropdown
* @example
*
* $scope.gridOptions = {
* columnDefs: [
* {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownOptionsFunction: function(rowEntity, colDef) {
* if (rowEntity.foo === 'bar') {
* return [{id: 'bar1', value: 'BAR 1'},
* {id: 'bar2', value: 'BAR 2'},
* {id: 'bar3', value: 'BAR 3'}];
* } else {
* return [{id: 'foo1', value: 'FOO 1'},
* {id: 'foo2', value: 'FOO 2'}];
* }
* },
* editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
* ],
*
*
*/
/**
* @ngdoc property
* @name editDropdownValueLabel
* @propertyOf ui.grid.edit.api:ColumnDef
* @description the label for the "value" field
* in the editDropdownOptionsArray. Defaults
* to 'value'
* @example
*
* $scope.gridOptions = {
* columnDefs: [
* {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
* editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
* ],
*
*
*/
/**
* @ngdoc property
* @name editDropdownFilter
* @propertyOf ui.grid.edit.api:ColumnDef
* @description A filter that you would like to apply to the values in the options list
* of the dropdown. For example if you were using angular-translate you might set this
* to `'translate'`
* @example
*
* $scope.gridOptions = {
* columnDefs: [
* {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
* editDropdownOptionsArray: [{code: 1, status: 'active'}, {code: 2, status: 'inactive'}],
* editDropdownIdLabel: 'code', editDropdownValueLabel: 'status', editDropdownFilter: 'translate' }
* ],
*
*
*/
function beginEditAfterScroll(triggerEvent) {
// If we are already editing, then just skip this so we don't try editing twice...
if (inEdit) {
return;
}
if (!shouldEdit($scope.col, $scope.row, triggerEvent)) {
return;
}
var modelField = $scope.row.getQualifiedColField($scope.col);
if ($scope.col.colDef.editModelField) {
modelField = gridUtil.preEval('row.entity.' + $scope.col.colDef.editModelField);
}
cellModel = $parse(modelField);
//get original value from the cell
origCellValue = cellModel($scope);
html = $scope.col.editableCellTemplate;
html = html.replace(uiGridConstants.MODEL_COL_FIELD, modelField);
html = html.replace(uiGridConstants.COL_FIELD, 'grid.getCellValue(row, col)');
var optionFilter = $scope.col.colDef.editDropdownFilter ? '|' + $scope.col.colDef.editDropdownFilter : '';
html = html.replace(uiGridConstants.CUSTOM_FILTERS, optionFilter);
var inputType = 'text';
switch ($scope.col.colDef.type){
case 'boolean':
inputType = 'checkbox';
break;
case 'number':
inputType = 'number';
break;
case 'date':
inputType = 'date';
break;
}
html = html.replace('INPUT_TYPE', inputType);
// In order to fill dropdown options we use:
// - A function/promise or
// - An array inside of row entity if no function exists or
// - A single array for the whole column if none of the previous exists.
var editDropdownOptionsFunction = $scope.col.colDef.editDropdownOptionsFunction;
if (editDropdownOptionsFunction) {
$q.when(editDropdownOptionsFunction($scope.row.entity, $scope.col.colDef))
.then(function(result) {
$scope.editDropdownOptionsArray = result;
});
} else {
var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
if (editDropdownRowEntityOptionsArrayPath) {
$scope.editDropdownOptionsArray = resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
}
else {
$scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
}
}
$scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
$scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
var cellElement;
var createEditor = function(){
inEdit = true;
cancelBeginEditEvents();
var cellElement = angular.element(html);
$elm.append(cellElement);
editCellScope = $scope.$new();
$compile(cellElement)(editCellScope);
var gridCellContentsEl = angular.element($elm.children()[0]);
gridCellContentsEl.addClass('ui-grid-cell-contents-hidden');
};
if (!$rootScope.$$phase) {
$scope.$apply(createEditor);
} else {
createEditor();
}
//stop editing when grid is scrolled
var deregOnGridScroll = $scope.col.grid.api.core.on.scrollBegin($scope, function () {
if ($scope.grid.disableScrolling) {
return;
}
endEdit();
$scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
deregOnGridScroll();
deregOnEndCellEdit();
deregOnCancelCellEdit();
});
//end editing
var deregOnEndCellEdit = $scope.$on(uiGridEditConstants.events.END_CELL_EDIT, function () {
endEdit();
$scope.grid.api.edit.raise.afterCellEdit($scope.row.entity, $scope.col.colDef, cellModel($scope), origCellValue);
deregOnEndCellEdit();
deregOnGridScroll();
deregOnCancelCellEdit();
});
//cancel editing
var deregOnCancelCellEdit = $scope.$on(uiGridEditConstants.events.CANCEL_CELL_EDIT, function () {
cancelEdit();
deregOnCancelCellEdit();
deregOnGridScroll();
deregOnEndCellEdit();
});
$scope.$broadcast(uiGridEditConstants.events.BEGIN_CELL_EDIT, triggerEvent);
$timeout(function () {
// execute in a timeout to give any complex editor templates a cycle to completely render
$scope.grid.api.edit.raise.beginCellEdit($scope.row.entity, $scope.col.colDef, triggerEvent);
});
}
function endEdit() {
$scope.grid.disableScrolling = false;
if (!inEdit) {
return;
}
//sometimes the events can't keep up with the keyboard and grid focus is lost, so always focus
//back to grid here. The focus call needs to be before the $destroy and removal of the control,
//otherwise ng-model-options of UpdateOn: 'blur' will not work.
if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
uiGridCtrl.focus();
}
var gridCellContentsEl = angular.element($elm.children()[0]);
//remove edit element
editCellScope.$destroy();
var children = $elm.children();
for (var i = 1; i < children.length; i++) {
angular.element(children[i]).remove();
}
gridCellContentsEl.removeClass('ui-grid-cell-contents-hidden');
inEdit = false;
registerBeginEditEvents();
$scope.grid.api.core.notifyDataChange( uiGridConstants.dataChange.EDIT );
}
function cancelEdit() {
$scope.grid.disableScrolling = false;
if (!inEdit) {
return;
}
cellModel.assign($scope, origCellValue);
$scope.$apply();
$scope.grid.api.edit.raise.cancelCellEdit($scope.row.entity, $scope.col.colDef);
endEdit();
}
// resolves a string path against the given object
// shamelessly borrowed from
// http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
function resolveObjectFromPath(object, path) {
path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
path = path.replace(/^\./, ''); // strip a leading dot
var a = path.split('.');
while (a.length) {
var n = a.shift();
if (n in object) {
object = object[n];
} else {
return;
}
}
return object;
}
}
};
}]);
/**
* @ngdoc directive
* @name ui.grid.edit.directive:uiGridEditor
* @element div
* @restrict A
*
* @description input editor directive for editable fields.
* Provides EndEdit and CancelEdit events
*
* Events that end editing:
* blur and enter keydown
*
* Events that cancel editing:
* - Esc keydown
*
*/
module.directive('uiGridEditor',
['gridUtil', 'uiGridConstants', 'uiGridEditConstants','$timeout', 'uiGridEditService',
function (gridUtil, uiGridConstants, uiGridEditConstants, $timeout, uiGridEditService) {
return {
scope: true,
require: ['?^uiGrid', '?^uiGridRenderContainer', 'ngModel'],
compile: function () {
return {
pre: function ($scope, $elm, $attrs) {
},
post: function ($scope, $elm, $attrs, controllers) {
var uiGridCtrl, renderContainerCtrl, ngModel;
if (controllers[0]) { uiGridCtrl = controllers[0]; }
if (controllers[1]) { renderContainerCtrl = controllers[1]; }
if (controllers[2]) { ngModel = controllers[2]; }
//set focus at start of edit
$scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function (evt,triggerEvent) {
// must be in a timeout since it requires a new digest cycle
$timeout(function () {
$elm[0].focus();
//only select text if it is not being replaced below in the cellNav viewPortKeyPress
if ($elm[0].select && ($scope.col.colDef.enableCellEditOnFocus || !(uiGridCtrl && uiGridCtrl.grid.api.cellNav))) {
$elm[0].select();
}
else {
//some browsers (Chrome) stupidly, imo, support the w3 standard that number, email, ...
//fields should not allow setSelectionRange. We ignore the error for those browsers
//https://www.w3.org/Bugs/Public/show_bug.cgi?id=24796
try {
$elm[0].setSelectionRange($elm[0].value.length, $elm[0].value.length);
}
catch (ex) {
//ignore
}
}
});
//set the keystroke that started the edit event
//we must do this because the BeginEdit is done in a different event loop than the intitial
//keydown event
//fire this event for the keypress that is received
if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
var viewPortKeyDownUnregister = uiGridCtrl.grid.api.cellNav.on.viewPortKeyPress($scope, function (evt, rowCol) {
if (uiGridEditService.isStartEditKey(evt)) {
var code = typeof evt.which === 'number' ? evt.which : evt.keyCode;
if (code > 0) {
ngModel.$setViewValue(String.fromCharCode(code), evt);
ngModel.$render();
}
}
viewPortKeyDownUnregister();
});
}
// macOS will blur the checkbox when clicked in Safari and Firefox,
// to get around this, we disable the blur handler on mousedown,
// and then focus the checkbox and re-enable the blur handler after $timeout
$elm.on('mousedown', function(evt) {
if ($elm[0].type === 'checkbox') {
$elm.off('blur', $scope.stopEdit);
$timeout(function() {
$elm[0].focus();
$elm.on('blur', $scope.stopEdit);
});
}
});
$elm.on('blur', $scope.stopEdit);
});
$scope.deepEdit = false;
$scope.stopEdit = function (evt) {
if ($scope.inputForm && !$scope.inputForm.$valid) {
evt.stopPropagation();
$scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
}
else {
$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
}
$scope.deepEdit = false;
};
$elm.on('click', function (evt) {
if ($elm[0].type !== 'checkbox') {
$scope.deepEdit = true;
$scope.$applyAsync(function () {
$scope.grid.disableScrolling = true;
});
}
});
$elm.on('keydown', function (evt) {
switch (evt.keyCode) {
case uiGridConstants.keymap.ESC:
evt.stopPropagation();
$scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
break;
}
if ($scope.deepEdit &&
(evt.keyCode === uiGridConstants.keymap.LEFT ||
evt.keyCode === uiGridConstants.keymap.RIGHT ||
evt.keyCode === uiGridConstants.keymap.UP ||
evt.keyCode === uiGridConstants.keymap.DOWN)) {
evt.stopPropagation();
}
// Pass the keydown event off to the cellNav service, if it exists
else if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
if (uiGridCtrl.cellNav.handleKeyDown(evt) !== null) {
$scope.stopEdit(evt);
}
}
else {
//handle enter and tab for editing not using cellNav
switch (evt.keyCode) {
case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
case uiGridConstants.keymap.TAB:
evt.stopPropagation();
evt.preventDefault();
$scope.stopEdit(evt);
break;
}
}
return true;
});
$scope.$on('$destroy', function unbindEvents() {
// unbind all jquery events in order to avoid memory leaks
$elm.off();
});
}
};
}
};
}]);
/**
* @ngdoc directive
* @name ui.grid.edit.directive:input
* @element input
* @restrict E
*
* @description directive to provide binding between input[date] value and ng-model for angular 1.2
* It is similar to input[date] directive of angular 1.3
*
* Supported date format for input is 'yyyy-MM-dd'
* The directive will set the $valid property of input element and the enclosing form to false if
* model is invalid date or value of input is entered wrong.
*
*/
module.directive('uiGridEditor', ['$filter', function ($filter) {
function parseDateString(dateString) {
if (typeof(dateString) === 'undefined' || dateString === '') {
return null;
}
var parts = dateString.split('-');
if (parts.length !== 3) {
return null;
}
var year = parseInt(parts[0], 10);
var month = parseInt(parts[1], 10);
var day = parseInt(parts[2], 10);
if (month < 1 || year < 1 || day < 1) {
return null;
}
return new Date(year, (month - 1), day);
}
return {
priority: -100, // run after default uiGridEditor directive
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
if (angular.version.minor === 2 && attrs.type && attrs.type === 'date' && ngModel) {
ngModel.$formatters.push(function (modelValue) {
ngModel.$setValidity(null,(!modelValue || !isNaN(modelValue.getTime())));
return $filter('date')(modelValue, 'yyyy-MM-dd');
});
ngModel.$parsers.push(function (viewValue) {
if (viewValue && viewValue.length > 0) {
var dateValue = parseDateString(viewValue);
ngModel.$setValidity(null, (dateValue && !isNaN(dateValue.getTime())));
return dateValue;
}
else {
ngModel.$setValidity(null, true);
return null;
}
});
}
}
};
}]);
/**
* @ngdoc directive
* @name ui.grid.edit.directive:uiGridEditDropdown
* @element div
* @restrict A
*
* @description dropdown editor for editable fields.
* Provides EndEdit and CancelEdit events
*
* Events that end editing:
* blur and enter keydown, and any left/right nav
*
* Events that cancel editing:
* - Esc keydown
*
*/
module.directive('uiGridEditDropdown',
['uiGridConstants', 'uiGridEditConstants', '$timeout',
function (uiGridConstants, uiGridEditConstants, $timeout) {
return {
require: ['?^uiGrid', '?^uiGridRenderContainer'],
scope: true,
compile: function () {
return {
pre: function ($scope, $elm, $attrs) {
},
post: function ($scope, $elm, $attrs, controllers) {
var uiGridCtrl = controllers[0];
var renderContainerCtrl = controllers[1];
//set focus at start of edit
$scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
$timeout(function(){
$elm[0].focus();
});
$elm[0].style.width = ($elm[0].parentElement.offsetWidth - 1) + 'px';
$elm.on('blur', function (evt) {
$scope.stopEdit(evt);
});
});
$scope.stopEdit = function (evt) {
// no need to validate a dropdown - invalid values shouldn't be
// available in the list
$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
};
$elm.on('keydown', function (evt) {
switch (evt.keyCode) {
case uiGridConstants.keymap.ESC:
evt.stopPropagation();
$scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
break;
}
if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
evt.uiGridTargetRenderContainerId = renderContainerCtrl.containerId;
if (uiGridCtrl.cellNav.handleKeyDown(evt) !== null) {
$scope.stopEdit(evt);
}
}
else {
//handle enter and tab for editing not using cellNav
switch (evt.keyCode) {
case uiGridConstants.keymap.ENTER: // Enter (Leave Field)
case uiGridConstants.keymap.TAB:
evt.stopPropagation();
evt.preventDefault();
$scope.stopEdit(evt);
break;
}
}
return true;
});
$scope.$on('$destroy', function unbindEvents() {
// unbind jquery events to prevent memory leaks
$elm.off();
});
}
};
}
};
}]);
/**
* @ngdoc directive
* @name ui.grid.edit.directive:uiGridEditFileChooser
* @element div
* @restrict A
*
* @description input editor directive for editable fields.
* Provides EndEdit and CancelEdit events
*
* Events that end editing:
* blur and enter keydown
*
* Events that cancel editing:
* - Esc keydown
*
*/
module.directive('uiGridEditFileChooser',
['gridUtil', 'uiGridConstants', 'uiGridEditConstants',
function (gridUtil, uiGridConstants, uiGridEditConstants) {
return {
scope: true,
require: ['?^uiGrid', '?^uiGridRenderContainer'],
compile: function () {
return {
pre: function ($scope, $elm, $attrs) {
},
post: function ($scope, $elm) {
function handleFileSelect(event) {
var target = event.srcElement || event.target;
if (target && target.files && target.files.length > 0) {
/**
* @ngdoc property
* @name editFileChooserCallback
* @propertyOf ui.grid.edit.api:ColumnDef
* @description A function that should be called when any files have been chosen
* by the user. You should use this to process the files appropriately for your
* application.
*
* It passes the gridCol, the gridRow (from which you can get gridRow.entity),
* and the files. The files are in the format as returned from the file chooser,
* an array of files, with each having useful information such as:
* - `files[0].lastModifiedDate`
* - `files[0].name`
* - `files[0].size` (appears to be in bytes)
* - `files[0].type` (MIME type by the looks)
*
* Typically you would do something with these files - most commonly you would
* use the filename or read the file itself in. The example function does both.
*
* @example
*
* editFileChooserCallBack: function(gridRow, gridCol, files ){
* // ignore all but the first file, it can only choose one anyway
* // set the filename into this column
* gridRow.entity.filename = file[0].name;
*
* // read the file and set it into a hidden column, which we may do stuff with later
* var setFile = function(fileContent){
* gridRow.entity.file = fileContent.currentTarget.result;
* };
* var reader = new FileReader();
* reader.onload = setFile;
* reader.readAsText( files[0] );
* }
*
*/
if ( typeof($scope.col.colDef.editFileChooserCallback) === 'function' ) {
$scope.col.colDef.editFileChooserCallback($scope.row, $scope.col, target.files);
} else {
gridUtil.logError('You need to set colDef.editFileChooserCallback to use the file chooser');
}
target.form.reset();
$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
} else {
$scope.$emit(uiGridEditConstants.events.CANCEL_CELL_EDIT);
}
$elm[0].removeEventListener('change', handleFileSelect, false);
}
$elm[0].addEventListener('change', handleFileSelect, false);
$scope.$on(uiGridEditConstants.events.BEGIN_CELL_EDIT, function () {
$elm[0].focus();
$elm[0].select();
$elm.on('blur', function () {
$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
$elm.off();
});
});
}
};
}
};
}]);
})();