typescript angular 2 ngIf 可观察?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40977839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:04:07  来源:igfitidea点击:

angular 2 ngIf with observable?

angularasynchronoustypescriptobservable

提问by Kamran Pervaiz

I have a very simple service and its job is to get either 200 or 401 from api/authenticate url.

我有一个非常简单的服务,它的工作是从 api/authenticate url 获取 200 或 401。

auth.service.ts

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);
    }
}

now I want to use this in my html I know I can create a subscriber and based on response or error code set a variable but my problem is I will have to duplicate the code all over the place. I want very simple

现在我想在我的 html 中使用它我知道我可以创建一个订阅者并根据响应或错误代码设置一个变量,但我的问题是我将不得不到处复制代码。我想要很简单

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

If its 401 which is coming from handleError then hide otherwise show the div.

如果它的 401 来自 handleError 则隐藏否则显示 div。

Its like getting boolean value from Observable. I also have AuthGuard.

就像从 Observable 获取布尔值一样。我也有 AuthGuard。

authguard.ts

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;
    }   

}

I cannot use authGuard.canActive() as well in ngIf. Is there any easier way to do it without duplicating code. I am pretty sure AuthGuard is not working as it must return true everytime because subscribe will take time.

我也不能在 ngIf 中使用 authGuard.canActive()。有没有更简单的方法可以在不重复代码的情况下做到这一点。我很确定 AuthGuard 不起作用,因为它每次都必须返回 true,因为订阅需要时间。

app.component.ts

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

主页.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);
    }
}

As you can see alot of duplicated code. I am trying to avoid duplication.

正如你可以看到很多重复的代码。我正在努力避免重复。

When I call my api a pop up appears to enter windows username/password for windows Authentication. I dont get 401 until I cancel that pop up. so I want to hide my menu + home component.

当我调用我的 api 时,会出现一个弹出窗口,输入 Windows 用户名/密码以进行 Windows 身份验证。在我取消弹出窗口之前,我不会收到 401。所以我想隐藏我的菜单 + 主页组件。

In my service I get response:200 in mapand unauthorized:401 in catchblock

在我的服务中,我得到 response:200 in map和未授权:401 in catchblock

回答by Bruno Jo?o

Here, you are returning an observable and not the value:

在这里,您返回的是一个 observable 而不是值:

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

What you should do is create a property in your service and then use this property in your html and not the function that subscribes to the observable. Something like:

你应该做的是在你的服务中创建一个属性,然后在你的 html 中使用这个属性,而不是订阅可观察的函数。就像是:

@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);
    }
}

And then, in your html, just use:

然后,在您的 html 中,只需使用:

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

Another way of doing this is using the asyncpipe. So, the view will wait the observation to return before make digest cicle. Something like:

另一种方法是使用async管道。因此,视图将在制作摘要循环之前等待观察返回。就像是:

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