ユーザーが自分の Google アカウントを介して自分自身を識別できるアプリケーションを作成しています。舞台裏では、gapi を使用してログインを処理しています。一方、ユーザーObservable
の状態(オンライン/オフライン)が変化するたびに加入者に情報をブロードキャストする「ユーザー」と呼ばれる角度のあるサービスがあります。次に、すべてを結合するためにボタンがあり、ユーザーがそれをクリックすると、次のようになります。
- gapi が初期化されると解決される promise が作成されます。(以下のコードの 1 行目)
- promise が解決されると、gapi を介して Google ログインが実行されます。(以下のコードの 2 行目)
- ログインの約束が解決されると、AJAX リクエスト ID がバックエンドに対して行われ、Google トークンが検証され、電子メール、名前などの情報が返され、このオブザーバブルにサブスクライブされます。
this.restService
(以下のコードの で始まる行) - 上記のオブザーバブルが Web サービスによって返された値を発行するとき、ユーザーのステータスのオブザーバブルの値を発行する「ユーザー」サービスの関数を呼び出します (ユーザーが現在認証されているという事実をブロードキャストします)。
- 次に、すべてのサブスクライバーがこの情報を受け取り、ユーザーがログインしていることを認識します。
コードは次のとおりです。
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
});
});
});
問題は、コードが機能する場合と機能しない場合があることです。調査の結果、これは Web サービスの実行時間に関連していることに気付きました。これを確実にするために、リクエストの実行を2秒間一時停止するステートメントを内部に作成しました。その場合、コードは常に失敗します。しかし、「失敗」とはどういう意味ですか?
ページのどこかに、ユーザー サービス オブザーバブルにサブスクライブするコンポーネントがあります。
this.userService.getStatus().subscribe(status => {
console.log(status);
this.canPostComment = (status == UserStatus.Online);
});
Web サービスが非常に高速に実行されると、 が表示されconsole.log
、canPostComment
プロパティが更新され、ビューも更新されるため、問題はありません。ただし、Web サービスに少し時間がかかるconsole.log
と、正しい値が表示されますが、ビューは更新されません...
Angular の変更検出と関係があるのではないかと疑って、次のようにゾーンを使用します。
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.zoneService.run(() => {
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set("data.name", "data.email", "data.picture", AuthenticationType.Google);
});
});
});
});
そして、それは機能します...だから、ゾーンについて読んで、変更検出(またはそのようなもの...)を実行する必要があることをangularに警告するために使用されていることを知りましたが、setTimeout
またはAJAX呼び出しのような一般的な機能も読みましたすでに「ゾーン」によってモンキーパッチが適用されているため、問題がどのように解決されるのかわかりません。また、この問題が発生する理由もわかりません。canPostComment
Angularが変更を認識しないのはなぜですか?
私のコードは少し複雑なので、それを plunkr するのはかなり難しいでしょう。そのため、関連するコードのほとんどをコピーして貼り付けます。
編集
質問した後、ログイン プロセス全体がいつ完了したかを知る必要があったため、コードを少し変更する必要がありました。実際、ユーザーがログイン ボタンをクリックすると、そのキャプションが「Logging in...」になり、プロセス全体が完了すると消えます。オブザーバブルを購読することuserService.getStatus
もできましたが、次のことができるという約束をすることにしました。
this.googleAuthenticationService.login.then(() => { ... });
したがって、上記のコードを次のように更新しました。
return new Promise((resolve, reject) => {
this.ensureApiIsLoaded().then(() => {
this.auth.signIn().then((user) => {
let profile = user.getBasicProfile();
this.zoneService.run(() => {
this.restService
.post("/api/security/authenticate", <IAuthenticationPayload>{ type: AuthenticationType.Google, token: user.getAuthResponse().id_token })
.subscribe((data: IUserData) => {
this.userService.set(data.name, data.email, data.picture, AuthenticationType.Google);
resolve(true)
},
error => reject(false));
});
});
});
});
好奇心から、this.zoneService.run
何が起こるかを確認するためだけにステートメントを削除しようとしましたが、それがなくても機能することがわかりました...すべてを約束に入れると問題が解決するようです...しかし、問題はまだ残っています...なぜ最初の例は機能しませんでしたか?