【问题标题】:Angular ng-repeat view does not update after a search搜索后角度 ng-repeat 视图不会更新
【发布时间】:2014-06-29 18:49:19
【问题描述】:

我正在尝试使用服务调用来更新结果数组,然后在 ng-repeat 中使用该数组。在提交表单时,我调用必要的服务并通过 promise 对象上的 .then() 连接我的回调。不幸的是,只有在我开始从文本输入中删除字符时,视图才会更新。然后它会显示正确的结果。

这是我的看法:

<div id="main" ng-controller="SearchController as searchCtrl">
        <div class="header" >
            <h1>Search and Add Tracks</h1>
        </div>
        <!--Search Bar-->
        <form class="pure-form pure-g" novalidate ng-submit="searchCtrl.search()">
            <div class="pure-u-1">
                <input class="pure-input-1" type="search" placeholder="Search for tracks" ng-model="searchCtrl.query">
            </div> 
        </form>
        <!--Search Results Table-->
        <div class="pure-u-1" >
            {{searchCtrl.results.length}}
            <div ng-repeat="track in searchCtrl.results" ng-include src="'templates/single-track-view.html'" >
            </div>
        </div>
    </div>

还有我的控制器代码:

app.controller('SearchController',function(){
    var searchCtrl = this;
    searchCtrl.results = [];
    searchCtrl.query = '';

    this.search = function(query){
        console.log(searchCtrl.query);
        var processTracks = function(results){
            console.log(results);
            searchCtrl.results = results[0].tracks;
            searchCtrl.results.push(results[1].tracks);
            searchCtrl.query = '';
            return results;
        }
        //search takes a DICTIONARY not a pure string
        mopidy.library.search({"any": searchCtrl.query}).then(processTracks,console.error.bind(console));
    }

});

当使用 AngularJS 检查器时,我绝对可以看到 searchCtrl.results 在范围内更新,结果正确。在我开始删除字符之前,视图不会更新。

编辑:从承诺返回的结果实际上是一个响应数组。我正在从 Mopidy(音乐播放器)调用 api,数组是来自不同音乐提供者的不同响应。

【问题讨论】:

  • processTracks中尝试$scope.apply(),你可以将$scope注入你的控制器
  • 我认为您需要在承诺中查看$scope.$apply()
  • @IanBrindley 这实际上不是必需的 - 您可以吸收承诺。写一个答案。

标签: javascript angularjs promise


【解决方案1】:

调用$scope.$apply 是有风险的,但摘要循环确实是问题所在。

正确的做法是通过调用 $q.when 将调用同化到 Angular 中:

app.controller('SearchController',function($q){ // note the $q here for promises
    var searchCtrl = this;
    searchCtrl.results = [];
    searchCtrl.query = '';

    this.search = function(query){
        console.log(searchCtrl.query);
        var processTracks = function(results){
            console.log(results);
            searchCtrl.results = results[0].tracks;
            searchCtrl.results.push(results[1].tracks);
            searchCtrl.query = '';
            return results;
        }
        //$q.when assimilates a third party promise into Angular
        $q.when(mopidy.library.search({"any": searchCtrl.query}))
        .then(processTracks,console.error.bind(console));
    }

});

但是为什么它会起作用呢? $q 是什么?

如果我们仔细查看代码,我们会注意到.then

.then 是一个承诺 - 对并发的抽象表示 API 调用的值现已准备就绪。

Promise 库,至少不错的库运行在名为 "Promises/A+" 的规范上,该规范告诉它们如何相互交互 - 所以 Angular 的 promise 库 - $q - 可以无缝地使用 mopidy.library 承诺。

Angular 的 $q 承诺是 hooked directly into the digest loop,因此将第三方承诺转换为 Angular 会使其与摘要循环同步运行,而不是强制自己进行第二次摘要。

【讨论】:

  • 哦,它有效!为什么它会起作用?为什么这比在原始电话中调用 .then 更好? $q by us here 是什么意思?
  • 好问题。 then 是一个承诺库,表示值已准备就绪。 Promise 库,至少不错的库运行在名为 "Promises/A+" 的规范上,该规范告诉它们如何相互交互 - 所以 Angular 的 Promise 库 - $q - 可以无缝地使用 mopidy.library 承诺。 Angular 的 $q 承诺直接挂钩到摘要循环中(请参阅stackoverflow.com/questions/23363014),因此将第三方承诺转换为 Angular 使其与摘要循环同步运行,而不是自己强制进行第二次摘要。
  • 哦,有道理。那么将 Promise 包装在 Angular Promise 中总是好的做法吗?
  • 是的。如果它重复很多——那么你可以把它变成一个方法,在你自己的 .then 调用中吸收它们也是安全的(例如,直接从链接到 $http 调用的 then 返回该承诺,然后将.then 就可以了。就我个人而言,我避免使用 $q 并使用 Bluebird,因为它是一个更快的 Promise 实现并且更容易调试 - stackoverflow.com/q/23984471/1348195
【解决方案2】:

除非你的 track 属性是一个数组,否则这是没有意义的

      searchCtrl.results = results[0].tracks;
      searchCtrl.results.push(results[1].tracks);

如果它是一个数组,您将通过重新定义它来破坏 ng-repeat 和观察变量之间的链接。如果 mopidy 是一个外部库,您将需要在更新结果变量后应用您的更改

【讨论】:

    【解决方案3】:

    正如其他人指出的那样,这里的解决方案是致电$scope.$apply();

    原因: 当您制作 XHR 时,它超出了 Angular 的常规摘要周期,即当它更新所有侦听器以进行双向数据绑定时。调用 $apply 会强制执行摘要,以便更新所有侦听模型。

    Per angular docs on $apply

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-09
      • 2023-03-23
      • 2015-03-18
      • 2020-12-17
      • 2015-03-02
      • 2016-04-20
      • 1970-01-01
      • 2018-04-02
      相关资源
      最近更新 更多