Angular2在服务中观察变化的属性

时间:2016-12-18 02:04:45

标签: angular observable subscription emit

我是Angular2的新手,我正在尝试找出父和子组件的设计模式,以便在服务中的属性发生变化时执行操作,此服务全局可用(在app.component.ts中声明{ {1}}属性)。我正在使用:

  • Angular 2.2.1
  • rxjs 5.0.0-beta.12
  • typescript 2.2.1

服务基本上连接到远程API,此API需要令牌身份验证。该服务具有公共providerslogin()功能。前者调用API,然后将私有属性logout()设置为令牌字符串(如果有效登录)或'' (如果登录无效)。调用API的所有其他公共函数都使用此私有令牌。

我假设使用此服务的组件不需要查看或使用令牌属性,因为它们应该是“愚蠢的”。到API的业务流程,只通过此服务使用数据。

服务(简化)

token

app.component.ts

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

子组件

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)?也许我以错误的方式接近它,但我以这种方式接近它的原因是有几个子组件依赖于有效的令牌获取/发送和显示数据,并且应该只在成功登录时获取/发送数据。我一直在尝试各种ngOnChanges,Observerable,Subject.emit等,但是没能使这项工作。

2 个答案:

答案 0 :(得分:0)

子组件不应该知道服务的状态。

当子组件使用getData()时,服务可以检查它是否有有效的令牌,如果没有,它可以通过登录获得一个,然后执行GET。

如果你想要在没有令牌的情况下阻止用户加载组件,你可以使用路线保护。

也许不是你需要的,但在这里阅读有关守卫的好文章: http://blog.thoughtram.io/angular/2016/07/18/guards-in-angular-2.html

答案 1 :(得分:0)

感谢Johan,我希望页面可用并且有一些子组件只在用户登录时填充数据。

我在Delegation: EventEmitter or Observable in Angular2找到了解决方案。

通过这种方式,我可以阻止子组件发出请求,直到更改令牌(即成功调用login()):

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