Как инициализировать вводимую переменную с помощью службы

Я использую Ionic2 Storage для хранения учетных данных пользователя access_token, когда пользователь входит в систему.

Когда пользователь пытается получить доступ к backend api, мне нужно предоставить access_token клиенту REST.

Я создал службу, используя https://github.com/hboylan/ng2-http Первоначально пакет использует

export class CategoryService extends RESTClient{
    categoryList : Category[] = [];
    public user:User;
    constructor(protected http:Http) {super(http)}
}

Я использовал Angular2 DI, чтобы добавить Компонент UserStorage конструктору:

let categoryServiceFactory = (http:Http, userStorage:UserStorage) => {
    return new CategoryService(http, userStorage);
}
export let categoryServiceProvider = 
{
    provide: CategoryService,
    useFactory: categoryServiceFactory,
    deps: [Http, UserStorage]
}

чтобы получить это:

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

Сейчас, когда я звоню

 @GET('/itemtype/list')
 @Produces<String>()
 public getAvailableCategories(): Observable<String> {
   return null;
 }

Мне нужно использовать

 protected requestInterceptor(req: Request) {
   req.headers.set('Authorization', `Bearer ${this.user.api_credentials.access_token}`)
    return req;
 }

чтобы добавить учетные данные access_token

на данный момент мой вызов в компоненте моей страницы должен выглядеть так:

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

}

Это похоже на то, что я НЕ МОГУ установить пользователя в конструкторе класса CategoryService. Поэтому мне нужно сначала получить пользователя из хранилища, использовать «сеттер» в службе категорий, а затем вложить вызов getAvailableCategories () в функцию getUser (). Then ().

Это потому, что функция getCategories вызывается до того, как конструктор CategoryService завершит настройку пользователя из UserStorage.

Я знаю, что это потому, что вызов является асинхронным, но мне кажется, что использование чего-то вроде setTimeout для «ожидания», пока вызов getUser не вернется, является хакерским и не на 100% надежным.

Есть еще что-нибудь, что я могу попробовать? Я бы очень хотел просто позвонить

this.categoryService.getAvailableCategories().then()

и продолжить оттуда без вложенных вызовов обещаний.

Я готов внести любые разумные изменения, которые сразу же сделают access_token доступным.


person Schwoebel    schedule 13.02.2017    source источник
comment
then(...) означает асинхронный. Вероятно, это просто вопрос времени. Значение еще не доступно, когда вы к нему обращаетесь. Вам необходимо правильно связать все асинхронные вызовы, чтобы получать уведомления (ваш переданный обратный вызов вызывается), когда значение становится доступным.   -  person Günter Zöchbauer    schedule 13.02.2017
comment
Не могли бы вы показать еще немного кода? Как выглядит компонент страницы?   -  person Michał Miszczyszyn    schedule 13.02.2017
comment
@ MichałMiszczyszyn Я добавил в вопрос весь компонент.   -  person Schwoebel    schedule 13.02.2017


Ответы (1)


Если getUser вызов асинхронный, можно попробовать сделать его синхронным :)

Если это не вариант для вас, есть синтаксический сахар, который поможет вам лучше справляться с асинхронными вызовами - 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) },
        () => { }
    );
}

Учтите, что это async ngOnInit, а затем await this.userStorage.getUser()

person Michał Miszczyszyn    schedule 13.02.2017
comment
Мне нравится эта идея, и она решает мои мелкие придирки, но я ищу что-нибудь для использования в CategoryService, поэтому мне не нужно вызывать categoryService.setUser (). Я хотел бы помочь найти решение, чтобы пользовательская переменная CategoryServices была готова в фоновом режиме, пока Angular загружает страницу. - person Schwoebel; 13.02.2017
comment
@Schwoebel Это абсолютно возможно сделать на чистом TypeScript / JavaScript. Просто декораторы hBoylan's ng2-http package явно не допускают асинхронных параметров. Вам следует открыть вопрос на GitHub. - person Michał Miszczyszyn; 13.02.2017
comment
@Schwoebel Был ли мой ответ вам чем-то полезен? - person Michał Miszczyszyn; 29.03.2017