Нет обновлений ng-модели, когда ввод сфокусирован

Я делаю директиву, которая будет блокировать рендеринг на входе, пока он сфокусирован.

Вариант использования заключается в том, что мы получаем частые оперативные обновления от бэкэнда, и он перезаписывает все, что пользователь пишет на входе, из-за привязки ng-model. Мы отправляем обновление при нажатии на ввод с помощью ng-keydown="($event.keyCode === 13) ? $ctrl.setItem($event, $ctrl.item) : return", где $ctrl.setItem отправит запрос на серверную часть.

Я почти заставил его работать так, как я этого хочу, только я получаю удивительные результаты, когда размываю ввод после редактирования.

Я сделал планкер, в котором имитирую обновления серверной части, используя $interval: 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);
        }
      };
    }
  };
});

Если вы размоете после редактирования в первом поле ввода и подождите несколько секунд для нового «обновления», то модель вернется к состоянию последнего редактирования вида, а не к последнему обновлению модели. Мы всегда хотим показывать последнее обновление из бэкенда, так что это то, что мне нужно исправить, но я в тупике.


person Sammi    schedule 03.07.2016    source источник


Ответы (1)


Хорошо, я понял это. ngModel.$pasers запускались до события размытия. Поэтому я добавил синтаксический анализатор, который игнорирует 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>

person Sammi    schedule 04.07.2016