【问题标题】:Setting $scope.myModel element with ng-change enters in infinite loop使用 ng-change 设置 $scope.myModel 元素进入无限循环
【发布时间】:2015-07-16 20:53:29
【问题描述】:

我对 Angular 很陌生,并试图实现一些“基本”的东西。我在谷歌上搜索了 2 天都没有成功,希望能得到一些帮助。

我有一个 html 页面,我正在尝试:

  1. 使用 HTTP POST 请求初始化数据
  2. 当用作过滤器的元素发生更改(即类别、按 asc/desc 排序...)时,通过 ng-change 事件调用函数以使用另一个 HTTP POST 更新数据

我的问题是,当我使用 HTTP 响应(仅在这种情况下) 以编程方式更新模型时,它会触发附加到元素的 ng-change 事件,该事件本身会调用更新函数,然后进入无限循环: ng-change -> 更新函数 -> ng-change -> 更新函数

注意:我使用的是 Angular Material 模板,但它不会更改代码

HTML

<html ng-app="MyApp">
    <body layout="column" ng-controller="SearchServiceController">
        <h1 class="md-headline">Filter results</h1>
        <form name="searchServiceForm" novalidate>
            <md-input-container>
                <md-select placeholder="Choose category" ng-model="searchService.selectedCategory" ng-change="changedSearchServiceCriteria()">
                    <md-option ng-value="category.value" ng-repeat="category in listOfCategories">{{ category.title }}</md-option>
                </md-select>
             </md-input-container>
             <md-input-container>
                 <md-select placeholder="Sort by" ng-model="searchService.sortBy" ng-change="changedSearchServiceCriteria()">
                     <md-option ng-value="criteria.value" ng-repeat="criteria in sortByCriterias">{{ criteria.title }}</md-option>
                  </md-select>
              </md-input-container>
          </form>
          <h1 class="md-headline">{{ selectedCategory.title }}</h1>
          <p class="md-body-1">{{ selectedCategory.description }}</p>
    </body>
</html>

JS

var app = angular.module('MyApp', ['ngMaterial']);

app.controller('SearchServiceController', function($scope, $http, $location) {
  // Initialize data using the category id parameter in the URL
  $http({
    method: 'POST',
    url: '/projets/get-offerings-list',
    data: {selectedCategory: $location.path().split("/")[4]},
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    })
      .success(function(response) {
        alert('INIT');
        $scope.listOfCategories = response.listOfCategories;
        $scope.sortByCriterias = response.sortByCriterias;
        $scope.searchService = response.searchService;
      })
      .error(function(response) {
        console.log('Failure occured');
      });

  // Update data
  $scope.changedSearchServiceCriteria = function() {
    $http({
    method: 'POST',
    url: '/projets/get-offerings-list',
    data: {selectedCategory: $location.path().split("/")[4]},
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    })
      .success(function(response) {
        alert('UPDATE');
        $scope.listOfCategories = response.listOfCategories;
        $scope.sortByCriterias = response.sortByCriterias;
        $scope.searchService = response.searchService;
      })
      .error(function(response) {
        console.log('Failure occured');
      });
  };
});

结果

INIT
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
UPDATE
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
UPDATE
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
UPDATE
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
UPDATE
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
UPDATE
Object {listOfCategories: Array[3], sortByCriterias: Array[2], searchService: Object}
....infinite loop....

当我以编程方式更新模型而不使用 HTTP 请求的响应时,不会发生这种情况。见这里:http://plnkr.co/edit/baNjr85eAOkKVu4dnf1m?p=preview 您对如何在不引发 ng-change 事件的情况下更新表单元素有任何想法吗?

谢谢

请注意,我不想使用 $watch 这样的解决方法:ngChange is called when model changed programmatically

【问题讨论】:

    标签: angularjs angularjs-scope angularjs-ng-change


    【解决方案1】:

    您应该尝试将工作示例添加到 http://jsfiddle.net/ 或类似内容中。

    我会猜测并且没有测试你需要保留最后一次搜索并且只运行更新 AJAX 请求,如果它每次都获得一个新地址(或在 JS 中调用的任何内容)时发生变化 - 即使它相同的值并再次重新评估

    $scope.searchService = "";
    $scope.lastSearch = ""
    
    // Update data using form elements
    $scope.changedSearch = function() {
    
        if($scope.searchService != $scope.lastSearch){
    
          $http({
            method: 'POST',
            url: '/projects/get-list',
            data: $scope.searchService,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
          })
            .success(function(response) {
                // Request succeeded? Display message
                console.log('UPDATE');
                console.log(response);
                // Update data
                $scope.listOfCategories = response.listOfCategories;
                $scope.sortByCriterias = response.sortByCriterias;
                $scope.searchForm = response.searchForm;
            })
              .error(function(response) {
                // Request failed? Display message
                console.log('Failure occured');
            })
              .complete(function(response) {
                // do after success or error
                $scope.lastSearch = $scope.searchService;
                console.log('complete');
            });
        }
    };
    

    【讨论】:

    • 感谢您的建议。这似乎是一个错误。我会试试的。我添加了一个 Plunker 示例来说明它应该如何工作。我没有添加 Plunker 来说明错误,因为它依赖于 http 请求,并且如果没有远程服务器的链接,我无法在 Plunker 中执行此操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多