web-dev-qa-db-ja.com

Angular2:サービスおよびコンポーネント内で監視可能なHttp.postを適切にサブスクライブする方法は?

JWT認証の場合、Observablesで動作する新しいHttpモジュールを使用して、トークンを取得するためのPOSTリクエストを作成します。

フォームを表示する単純なLoginコンポーネントがあります。

@Component({
selector: 'my-login',
    template: `<form (submit)="submitForm($event)">
                <input [(ngModel)]="cred.username" type="text" required autofocus>
                <input [(ngModel)]="cred.password" type="password" required>
                <button type="submit">Connexion</button>
            </form>`
})
export class LoginComponent {
    private cred: CredentialsModel = new CredentialsModel();

    constructor(public auth: Auth) {}

    submitForm(e: MouseEvent) {
        e.preventDefault();
        this.auth.authentificate(this.cred);
    }
}

リクエストを行うAuthサービスがあります。

@Injectable()
export class Auth {
    constructor(public http: Http) {}

    public authentificate(credentials: CredentialsModel) {
        const headers = new Headers();
        headers.append('Content-Type', 'application/json');

        this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
            .map(res => res.json())
            .subscribe(
                data => this._saveJwt(data.id_token),
                err => console.log(err)
            );
    }
}

正常に動作しますが、コンポーネント内にエラーメッセージを表示したいので、2か所でサブスクライブする必要があります(成功を管理するためのAuthとエラーを管理するためのLogin)。

私はshare演算子を使用してそれを達成しました:

public authentificate(credentials: CredentialsModel) : Observable<Response> {
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    const auth$ = this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
                            .map(res => res.json()).share();

    auth$.subscribe(data => this._saveJwt(data.id_token), () => {});

    return auth$;
}

そしてコンポーネント内:

submitForm(e: MouseEvent) {
    e.preventDefault();
    this.auth.authentificate(this.cred).subscribe(() => {}, (err) => {
        console.log('ERROR component', err);
    });
}

それは動作しますが、私はそれを間違っていると感じています。angular1とpromisesを使用して行った方法を転置するだけですが、それを達成するためのより良い方法がわかりますか?

7
bertrandg

サービスのイベントにサブスクライブして、対応するオブザーバブルのみを返すことができます。

public authentificate(credentials: CredentialsModel) {
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    var obs = this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
        .map(res => res.json())
        .subscribe(
            data => this._saveJwt(data.id_token)
        );

    return obs;
}

エラーが発生した場合は、catch演算子を使用してエラーをキャッチできます。

submitForm(e: MouseEvent) {
  e.preventDefault();
  this.auth.authentificate(this.cred).catch((err) => {
    console.log('ERROR component', err);
  });
}

編集

オブザーバブルを2回サブスクライブしたい場合は、shareメソッドを呼び出して、それを「ホット」にする必要があります。

do演算子を利用して、コンポーネントでのみサブスクライブすることもできます。

public authentificate(credentials: CredentialsModel) {
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    return this.http.post(config.LOGIN_URL, JSON.stringify(credentials), {headers})
        .map(res => res.json())
        .do(
            data => this._saveJwt(data.id_token)
        );
}
2