【问题标题】:Angular js ng-change eventAngular js ng-change 事件
【发布时间】:2014-12-29 21:16:41
【问题描述】:

我在我的应用程序中使用 Angular js。在 ng-change 事件中,我正在调用 webservice 并基于呈现 html 的响应。但是在 ng-change 调用太频繁,我们快速输入导致浏览器等待。这在 chrome 和 Mozilla 中不是问题。有人可以帮我吗?

【问题讨论】:

标签: javascript jquery html angularjs


【解决方案1】:

您可以在调用服务器之前使用超时并等待用户完成输入:

<input type="text" ng-model="some.thing" ng-change="fetchData()" />

app.controller('someCtrl', function ($scope, $timeout) {
    var fetchDataDelay = 500;   // milliseconds
    var fetchDataTimer;

    $scope.fetchData = function () {
        $timeout.cancel(fetchDataTimer);
        fetchDataTimer = $timeout(function () {
            // make expensive call to the server...
        }, fetchDataDelay);
    };
});

请注意,使用 Angular 的 $timeout(而不是 setTimeout/clearTimeout)将为您处理 Angular 摘要循环(因此您不必为手动调用 $apply() 或 $digest() 而烦恼)。

【讨论】:

    【解决方案2】:

    我也遇到了类似的问题,我想实现去抖动搜索。经过一番头撞后,这就是我所做的:

    这是我用 ng-model 指令标记的输入字段

    &lt;input ng-model="searchText" ng-model-options="{ debounce: 500 }" type="text" class="form-control" placeholder="Search..."&gt;

    请注意我还包含了一个 ng-model-options="{ debounce: 500 }"。它以指定的毫秒数消除对基础模型的更新。 请参考 ng-model-options 指令here 的文档。

    现在,我添加了一个像这样的 $watch :

        $scope.$watch('searchText', function(newValue) {
            // expensive ajax call
        });
    

    请参考 $watch here 的文档。它注册一个事件监听器,监听作为其第一个参数传递的表达式的任何变化。在本例中为“searchText”,这是与我的输入字段关联的模型。

    ng-model-options 中提到的 debounce 可以消除对“searchText”模型的更新,因此,它负责消除 ajax 调用(在我的例子中)。

    希望对您有所帮助。 :)

    【讨论】:

    • 这是正确的答案,尽管应该注意 ng-model-options 确实可以与 ng-change 一起使用,因此不需要使用 $watch。 :)
    • 我最喜欢这个答案。
    【解决方案3】:

    您需要使用去抖动模式,大致如下:

    .factory('myFactory', function($http) {
      var debounce;
      var doRequest = function() {
        clearTimeout(debounce);
        setTimeout(function() {
          // Make HTTP call here
        }, 333);
      };
      return {
        doRequest: doRequest
      };
    });
    

    它的作用是在最后一次调用它之后发送请求333毫秒。如果您在每次更改时都调用它,这将在请求之间增加一点间距,从而优化应用程序。

    333 是 Google 用于文本输入的工具,您可以随意使用这些值,看看哪种方法最适合您。

    【讨论】:

    • 你不是每次都在创建一个新变量,然后在这里尝试清除Timeout吗?我认为你应该在这里使用像this.debounce 这样的全局变量。如果我错了,请解释一下。
    • @Mr_Green 你会注意到我使用了一个工厂——变量只会被创建一次。更新澄清,虽然
    • hmm 第一次见..需要研究一下。顺便说一句,我认为您在var doRequest = function() 缺少{。感谢您的解释:)
    【解决方案4】:

    您可以使用$watch 或$watchCollection 来实现直播活动。

    在我的理解和使用中,$watch 和 $watchCollection 比 ng-change 效率低。

    这是一个很好的例子,

    $scope.$watchCollection('[some_modelname,someother_modelname]',function(){
                alert('Changed the input value!');
            });
    $scope.$watch('some_modelname',function(){
                alert('Changed the input value!');
            });
    

    在 HTML 中,

    <input type="text" ng-model="some_modelname" id="someid" name="somenameifneeded" value=""/>
    <input type="text" ng-model="someother_modelname" id="someotherid" name="somenameifneeded" value=""/>
    

    $watch 和 $watchCollection 都会继续查看输入字段是否有任何更改。一旦进行了任何更改,触发器将被调用,这将永远不会消失。希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      在 angularjs 1/3 上,你有 debounce 作为 ng-options 这里是一个例子,所以你可以将它添加到你的 ng-change 中,它会为你管理它

      ng-model-options="{debounce: {'default': 500} }
      

      【讨论】:

      • 这很好,但只会消除模型的抖动。它不会反跳 ng-change
      【解决方案6】:

      您应该使用 debounce 方法 - 当您输入过于频繁时,服务器不应受到影响。当您停止输入并发生超时时,应将请求发送到服务器。您可以使用Underscore Debounce feature 或在此处进行自定义实现:

      $scope.loadData = function () {
         var loadThrottle;
         clearTimeout(loadThrottle);
         loadThrottle = setTimeout(function () {
             $scope.$apply(function () {
                 $scope.getData();
             });
         }, 500);
      };
      

      这里的请求只有在你停止输入并且之后发生 500ms 超时时才会发送。

      另一种实现方式(使用角度化方法):

      $scope.loadData = function(timeout) {
           $scope.counter += 1;
           var counter = $scope.counter;
           $timeout(function(){
               if (counter === $scope.counter) {
                   $scope.getData();
                   $scope.counter = 0;
               }
           }, timeout ? timeout : 500);
      }
      

      另外一种选择是使用更通用的方法和自定义指令和下划线类似的东西:

      app.directive('changeTimeout', function() {
          return {
              require: 'ngModel',
              link: function(scope, element, attrs, ctrl) {
                  angular.forEach(ctrl.$viewChangeListeners, function(listener, index) {
                      ctrl.$viewChangeListeners[index] = _.debounce(function() {
                          scope.$apply(attrs.ngChange);
                      }, attrs.changeTimeout || 0)
                  });
              }
          }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-25
        • 2015-06-06
        • 2017-10-01
        • 1970-01-01
        • 2017-05-16
        • 1970-01-01
        相关资源
        最近更新 更多