angular $http promise 调用包装在 rxjs Observable 中时如何刷新视图
How to refresh the view when angular $http promise call wrapped in rxjs Observable
我有一个项目使用 angular 的 $http 服务从远程位置加载数据。我想使用 rxjs Observables,所以我的服务中的调用如下所示:
userInfo() : Rx.Observable<IUserInfo> {
var url : string = someUrl + this._accessToken;
return Rx.Observable.fromPromise<IUserInfo>( this.$http.get<IUserInfo>( url ) );
}
我的控制器是这样订阅的:
getUserInfo() : void {
this._googleService.userInfo().subscribe(
( result ) => { this.handleUserInfo( result ) },
( fault : string ) => this.handleError( fault )
)
}
private handleUserInfo( result : IHttpPromiseCallbackArg<IUserInfo> ) : void {
console.log( "User info received at " + new Date() );
this._name = result.data.given_name + " " + result.data.family_name;
this._email = result.data.email;
this._profilePicUrl = result.data.picture;
}
问题是尽管更新了姓名、电子邮件和个人资料照片,但这些更改是不可见的。一旦其他任何东西触发 angular $apply,更改就会出现,但是由于 Observable,控制器中的这些更改发生在 $http 调用触发的 angular 摘要循环之后。
如果我的服务只是 returns 对控制器的承诺,这确实可以正常工作。
在这种情况下如何更新我的视图?我不想手动连接每个可观察对象来触发摘要周期。我希望所有 Observables 在收到新值或错误时触发摘要循环。
为此,我们可以使用 rx.angular.js 中的 ScopeScheduler。我们只需要创建一个新模块,在其中创建 angular 模块并将 $rootScope 传递给它:
const module : ng.IModule = angular.module( 'moduleName', [] );
module.run( ["$rootScope", ( $rootScope ) => {
new Rx.ScopeScheduler( $rootScope );
}]);
这就是您要做的全部。现在所有 Rx.Observables 在获得新值时都会触发 $apply。
由于某些原因,当 rx.angular.js 库升级到 rxjs 版本 4 时,ScopeScheduler 被删除了。我们必须使用 rx.angular.js 版本 0.0.14 才能使用 ScopeScheduler。
我不知道版本 4 中建议的解决方案是什么。
可以在此处查看使用此修复程序的项目:
https://github.com/Roaders/Typescript-OAuth-SPA/tree/observable_apply_issues
我无法让 Rx.ScopeScheduler 方法工作,所以我只是改写了 rx 可观察订阅方法本身,并将回调包装在 $rootScope.$apply :)
module.run(['$rootScope', 'rx', function ($rootScope, rx) {
rx.Observable.prototype.subscribe = function (n, e, c) {
if(typeof n === 'object') {
return this._subscribe(n);
}
var onNext = function(){};
if(n) {
onNext = function(value) {
if($rootScope.$$phase) {
n(value);
}
else {
$rootScope.$apply(function(){ n(value); });
}
};
}
var onError = function(err) { throw err; };
if(e) {
onError = function(error) {
if($rootScope.$$phase) {
e(error);
}
else {
$rootScope.$apply(function(){ e(error); });
}
};
}
var onCompleted = function(){};
if(c) {
onCompleted = function() {
if($rootScope.$$phase) {
c();
}
else {
$rootScope.$apply(function(){ c(); });
}
};
}
return this._subscribe(
new rx.AnonymousObserver(onNext, onError, onCompleted)
);
};
}]);
我有一个项目使用 angular 的 $http 服务从远程位置加载数据。我想使用 rxjs Observables,所以我的服务中的调用如下所示:
userInfo() : Rx.Observable<IUserInfo> {
var url : string = someUrl + this._accessToken;
return Rx.Observable.fromPromise<IUserInfo>( this.$http.get<IUserInfo>( url ) );
}
我的控制器是这样订阅的:
getUserInfo() : void {
this._googleService.userInfo().subscribe(
( result ) => { this.handleUserInfo( result ) },
( fault : string ) => this.handleError( fault )
)
}
private handleUserInfo( result : IHttpPromiseCallbackArg<IUserInfo> ) : void {
console.log( "User info received at " + new Date() );
this._name = result.data.given_name + " " + result.data.family_name;
this._email = result.data.email;
this._profilePicUrl = result.data.picture;
}
问题是尽管更新了姓名、电子邮件和个人资料照片,但这些更改是不可见的。一旦其他任何东西触发 angular $apply,更改就会出现,但是由于 Observable,控制器中的这些更改发生在 $http 调用触发的 angular 摘要循环之后。 如果我的服务只是 returns 对控制器的承诺,这确实可以正常工作。
在这种情况下如何更新我的视图?我不想手动连接每个可观察对象来触发摘要周期。我希望所有 Observables 在收到新值或错误时触发摘要循环。
为此,我们可以使用 rx.angular.js 中的 ScopeScheduler。我们只需要创建一个新模块,在其中创建 angular 模块并将 $rootScope 传递给它:
const module : ng.IModule = angular.module( 'moduleName', [] );
module.run( ["$rootScope", ( $rootScope ) => {
new Rx.ScopeScheduler( $rootScope );
}]);
这就是您要做的全部。现在所有 Rx.Observables 在获得新值时都会触发 $apply。
由于某些原因,当 rx.angular.js 库升级到 rxjs 版本 4 时,ScopeScheduler 被删除了。我们必须使用 rx.angular.js 版本 0.0.14 才能使用 ScopeScheduler。
我不知道版本 4 中建议的解决方案是什么。
可以在此处查看使用此修复程序的项目:
https://github.com/Roaders/Typescript-OAuth-SPA/tree/observable_apply_issues
我无法让 Rx.ScopeScheduler 方法工作,所以我只是改写了 rx 可观察订阅方法本身,并将回调包装在 $rootScope.$apply :)
module.run(['$rootScope', 'rx', function ($rootScope, rx) {
rx.Observable.prototype.subscribe = function (n, e, c) {
if(typeof n === 'object') {
return this._subscribe(n);
}
var onNext = function(){};
if(n) {
onNext = function(value) {
if($rootScope.$$phase) {
n(value);
}
else {
$rootScope.$apply(function(){ n(value); });
}
};
}
var onError = function(err) { throw err; };
if(e) {
onError = function(error) {
if($rootScope.$$phase) {
e(error);
}
else {
$rootScope.$apply(function(){ e(error); });
}
};
}
var onCompleted = function(){};
if(c) {
onCompleted = function() {
if($rootScope.$$phase) {
c();
}
else {
$rootScope.$apply(function(){ c(); });
}
};
}
return this._subscribe(
new rx.AnonymousObserver(onNext, onError, onCompleted)
);
};
}]);