Наблюдатель «спит», когда загрузка данных занимает некоторое время - PullRequest
0 голосов
/ 21 февраля 2020

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

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

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

Вот мой код

angular.module('app',[])

.controller('mainCtrl', function($timeout) {
  var vm = this;
  vm.tab = 1;
  
  //fake async call
  $timeout(function() {
    vm.text = 'fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r ';
  }, 1500);
})

.directive('autoResize', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function autoResizeLink(scope, element, attrs, ngModel) {
      scope.$watch(function() {
          console.log('listen');
          if((ngModel.$viewValue || ngModel.$modelValue) && element[0].scrollHeight > 0) {
              console.log('view value appeared', ngModel.$viewValue);
              console.log('element[0].scrollHeight',element[0].scrollHeight);

              element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
              element.css('height', element[0].scrollHeight + 'px');

              console.log('stop listening here');
          }
      });

      element.on('input', function () {
          element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
          element.css('height', element[0].scrollHeight + 'px');

      });
    }
  }
});
a {
  text-decoration: underline;
  color: blue;
  cursor: pointer;
}
<html ng-app="app">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
  </head>
  
  <body>
    <div ng-controller="mainCtrl as vm">
 
      <a ng-click="vm.tab = 1">Tab 1</a>
      <a ng-click="vm.tab = 2">Tab 2</a>
      
      <div ng-show="vm.tab === 2">
         <textarea auto-resize ng-model="vm.text"></textarea>
      </div>
    </div>
  </body>
</html>

1 Ответ

0 голосов
/ 21 февраля 2020

Наблюдатели оценивают свое выражение наблюдения только при наличии пользовательских событий или событий инфраструктуры, таких как данные, поступающие с сервера. То, что вы называете «спящим», является нормальным поведением для AngularJS фреймворка.

Вместо использования наблюдателя используйте $ форматеры и $ viewChangeListeners конвейеры:

app.directive('autoResize', function($timeout) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function autoResizeLink(scope, element, attrs, ngModel) {
      ngModel.$formatters.push(function(data) {
          $timeout(resize);
          return data;
      });

      ngModel.$viewChangeListeners.push(function() {
          $timeout(resize);
      });

      function resize() {
          console.log("resize");
          element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
          element.css('height', element[0].scrollHeight + 'px');
      }
    }
  }
});

ngModelController вызывает функции $ formatters , когда получает новые значения модели из каркаса. Он вызывает $ viewChangeListeners , когда получает новые значения от пользователя.

THE DEMO

angular.module('app',[])

.controller('mainCtrl', function($timeout) {
  var vm = this;
  vm.tab = 1;
  
  //fake async call
  $timeout(function() {
    console.log("data");
    vm.text = 'fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r fsafsafsafasfsa \r ';
  }, 1500);
})

.directive('autoResize', function($timeout) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function autoResizeLink(scope, element, attrs, ngModel) {
      ngModel.$formatters.push(function(data) {
          $timeout(resize);
          return data;
      });

      ngModel.$viewChangeListeners.push(function() {
          $timeout(resize);
      });

      function resize() {
          console.log("resize");
          element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
          element.css('height', element[0].scrollHeight + 'px');
      }
    }
  }
});
a {
  text-decoration: underline;
  color: blue;
  cursor: pointer;
}
<html ng-app="app">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
  </head>
  
  <body>
    <div ng-controller="mainCtrl as vm">
 
      <a ng-click="vm.tab = 1">Tab 1</a>
      <a ng-click="vm.tab = 2">Tab 2</a>
      
      <div ng-if="vm.tab === 2">
         <textarea auto-resize ng-model="vm.text"></textarea>
      </div>
    </div>
  </body>
</html>
...