Angularjs承诺在1.2中不绑定模板

升级到1.2后,由我的服务返回的承诺行为不同…简单的服务myDates:

getDates: function () { var deferred = $q.defer(); $http.get(aGoodURL). success(function (data, status, headers, config) { deferred.resolve(data); // we get to here fine. })...... 

在早期版本中,我可以在我的控制器中做:

 $scope.theDates = myDates.getDates(); 

而getDates返回的promise可以直接绑定到Select元素。 现在这不起作用,我不得不在我的控制器提供一个callback的承诺或数据将不会绑定:

 $scope.theDates = matchDates.getDates(); $scope.theDates.then(function (data) { $scope.theDates = data; // this wasn't necessary in the past 

该文件仍然说:

$ q承诺被模板引擎以angular度识别,这意味着在模板中,您可以将附加到范围的承诺视为结果值。

他们(承诺)在旧版本的Angular工作,但在1.2 RC3自动绑定失败,在我所有的简单服务….任何想法,我可能做错了什么。

1.2.0-rc3有变化,包括你提到的一个:

AngularJS 1.2.0-RC3 凶猛抽搐修复了$ compile和$ animate中的一些高优先级问题,为1.2版铺平了道路。 此版本还介绍了一些重要的突破性更改,在某些情况下可能会破坏您的指令和模板。 请务必阅读更改日志以了解这些更改,并了解如何根据需要迁移您的代码。 有关此版本的完整详细信息,请参阅更新日志 。

在更改日志中有说明:

$parsing:

  • 由于5dc35b52 ,$parsing和模板一般不会再自动解开承诺 。 此function已被弃用,如果绝对需要,它可以通过$parseProvider.unwrapPromises(true) api在过渡期间重新启用。
  • 由于b6a37d11 ,在rc.2中增加了一个function,如果值是承诺(如果允许展开已启用 – 请参阅上一点),则从函数解开返回值,由于打破了常用的使用模式而被还原。

作为@Nenad通知,承诺不再自动解除引用。 这是我所见过的最奇怪的决定之一,因为它悄悄地去除了我依赖的一个function(而这对我来说是一个独特的卖点,而对我来说则是更less的一个)。 所以花了我相当多的时间来解决这个问题。 特别是因为$资源框架似乎仍然正常工作。 最重要的是,这也是一个候选版本。 如果他们真的不得不贬低这一点(这些论据听起来很无力),他们至less可以给他们一个宽限期,在他们悄悄closures之前就有警告。 虽然通常对angular度印象非常深刻,但这是一个很大的负面影响。 如果这个问题真的会得到回复的话,我也不会感到惊讶,尽pipe目前似乎没有什么大声疾呼。

无论如何。 有什么解决scheme?

  • 总是使用then(),并在then方法中分配$ scope

     function Ctrl($scope) { foo().then( function(d) { $scope.d = d; }); ) 
  • 通过展开函数调用该值。 这个函数在promise中返回一个字段,并通过then方法设置这个字段。 因此,只要承诺没有得到解决,它就是不确定的。

     $rootScope.unwrap = function (v) { if (v && v.then) { var p = v; if (!('$$v' in v)) { p.$$v = undefined; p.then(function(val) { p.$$v = val; }); } v = v.$$v; } return v; }; 

    你现在可以称之为:

     Hello {{ unwrap(world) }}. 

    这是从http://plnkr.co/edit/Fn7z3g?p=preview没有与它相关联的名称。;

  • 设置$parseProvider.unwrapPromises(true)并使用消息,您可以使用$parseProvider.logPromiseWarnings(false)closures消息,但最好注意,他们可能会删除以下版本中的function。

感叹,40年来,Smalltalk已经become允许您切换对象引用的消息。 承诺,因为他们本来可以…

更新:

更改我的应用程序后,我发现一个一般的模式工作得很好。

假设我需要对象'x'并且有一些方法可以远程获取这个对象。 然后,我将首先检查一个caching“x”。 如果有一个对象,我将它返回。 如果不存在这样的对象,我创build一个实际的空对象。 不幸的是,这需要你知道这是否将是一个数组或哈希/对象。 我把这个对象放在caching中,以便将来的调用可以使用它。 然后,我开始远程调用,并在callback中复制从创build的对象从远程系统获得的数据。 caching确保对get方法的重复调用不会为同一对象创build大量的远程调用。

  function getX() { var x = cache.get('x'); if ( x == undefined) { cache.put('x', x={}); remote.getX().then( function(d) { angular.copy(d,x); } ); } return x; } 

还有一种select是为get方法提供对象的目的地:

  function getX(scope,name) { remote.getX().then( function(d) { scope[name] = d; } ); } 

你总是可以创build一个Commonangular色服务,并在其中放置一个解包方法,这种方式重现旧承诺的工作方式。 这里是一个示例方法:

 var shared = angular.module("shared"); shared.service("Common", [ function () { // [Unwrap] will return a value to the scope which is automatially updated. For example, // you can pass the second argument an ng-resource call or promise, and when the result comes back // it will update the first argument. You can also pass a function that returns an ng-resource or // promise and it will extend the first argument to contain a new "load()" method which can make the // call again. The first argument should either be an object (like {}) or an array (like []) based on // the expected return value of the promise. // Usage: $scope.reminders = Common.unwrap([], Reminders.query().$promise); // Usage: $scope.reminders = Common.unwrap([], Reminders.query()); // Usage: $scope.reminders = Common.unwrap([], function() { return Reminders.query(); }); // Usage: $scope.reminders.load(); this.unwrap = function(result, func) { if (!result || !func) return result; var then = function(promise) { //see if they sent a resource if ('$promise' in promise) { promise.$promise.then(update); } //see if they sent a promise directly else if ('then' in promise) { promise.then(update); } }; var update = function(data) { if ($.isArray(result)) { //clear result list result.length = 0; //populate result list with data $.each(data, function(i, item) { result.push(item); }); } else { //clear result object for (var prop in result) { if (prop !== 'load') delete result[prop]; } //deep populate result object from data $.extend(true, result, data); } }; //see if they sent a function that returns a promise, or a promise itself if ($.isFunction(func)) { // create load event for reuse result.load = function() { then(func()); }; result.load(); } else { then(func); } return result; }; } ]); 

这基本上工作如何旧承诺做,并自动解决。 但是,如果第二个参数是一个函数,那么添加一个“.load()”方法可以将该值重新加载到作用域中,

 angular.module('site').controller("homeController", function(Common) { $scope.reminders = Common.unwrap([], Reminders.query().$promise); $scope.reminders = Common.unwrap([], Reminders.query()); $scope.reminders = Common.unwrap([], function() { return Reminders.query(); }); function refresh() { $scope.reminders.load(); } }); 

这些是一些很好的答案,并帮助我find我的问题,当我升级angular度和我的诺言自动解包停止工作。

在与彼得·克里恩斯(Peter Kriens)多余的风险之下,我发现这种模式对我来说很有用(这是一个简单的例子,简单地把一些着名的人引用到页面上)。

我的控制器:

 angular.module('myModuleName').controller('welcomeController', function ($scope, myDataServiceUsingResourceOrHttp) { myDataServiceUsingResourceOrHttp.getQuotes(3).then(function (quotes) { $scope.quotes = quotes; }); } ); 

我的页面:

 ... <div class="main-content" ng-controller="welcomeController"> ... <div class="widget-main"> <div class="row" ng-repeat="quote in quotes"> <div class="col-xs-12"> <blockquote class="pull-right"> <p>{{quote.text}}</p> <small>{{quote.source}}</small> </blockquote> </div> </div> </div> ...