2017-02-13 15 views
0

Я использую Ionic2 хранение для хранения пользовательского access_token учетных данных при входе пользователя в системе.Как инициализировать инъекционные переменный с помощью службы

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

Я создал службу, используя hBoylan's ng2-http package Первоначально пакет использует

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

Cur rently, когда я называю

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

} 

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

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

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

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

this.categoryService.getAvailableCategories().then() 

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

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

+0

'то (...)' означает асинхр. Вероятно, это вопрос времени. Значение доступно еще при доступе к нему. Вам нужно правильно связать все асинхронные вызовы, чтобы получить «уведомление» (ваш обратный вызов будет вызван), когда значение станет доступным. –

+0

Можете ли вы показать немного больше кода? Как выглядит компонент страницы? –

+1

@ MichałMiszczyszyn Я добавил весь компонент к вопросу. – Schwoebel

ответ

0

Если 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()

+0

Мне нравится эта идея, и она решает мою nesting nitpicking, но я ищу что-то для использования в CategoryService, поэтому мне не нужно вызывать categoryService.setUser(). Я бы хотел помочь найти решение, поэтому пользовательская переменная CategoryServices будет подготовлена ​​в фоновом режиме, а Angular загрузит страницу. – Schwoebel

+0

@Schwoebel Это абсолютно возможно сделать в чистом TypeScript/JavaScript. Это просто, что декодеры 'hBoylan's ng2-http pack', по-видимому, не позволяют асинхронные параметры. Вы должны открыть проблему в GitHub. –

+0

@Schwoebel Был ли мой ответ полезным для вас каким-либо образом? –