web-dev-qa-db-ja.com

angular 2 ngIf with observable?

私は非常にシンプルなサービスを持っており、その仕事はapi/authenticateurlから200または401を取得することです。

auth.service.ts

@Injectable()
export class AuthService {

    constructor(private http: Http) {

    }

    authenticateUser(): Observable<any> {
        return this.http.get(AppSettings.authenitcationEnpoint)
            .map(this.extractData)
            .catch(this.handleError);
    }

    private extractData(response: Response) {
        let body = response;
        return body || {};
    }

    private handleError(error: Response) {
        let errMsg: string;
        if (error instanceof Response) {
            errMsg = `${error.status} - ${error.statusText || ''}`;
        } else {
            errMsg = error.toString();
        }
        return Observable.throw(errMsg);
    }
}

これをHTMLで使用したいのですが、サブスクライバーを作成でき、応答またはエラーコードに基づいて変数を設定できますが、問題は、コードをあちこちに複製する必要があることです。とてもシンプルにしたい

<div *ngIf="authService.AuthenticateUser()">my content</div>

HandleErrorから来ている401の場合は非表示にし、そうでない場合はdivを表示します。

Observableからブール値を取得するようなものです。 AuthGuardもあります。

authguard.ts

@Injectable()
export class AuthGuard implements CanActivate {

    private isActive: boolean = true;
    constructor(private authService: AuthService, private router: Router) {
    }

    canActivate(): boolean {
        this.authService.authenticateUser()
            .subscribe(() => {},
            error => {
                if (error.indexOf("401") >= 0) {
                    let link = ['contactus'];
                    this.router.navigate(link);
                    this.isActive = false;
                }
            });
        return this.isActive;
    }   

}

NgIfでもauthGuard.canActive()を使用できません。コードを複製せずにそれを行う簡単な方法はありますか?サブスクライブには時間がかかるため、AuthGuardは毎回trueを返す必要があるため、AuthGuardが機能していないことは間違いありません。

app.component.ts

export class AppComponent {
    private isAuthenticated: boolean = false;

    constructor(private authService: AuthService,private authGuard: AuthGuard) {
        this.authService.authenticateUser()
            .subscribe(response => {
                if (response.status == 200)
                    this.isAuthenticated = true;
            },
            error => {
                if (error.indexOf("401") >= 0)
                    this.isAuthenticated = false;
            });
    }
}

home.component.ts

export class HomeComponent implements OnInit {

    constructor(private http: Http, private authService: AuthService, private utilityService: UtilityService, private homeService: HomeService, private factoryService: FactoryService, private supplierService: SupplierService, private businessAreaService: BusinessAreaService, private router: Router) {
        this.authService.authenticateUser()
            .subscribe(response => {
                if (response.status == 200)
                    this.isAuthenticated = true;
            },
            error => {
                if (error.indexOf("401") >= 0)
                    this.isAuthenticated = false;
            });
        this.customData = new CustomData(http);
    }
}

ご覧のとおり、重複したコードがたくさんあります。重複を避けようとしています。

APIを呼び出すと、Windows認証用のWindowsユーザー名/パスワードを入力するポップアップが表示されます。そのポップアップをキャンセルするまで、401を取得しません。メニューとホームコンポーネントを非表示にします。

私のサービスでは、応答:200 in mapおよびauthorized:401 in catch blockを取得します

5
Kamran Pervaiz

ここでは、値ではなく、オブザーバブルを返しています。

authenticateUser(): Observable<any> {
    return this.http.get(AppSettings.authenitcationEnpoint)
        .map(this.extractData)
        .catch(this.handleError);
}

あなたがすべきことは、あなたのサービスでプロパティを作成し、そしてあなたのhtmlでこのプロパティを使用することであり、observableをサブスクライブする関数ではありません。何かのようなもの:

@Injectable()
export class AuthService {

    isAuthenticated: boolean = false; //The variable

    constructor(private http: Http) {
    }

    authenticateUser(): Observable<any> {
        return this.http.get(AppSettings.authenitcationEnpoint)
            .map(this.extractData)
            .catch(this.handleError);
    }

    private extractData(response: Response) {
        let body = response;
        this.isAuthenticated = body.isAuthenticated; //here you assign a value to variable
        return body || {};
    }

    private handleError(error: Response) {
        let errMsg: string;
        if (error instanceof Response) {
            errMsg = `${error.status} - ${error.statusText || ''}`;
        } else {
            errMsg = error.toString();
        }
        return Observable.throw(errMsg);
    }
}

そして、あなたのhtmlで、ただ使用してください:

<div *ngIf="authService.isAuthenticated">my content</div>

これを行う別の方法は、asyncパイプを使用することです。したがって、ビューは、ダイジェストシクルを作成する前に観測が戻るのを待ちます。何かのようなもの:

<div *ngIf="authService.AuthenticateUser() | async">my content</div> // Here you use the async pipe
10
Bruno João