在 Observable Subject 上调用 onError 时如何在 angularJs 应用程序中刷新视图
How to refresh view in angularJs app when onError called on Observable Subject
我有一个 AngularJs 应用程序并使用 RXJS。我有一项服务等待用户允许或拒绝访问 OAuth 提供商并具有此签名:
authorise( requestDetails : IRequestDetails ) : Rx.Observable<string>;
当允许访问并且我取回访问令牌时,我将其传回控制器,如下所示:
request.observable.onNext( request.access_token );
request.observable.onCompleted();
并且控制器通过更新消息的支持者变量将其传递回视图:
private _message : string = "Awaiting authorisation";
get message() : string {
return this._message;
}
authenticate() : void
{
this._oAuthService.authorise( Example.googleAuthDetails ).subscribe(
( result : string ) => this.handleAuthorisation( result ),
( fault : string ) => this.handleError( fault )
);
}
private handleAuthorisation( result : string ) : void {
this._message = result;
}
一切正常。我发现它在这种情况下起作用的原因是因为 onNext 调用是作为 $http 调用结果的一部分进行的。此调用包含在触发摘要循环的 $apply 调用中。
但是,当用户拒绝访问时,我会在可观察对象上调用 onError:
request.observable.onError( "access token denied" );
request.observable.onCompleted();
并且在控制器中我用错误更新了字符串:
private handleError( fault : string ) : void {
this._message = fault;
}
但在这种情况下,视图不会更新,显示的字符串仍为 "Awaiting Authorisation"。
在这种情况下,由于授权被拒绝,因此不会进行任何 $http 调用,并且会在未包含在 $apply 调用中的函数中触发控制器。
我已将 rx.angular.js 库包含在我的 html 页面中,希望它会自动修复它,但它没有。阅读文档似乎我可能需要专门看一些东西。我认为我可以让它与 RXJS 一起工作,并在更新时始终更新范围。
如果不需要,我不想将范围注入我的控制器以强制刷新。我不喜欢依赖它。
可以在这个分支中查看整个项目:
https://github.com/Roaders/Typescript-OAuth-SPA/blob/rxjs_issues/index.html
只需将所有内容包装到一个 $timeout 调用中,它将确保调用摘要。
RX.angular 看起来不错,但我认为不在任何地方使用 $scope
的新规范有点过时了。
var myAppModule = angular.module('myApp', []).controller('ctrl', SettingsController1);
function SettingsController1($timeout) {
this.message = "waiting";
this.observable = new Rx.ReplaySubject(2 /* buffer size */ );
var _this = this;
this.observable.subscribe(
function(x) {
$timeout(function() {
_this.message = x;
}, 0);
},
function(err) {
$timeout(function() {
_this.message = err;
}, 0);
},
function() {
this.message = 'completed';
});
this.success = function() {
this.observable.onNext('success');
}
this.error = function() {
this.observable.onError('failed');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl as ctrl">
<div>
{{ ctrl.message }}
</div>
<button ng-click="ctrl.success()">
Success
</button>
<button ng-click="ctrl.error()">
Error
</button>
</div>
这个解决方案在这个分支中实现:https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_timeout
它在错误情况下不起作用的原因是因为没有 http 调用来触发摘要循环,所以我们需要在这种情况下触发摘要循环。
为此,我们需要将 $rootScope 注入到服务中,当我们调用 onError 时,我们需要将其包装在 $rootScope.$apply 调用中:
this._scope.$apply( () => {
request.observable.onError( "access token denied" );
request.observable.onCompleted();
} );
这个解决方案在这里:
https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_scope
我知道我说过我不想注入作用域,但现在我更好地理解了为什么需要注入,我认为我可以接受。我也更乐于注入根作用域,而不是注入不用于任何其他用途的控制器作用域。
我有一个 AngularJs 应用程序并使用 RXJS。我有一项服务等待用户允许或拒绝访问 OAuth 提供商并具有此签名:
authorise( requestDetails : IRequestDetails ) : Rx.Observable<string>;
当允许访问并且我取回访问令牌时,我将其传回控制器,如下所示:
request.observable.onNext( request.access_token );
request.observable.onCompleted();
并且控制器通过更新消息的支持者变量将其传递回视图:
private _message : string = "Awaiting authorisation";
get message() : string {
return this._message;
}
authenticate() : void
{
this._oAuthService.authorise( Example.googleAuthDetails ).subscribe(
( result : string ) => this.handleAuthorisation( result ),
( fault : string ) => this.handleError( fault )
);
}
private handleAuthorisation( result : string ) : void {
this._message = result;
}
一切正常。我发现它在这种情况下起作用的原因是因为 onNext 调用是作为 $http 调用结果的一部分进行的。此调用包含在触发摘要循环的 $apply 调用中。 但是,当用户拒绝访问时,我会在可观察对象上调用 onError:
request.observable.onError( "access token denied" );
request.observable.onCompleted();
并且在控制器中我用错误更新了字符串:
private handleError( fault : string ) : void {
this._message = fault;
}
但在这种情况下,视图不会更新,显示的字符串仍为 "Awaiting Authorisation"。 在这种情况下,由于授权被拒绝,因此不会进行任何 $http 调用,并且会在未包含在 $apply 调用中的函数中触发控制器。
我已将 rx.angular.js 库包含在我的 html 页面中,希望它会自动修复它,但它没有。阅读文档似乎我可能需要专门看一些东西。我认为我可以让它与 RXJS 一起工作,并在更新时始终更新范围。 如果不需要,我不想将范围注入我的控制器以强制刷新。我不喜欢依赖它。
可以在这个分支中查看整个项目:
https://github.com/Roaders/Typescript-OAuth-SPA/blob/rxjs_issues/index.html
只需将所有内容包装到一个 $timeout 调用中,它将确保调用摘要。
RX.angular 看起来不错,但我认为不在任何地方使用 $scope
的新规范有点过时了。
var myAppModule = angular.module('myApp', []).controller('ctrl', SettingsController1);
function SettingsController1($timeout) {
this.message = "waiting";
this.observable = new Rx.ReplaySubject(2 /* buffer size */ );
var _this = this;
this.observable.subscribe(
function(x) {
$timeout(function() {
_this.message = x;
}, 0);
},
function(err) {
$timeout(function() {
_this.message = err;
}, 0);
},
function() {
this.message = 'completed';
});
this.success = function() {
this.observable.onNext('success');
}
this.error = function() {
this.observable.onError('failed');
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl as ctrl">
<div>
{{ ctrl.message }}
</div>
<button ng-click="ctrl.success()">
Success
</button>
<button ng-click="ctrl.error()">
Error
</button>
</div>
这个解决方案在这个分支中实现:https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_timeout
它在错误情况下不起作用的原因是因为没有 http 调用来触发摘要循环,所以我们需要在这种情况下触发摘要循环。
为此,我们需要将 $rootScope 注入到服务中,当我们调用 onError 时,我们需要将其包装在 $rootScope.$apply 调用中:
this._scope.$apply( () => {
request.observable.onError( "access token denied" );
request.observable.onCompleted();
} );
这个解决方案在这里: https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_scope
我知道我说过我不想注入作用域,但现在我更好地理解了为什么需要注入,我认为我可以接受。我也更乐于注入根作用域,而不是注入不用于任何其他用途的控制器作用域。