Создание пользовательской директивы редактора в пользовательском интерфейсе для локализации
Я создаю приложение, которое использует ui-grid, которое должно поддерживать IE 11. Локализация работала нормально, за исключением случаев редактирования числовых ячеек (десятичный разделитель не меняется).
Я читал, что способ решить эту проблему - создать собственную директиву редактора. Я создал editableCellTemplate:
var customNumberTemplate = '<div><form name="inputForm"><input type="text" class="customNumber" custom-number ng-class="\'colt\' + col.uid" ng-model="MODEL_COL_FIELD" pattern="^[+-]?([0-9]+([,][0-9]*)?|[,][0-9]+)$"></form></div>';
Обратите внимание, что он имеет тип текста и шаблон для проверки действительного числа, но с "," в качестве разделителя. Я попытался дать ему type='number', однако это не работает, так как он пытается запустить мой валидатор и стандартный валидатор html-5 (не может иметь ",").
Для директивы я скопировал ui-grid-uiGridEditor и добавил две функции. Цель этого заключалась в том, чтобы, когда пользователь открывает ячейку, я преобразовывал ее в строку, а когда он закрывал, я преобразовывал ее обратно в число с плавающей точкой. Это, по-видимому, невозможно, сетка всегда возвращает мне значение в виде строки, возможно, потому, что тип шаблона установлен на текст (я пытался изменить тип $elm на 'numeric', но это не сработало). Вот код, две функции находятся сверху:
var _initCustomNumberDirective = function () {
_angularController.directive('customNumber', ['gridUtil', 'uiGridConstants', 'uiGridEditConstants', '$timeout', 'uiGridEditService',
function (gridUtil, uiGridConstants, uiGridEditConstants, $timeout, uiGridEditService) {
return {
scope: true,
require: ['?^uiGrid', '?^uiGridRenderContainer', 'ngModel'],
compile: function () {
// START OF MY CODE
var beforeEdit = function ($scope, $elm) {
if ($elm.length > 0 && $elm[0].classList.contains('customNumber')) {
var modelField = $scope.row.getQualifiedColField($scope.col)
if (eval('!isNaN($scope.' + modelField + ')')) {
eval('$scope.' + modelField + '= $scope.' + modelField + '.toString().replace(".", ",")');
}
}
}
var editionComplete = function ($scope, $elm) {
if ($elm.length > 0 && $elm[0].classList.contains('customNumber')) {
$elm[0].value = $elm[0].value.replace(',', '.');
if (!isNaN($elm[0].value)) {
var modelField = $scope.row.getQualifiedColField($scope.col)
eval('$scope.' + modelField + ' = parseFloat($elm[0].value)');
}
}
}
// END OF MY CODE
return {
pre: function ($scope, $elm, $attrs) {
beforeEdit($scope, $elm); // MY CODE
},
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) {
$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)) {
ngModel.$setViewValue(String.fromCharCode(typeof evt.which === 'number' ? evt.which : evt.keyCode), 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 {
editionComplete($scope, $elm); // MY CODE
$scope.$emit(uiGridEditConstants.events.END_CELL_EDIT);
}
$scope.deepEdit = false;
};
$elm.on('click', function (evt) {
if ($elm[0].type !== 'checkbox') {
$scope.deepEdit = true;
$timeout(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();
});
}
};
}
};
}]);
}
Поскольку я не мог заставить редактор возвращать число, я нашел обходной путь, непосредственно изменив значение сетки, однако это не работает, когда ячейка не проходит нашу проверку (должно быть <число и т. Д.), так как я уже редактировал непосредственно в сетке, у меня все равно будет неправильное значение.
У меня вопрос: могу ли я заставить свой пользовательский редактор возвращать число вместо строки, и если нет, то как я могу реализовать эту функцию без нее?