2017-03-16 134 views
7

我有一个移动应用程序,我正在构建,现在我正在进行身份验证。在我打开我的主页之前,我需要在我可以向用户显示数据之前在我创建的API上点击各种端点。Angular 2调用多个异步方法

在Postman中测试时,所有端点都返回了正确的数据,但是当我在我的应用中使用它时,我在第二次异步调用中获得了null值。

我确定它与这些调用的顺序有关,所以我只是寻找一些帮助,以便我可以在开始另一个调用之前正确等待一个调用完成。

public login() { 

this.showLoading(); 

this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS 
    .subscribe(
    res => { 
     console.log(res); 
     localStorage.setItem("UserId", res.toString()); 
    }, 
    err => { 
     console.log(err); 
    }); 

this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL 
    .subscribe(
    res => { 
     console.log(res); 
     localStorage.setItem("EmployeeId", res.toString()); 
    }, 
    err => { 
     console.log(err); 
    }); 

this.authService.login(this.registerCredentials) 
    .subscribe(

    data => { 
     this.loading.dismissAll(); 
     console.log('User logged in successfully! ', data); 
     this.nav.push(TabsPage); 
     localStorage.setItem("Username", this.registerCredentials.username); 
     localStorage.setItem("isLoggedIn", "true"); 
    }, 

    error => { 
     this.loading.dismissAll(); 
     this.showAlert("Uh oh!", "Something went wrong. Please re-enter your login credentials or check your connection."); 
     console.log(error); 
    }); 
    } 
+0

标题写着'Angular2'但关键字说'angularjs'。你可以考虑修改其中的一个。 – ConnorsFan

+0

你应该在[这个答案]中找到你需要的东西(http://stackoverflow.com/a/35268597/1009922)。 – ConnorsFan

回答

14

你原来的代码有导致此错误的错误。你在你的代码))三个电话,我会打电话给A,B),并且C:

A) this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS 

B) this.userService.getEmployeeIdFromUserId(localStorage.getItem("UserId")) // THIS RETURNS NULL 

C) this.authService.login(this.registerCredentials) 

您需要了解RXJS之间有什么差异观察,(它代表所需的所有信息到开始一个异步操作)和一个可观察(这是一个可观察到与异步操作已经开始)。

这三个调用A),B)和C)仅仅构建冷的可观察对象,它们在您调用.subscribe()时开始。所以到B)建成时,A)已经开始,但尚未完成。所以对localStorage.getItem("UserId")的调用将返回null,因为A)尚未调用其订户的next回调。

所以你想要做的是让B)等待A)。而不是将东西填入全局状态(localStorage),最好将A)的结果传递给B)。输入.mergeMap()操作:

this.userService.getUserIdFromUserName(this.registerCredentials.username) // WORKS 
    .map(res => res.toString()) 
    .do(userId => localStorage.setItem("UserId", userId)) // cleanly separate side-effects into .do() calls 
    .mergeMap(userId => this.userService.getEmployeeIdFromUserId(userId)) 
    .map(res => res.toString()) 
    .do(employeeId => localStorage.setItem("EmployeeId", employeeId)) 
    .subscribe(
    employeeId => { 
     console.log(employeeId);  
    }, 
    err => { 
     console.log(err); 
    }); 

约rxjs的好处是,错误处理只是工作,一路过关斩将的可观测链。 如果你可以执行C)并行,看看.forkJoin().

最后,如果你需要一双手的.mergeMap()解释看看这个答案:SwitchMap vs MergeMap in the #ngrx example

+0

+1:很好的答案。真的很容易理解和整体非常干净的代码在这里。显然这与你无关,但我希望RxJS运营商有更好的名字。人们希望摆脱'selectMany'(这是一个很好的名字),所以他们用'flatMap'(这也是一个很好的名字)。两者都保留了与藏品的类比。 'mergeMap'什么也不做。它可能在排序方面更具描述性,或者缺乏它们,但是读起来就像故意提供直觉一样命名,但却失败了。他们可能会重命名为“绑定”并完成它。 –

+0

问题:不会是switchmap更好的解决方案吗? (我知道区别,但仍...) –

0

这应该work.Don't忘记import 'rxjs/Rx'

this.userService.getUserIdFromUserName(this.registerCredentials.username) 
    .map(res => res.toString()) 
    .do(userId => { 
     console.log(res); 
     localStorage.setItem("UserId", userId); 
    }) 
    .flatMap(userId => { 
     return this.userService.getEmployeeIdFromUserId(userId); 
    }) 
    .do(res => { 
     console.log(res); 
     localStorage.setItem("EmployeeId", res.toString()); 
    })