Angularjs承诺在1.2中不绑定模板

时间:2013-10-19 22:51:32

标签: angularjs

升级到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元素。 现在这不起作用,我被迫在我的控制器中提供对promise的回调,或者数据不会绑定:

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

文档仍然说:

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

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

4 个答案:

答案 0 :(得分:41)

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

  

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

更改日志中有说明:

  

<强> $解析:

     
      
  • 由于5dc35b52,$ parse和模板一般会不再自动解包承诺。此功能已被弃用   如果绝对需要,可以在过渡期间重新启用   通过$parseProvider.unwrapPromises(true) api。
  •   
  • 由于b6a37d11,在rc.2中添加了一个功能,如果值是promises,则会从函数中返回值(如果promise unwrapping是   启用 - 请参阅上一点),由于打破流行而被恢复   使用模式。
  •   

答案 1 :(得分:22)

在@Nenad通知中,承诺不再自动解除引用。这是我见过的最离奇的决定之一,因为它默默地删除了我依赖的功能(这对我来说是一个独特的角度卖点,少即是多)。因此我花了很多时间才弄明白这一点。特别是因为$ resource框架似乎仍然可以正常工作。除此之外,这也是一个候选版本。如果他们真的不得不弃用这个(这些论点听起来非常虚弱),他们至少可以给出一个宽限期,在他们默默关闭它之前会有警告。虽然通常对角度印象非常深刻,但这是一个很大的减号。如果这实际上将被还原,我不会感到惊讶,尽管到目前为止似乎没有相对较少的抗议。

反正。有什么解决方案?

  • 始终使用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)关闭的消息,但最好注意他们可能会删除以下版本中的功能。

叹了口气,40年来,Smalltalk发布了become消息,允许您切换对象引用。承诺,因为他们本来可以......

更新:

更改我的应用程序后,我发现了一个非常好用的一般模式。

假设我需要对象'x'并且有一些方法可以远程获取此对象。然后我将首先检查缓存中的'x'。如果有物体,我会把它归还。如果不存在这样的对象,我创建一个实际的空对象。不幸的是,这需要您知道这是一个数组还是一个哈希/对象。我将此对象放在缓存中,以便将来的调用可以使用它。然后我启动远程调用,在回调中,我复制从创建的对象中的远程系统获得的数据。缓存确保重复调用get方法不会为同一对象创建大量远程调用。

 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;
 }

另一种方法是为get方法提供对象的目标:

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

答案 2 :(得分:2)

您总是可以创建一个公共角度服务,并在其中放置一个解包方法,以重新创建旧承诺的工作方式。这是一个示例方法:

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();
    }
});

答案 3 :(得分:0)

这些是一些很好的答案,并帮助我找到我的问题,当我升级角度和我的自动解缠的承诺停止工作。

冒着被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>
...