2016-12-18 1 views
0

Я новичок в Angular2, и я пытаюсь выяснить шаблон проектирования для родительских и дочерних компонентов для выполнения действий при изменении атрибута в службе, эта услуга доступна глобально (объявлена в app.component.ts в атрибуте providers). Я использую:Angular2 наблюдать за атрибутом в службе для изменений

  • Угловые 2,2,1
  • rxjs 5.0.0-beta.12
  • машинопись 2.2.1

В основном услуга подключается к удаленному API, и этот API требует аутентификации маркера. Служба имеет общедоступные функции login() и logout(). Первый обращается к API, а затем устанавливает частный атрибут token в строку токена (если действует логин) или '' (если недействительный логин). Все остальные публичные функции, которые вызывают вызовы API, используют этот закрытый токен.

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

Сервис (упрощенный)

import { Injectable } from '@angular/core'; 
import { Http, Response, Headers, URLSearchParams } from '@angular/http'; 
import {Observable, Subject} from 'rxjs/Rx'; 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/operator/map'; 

@Injectable() 
export class ApiService { 
    private url:string = 'my.service.com/'; 
    private username: string; 
    private password: string; 
    private token: string; 

    constructor (private http: Http) {} 

    public getUsername(): string { 
    return this.username; 
    } 

    public setUsername(username: string) { 
    this.username = username; 
    } 

    public getPassword(): string { 
    return this.password; 
    } 

    public setPassword(password: string) { 
    this.password = password; 
    } 

    private setToken(token: string) { 
    this.token = token; 
    } 

    public login() { 
    let headers = new Headers({ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let urlSearchParams = new URLSearchParams(); 
    urlSearchParams.append('username', this.username); 
    urlSearchParams.append('password', this.password); 
    let body = urlSearchParams.toString(); 
    let url = this.url + 'user/login'; 
    this.http.post(url, body, {headers: headers}) 
     .map(res => {this.setToken(typeof res['token'] !== 'undefined' ? res['token'] : '');}); 
    } 

    public logout() { 
    this.setToken(''); 
    } 

    public getData() { 
    let headers = new Headers({ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let urlSearchParams = new URLSearchParams(); 
    urlSearchParams.append('token', this.token); 
    let body = urlSearchParams.toString(); 
    let url = this.url + 'data'; 
    return this.http.get(url, body, {headers: headers}) 
     .map(res => res.json()); 
    } 

app.component.ts

import { Component, ViewEncapsulation } from '@angular/core'; 
import { ApiService } from './services/api'; 

@Component({ 
    selector: 'app', 
    encapsulation: ViewEncapsulation.None, 
    styleUrls: ['./app.component.global.scss'], 
    templateUrl: './app.component.html', 
    providers: [ApiService] 
}) 

export class AppComponent { 
    constructor(private apiService: ApiService) {} 
} 

ребенок компонент

import { Component } from '@angular/core'; 
import { ApiService } from '../services/api'; 

@Component({ 
    selector: 'child-component', 
    styleUrls: ['./child-component.component.scss'], 
    templateUrl: './child-component.component.html' 
}) 

export class ChildComponent { 
    data: any[]; 
    constructor(private apiService: ApiService) {} 
} 

Как Я получаю компоненты (например, ChildComponent для наблюдения за состоянием частного атрибута token в ApiService, а когда это не '', вызывать функции в сервисе, для которых требуется токен (например, getData())? Возможно, я приближаюсь к этому не так, но мои причины для его приближения состоят в том, что существует несколько дочерних компонентов, зависящих от действительного токена, для извлечения/отправки и отображения данных, а также только для получения/отправки данных при успешном входе в систему Я экспериментировал с различными ngOnChanges, Observerable, Subject.emit и т. Д., Но не смог выполнить эту работу.

ответ

0

Детским компонентам не нужно знать о состоянии службы.

, когда дочерний компонент использует getData(), служба может проверить, имеет ли он действительный токен, если он не может получить один через логин, а затем выполнить GET.

Если вы хотите, чтобы пользователь не загружал компонент, если отсутствует токен, вы можете использовать защитные устройства маршрута.

Может быть, не то, что вам нужно, но хорошее чтение о охранниках здесь: http://blog.thoughtram.io/angular/2016/07/18/guards-in-angular-2.html

+0

Спасибо за ответ Йохан, это аккуратное решение, но не совсем соответствует моим требованиям. Я хотел, чтобы страница всегда была доступна, но некоторые дочерние компоненты на странице должны заполняться только тогда, когда пользователь вошел в систему. Я детализирую решение, с которым я столкнулся ниже. Но я обновляю ваш ответ как полезный. – vim

+0

Извините, я не могу повышать это, у меня есть rep <15. Но было записано. – vim

0

Благодаря Йохан, однако, я хочу, чтобы страница доступна и некоторые дочерние компоненты только заполнить данные, когда пользователь регистрируются in

Я нашел решение на Delegation: EventEmitter or Observable in Angular2.

Таким образом, можно предотвратить дочерние компоненты, сделать запрос, пока маркер не изменяется (т.е. входа() была вызвана успешно):

import { Injectable } from '@angular/core'; 
import { Http, Response, Headers, URLSearchParams } from '@angular/http'; 
import {Observable, Subject} from 'rxjs/Rx'; 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/operator/map'; 

@Injectable() 
export class ApiService { 
    private url:string = 'my.service.com/'; 
    private username: string; 
    private password: string; 
    private token: string; 

    constructor (private http: Http) {} 

    private setToken(token: string) { 
    this.tokenValue = token; 
    this.token.next(token); 
    } 

    public login() { 
    let headers = new Headers({ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let urlSearchParams = new URLSearchParams(); 
    urlSearchParams.append('username', this.username); 
    urlSearchParams.append('password', this.password); 
    let body = urlSearchParams.toString(); 
    let url = this.url + 'user/login'; 
    this.http.post(url, body, {headers: headers}) 
     .map(res => {this.setToken(typeof res['token'] !== 'undefined' ? res['token'] : '');}); 
    } 

    public logout() { 
    this.setToken(''); 
    } 

    public getData() { 
    let headers = new Headers({ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let urlSearchParams = new URLSearchParams(); 
    urlSearchParams.append('token', this.token); 
    let body = urlSearchParams.toString(); 
    let url = this.url + 'data'; 
    return this.http.get(url, body, {headers: headers}) 
    .map(res => res.json()); 
    } 

ребенок компонент

import { Component } from '@angular/core'; 
import { ApiService } from '../services/api'; 
import { Subscription } from 'rxjs/Rx'; 

@Component({ 
    selector: 'child-component', 
    styleUrls: ['./child-component.component.scss'], 
    templateUrl: './child-component.component.html' 
}) 

export class ChildComponent { 
    tokenSubscription: Subscription; 
    data: any[]; 
    constructor(private apiService: ApiService) {} 

ngOnInit() { 
    this.tokenSubscription = this.apiService.changeToken$ 
    .subscribe(token => { this.apiService.getData().subscribe(res => this.data = res.json())); 
} 

ngOnDestroy() { 
    this.tokenSubscription.unsubscribe(); 
    } 
} 
Смежные вопросы