I am using Ionic2 Storage to store user access_token credentials when a user logs in.
When the user tries to access a backend api I need to supply the access_token to a REST client.
I have created service using hBoylan's ng2-http package Initially the package uses
export class CategoryService extends RESTClient{
categoryList : Category[] = [];
public user:User;
constructor(protected http:Http) {super(http)}
}
I have used Angular2 DI to add a UserStorage component to the constructor:
let categoryServiceFactory = (http:Http, userStorage:UserStorage) => {
return new CategoryService(http, userStorage);
}
export let categoryServiceProvider =
{
provide: CategoryService,
useFactory: categoryServiceFactory,
deps: [Http, UserStorage]
}
to get this:
export class CategoryService extends RESTClient{
categoryList : Category[] = [];
public user:User;
constructor(protected http: Http, protected userStorage: UserStorage)
{
super(http);
this.userStorage.getUser().then((data:User) => {this.user = data})
}
Currently when I call
@GET('/itemtype/list')
@Produces<String>()
public getAvailableCategories(): Observable<String> {
return null;
}
I need to use
protected requestInterceptor(req: Request) {
req.headers.set('Authorization', `Bearer ${this.user.api_credentials.access_token}`)
return req;
}
to add the access_token credential
as of right now my call in my page component has to look like this:
@Component({
selector: 'page-categories',
templateUrl: 'categories.html',
providers: [User]
})
export class CategoriesPage implements OnInit {
// list of categories
public categories: any;
constructor(public nav: NavController,
public categoryService: CategoryService,
public userStorage: UserStorage,
public user: User) {}
ngOnInit() {
this.userStorage.getUser().then((user: User) => {
this.user = user
this.categoryService.setUser(this.user);
this.categoryService.getAvailableCategories().subscribe(
(data) => { console.log(data) },
error => console.log(error),
() => { });
});
}
// view category
viewCategory(categoryId) {
this.nav.push(CategoryPage, { id: categoryId });
}
showChildren(category: Category) {
category.open = !category.open;
}
openCategoryPage($event, category: Category) {
$event.stopPropagation();
this.nav.push(CategoryPage, { cat_id: category.id })
}
}
The reason it looks like that is because I CANNOT seem to set the user in the constructor of the CategoryService class. So I have to first get the User from storage, use a "setter" in the category service and then nest the getAvailableCategories() call inside of the getUser().then() function.
That is because the getCategories function is called before the CategoryService constructor is done setting the user from UserStorage.
I know this is because the call is asynchronous but I feel as though using something like setTimeout to "wait" until the getUser call has returned is hacky and not 100% dependable.
Is there anything else I can try? I would really like to just call
this.categoryService.getAvailableCategories().then()
and be continue on from there without the nested promise calls.
I am up for making any savvy changes that would make the access_token available right away.
If getUser
call is asynchronous, you can try making it synchronous :)
If that's not an option for you, there's a syntax sugar which will help you deal with async calls in a nicer way – async/await
:
async ngOnInit() {
this.categories = this.categoryService.getCategories();
this.user = await this.userStorage.getUser();
this.categoryService.setUser(this.user);
this.categoryService.getAvailableCategories().subscribe(
(data) => { console.log(data) },
(error) => { console.log(error) },
() => { }
);
}
Mind that it's async ngOnInit
and then await this.userStorage.getUser()