升级到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自动绑定中我的所有简单服务都失败了....任何关于我可能做错的想法。
答案 0 :(得分:41)
1.2.0-rc3有变化,包括你提到的一个:
AngularJS 1.2.0-rc3 凶猛抽搐修复了一些高优先级 $ compile和$ animate中的问题为1.2铺平了道路。 此版本还引入了一些重要的突破更改,在某些情况下可能会破坏您的指令和模板。请 请务必阅读更改日志以了解这些更改并了解 如果需要,如何迁移代码。 有关此版本的完整详细信息,请参阅changelog。
更改日志中有说明:
<强> $解析:强>
答案 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>
...