Нет обновлений ng-модели при фокусировке ввода
Я делаю директиву, которая будет блокировать рендеринг на входе, пока он сфокусирован.
Сценарий использования состоит в том, что мы получаем частые обновления в реальном времени от бэкэнда, и он будет перезаписывать все, что пользователь пишет во входных данных из-за привязки ng-модели. Мы отправляем обновление по нажатию Enter, используя ng-keydown="($event.keyCode === 13) ? $ctrl.setItem($event, $ctrl.item) : return"
где $ ctrl.setItem отправит запрос бэкэнду.
У меня почти получилось так, как я хочу, только я получаю удивительные результаты, когда размываю ввод после внесения изменений.
Я создал планку, где я имитирую обновления бэкэнда, используя интервал $: https://plnkr.co/edit/XNFA3bQtbGliAhS0uVmP?p=preview
app.directive('noUpdatesWhenFocused', function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel || element[0].type !== 'text') {
return;
}
var hasFocus = false;
element.on('focus', function() {
hasFocus = true;
});
element.on('blur', function() {
hasFocus = false;
ngModel.$render();
});
ngModel.$render = function() {
if (!hasFocus) {
element.val(ngModel.$viewValue);
}
};
}
};
});
Если вы размыли после выполнения редактирования в первом поле ввода и ожидания нового обновления в течение нескольких секунд, то модель возвращается к состоянию последнего редактирования вида, а не к последнему обновлению модели. Мы всегда хотим показывать последние обновления из бэкэнда, так что это то, что мне нужно исправить, но я в тупике.
1 ответ
Хорошо, я понял это. Пазеры ngModel.$ Запускались до события размытия. Поэтому я добавил парсер, который игнорирует viewValue, если он не изменился с прошлого раза, когда парсеры были вызваны, чего не произошло, если вы размыли.
var app = angular.module('myApp', []);
app.directive('noUpdatesWhenFocused', function() {
return {
restrict: 'A',
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel || element[0].type !== 'text') {
return;
}
var hasFocus = false;
element.on('focus', function() {
hasFocus = true;
});
element.on('blur', function() {
hasFocus = false;
ngModel.$render();
});
ngModel.$render = function() {
if (!hasFocus) {
element.val(ngModel.$viewValue);
}
};
var vValue = ngModel.$viewValue;
ngModel.$parsers.unshift(function(viewValue) {
var returnValue = viewValue === vValue ? ngModel.$modelValue : viewValue;
ngModel.$setViewValue(returnValue);
ngModel.$render();
vValue = viewValue;
return returnValue;
});
}
};
});
app.run(function($rootScope, $interval) {
$rootScope.item = 'item';
$interval(function(count) {
if (typeof count === 'number') {
if($rootScope.item) {
$rootScope.item = $rootScope.item + '' + count;
}
else {
$rootScope.item = '' + count;
}
console.log($rootScope.item);
}
},3000);
});
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="myApp">
<form name="myForm">
<input
no-updates-when-focused
name="item1"
ng-model="item"
size="50"
required>
</input>
<span ng-show="myForm.item1.$error.required">Required!</span>
</br>
<input
name="item2"
ng-model="item"
size="50"
required>
</input>
<span ng-show="myForm.item2.$error.required">Required!</span>
</form>
</body>
</html>