Angular2:在组件之间更新和共享数据

时间:2017-02-08 15:45:02

标签: angular typescript rxjs

我正在尝试制作看起来像这样的东西: enter image description here

寻找一种方法,使服务在必要时将最新数据提供给订阅组件。例如:Component3将更改写入API> Component1和Component2必须获取最新数据。

目前,两个组件都订阅了服务返回的observable,如果两个API请求都被渲染,则会导致2个API请求。这感觉不对。根据我的理解,这些组件应该由数据提供,而不是自己请求。需要明确的是:此服务返回的数据始终在Component1中使用,而Component2可选地呈现。

这里有一些片段和对我到目前为止所做的一些描述:

服务通过HTTP从API获取数据。 Component1 Component2 订阅服务返回的observable:

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";

import 'rxjs/add/operator/map';

@Injectable()

export class GroupService{
    constructor(private _http: Http){}

    getGroups(){
        return this._http.get('/assets/groups.json')
            .map((res) => {
                return res.json();
            });
    }
}

Component1 Component2 在功能方面基本相同。这是其中之一:

import { Component } from '@angular/core';
import { router } from '../../app.router';
import { GroupService } from '../../services/group.service';
import { Group } from '../../interfaces/group.interface';

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

export class SidebarComponent
{
    router;
    groups: Group[];

    constructor(private _groupService: GroupService){
        this.router = router;
        this.getGroups();
    }

    getGroups(){
        this._groupService.getGroups()
            .subscribe((groups) => {
                this.groups = groups;
            });
    }
}

2 个答案:

答案 0 :(得分:4)

与seidme的方法稍有不同,我个人更喜欢:

GroupService中设置数据流,并在组件中使用该数据流。

服务:

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/map';

@Injectable()
export class GroupService {
    private groupSource = new BehaviorSubject<any>({});
    public group$: Observable = this.groupSource.asObservable();

    constructor(private _http: Http) {}

    getGroups() {
        this._http.get('/assets/groups.json')
            .map((res) => {
                return res.json();
            })
            .subscribe((groups) => this.groupSource.next(groups));
    }
}

然后在您的组件中,执行此操作:

import { Component, OnInit } from '@angular/core';
import { router } from '../../app.router';
import { GroupService } from '../../services/group.service';
import { Group } from '../../interfaces/group.interface';
import { Observable } from 'rxjs/Observable';

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

export class SidebarComponent implements OnInit {
    router;
    groups: Observable;

    constructor(private _groupService: GroupService){
        this.router = router;
    }

    ngOnInit {
        this.groups = this._groupService.group$;
    }
}

然后在您的模板中,使用async管道:{{ groups | async }}。它将负责为您订阅(和处置)observable。

现在,只要您从任何组件中调用GroupService.getGroups(),其他所有组件都会自动更新。

此外,使用OnInit稍微比在构造函数中执行操作更可取,请参阅Difference between Constructor and ngOnInit

答案 1 :(得分:2)

使用BehaviorSubject as a delegate可能是您用例最方便的选项。在服务中注册BehaviorSubject,并在任何这些组件请求新数据时需要更新的所有组件中订阅它。

这就是服务的样子:

@Injectable()
export class GroupService {

    groupsSource: BehaviorSubject<any> = new BehaviorSubject(null);

    constructor(private _http: Http) { }

    getGroups(): void {
        this._http.get('/assets/groups.json')
            .map((res) => res.json())
            .subscribe((groups) => this.groupsSource.next(groups)); // Update all components subscribed to the BehaviorSubjet
    }
}

组件1,请求新数据:

export class Component1 implements OnInit {

    groups: any;

    constructor(private _groupService: GroupService) { }

    ngOnInit() {
        this._groupService.groupsSource.subscribe((groups) => {
            this.groups = groups;
        });

        this._groupService.getGroups();
    }
}

组件2,自动更新:

export class Component2 implements OnInit {

    groups: any;

    constructor(private _groupService: GroupService) { }

    ngOnInit() {
        this._groupService.groupsSource.subscribe((groups) => {
            this.groups = groups;
        });
    }
}

使用BehaviorSubject,您可以获得最新的价值而无需订阅它:

export class Component3 implements OnInit{

    groups: any;

    constructor(private _groupService: GroupService) { }

    ngOnInit() {
        this.groups = this._groupService.groupsSource.getValue();
    }
}