angular - Angular2: Uppdatera och dela data mellan komponenter
Jag försöker göra något som ser ut så här:
Letar efter ett sätt att få Service att mata den senaste datan till prenumererade komponenter när det behövs. Till exempel: Komponent3 skriver ändringar till API:t > Komponent1 och Komponent2 måste få den senaste datan.
För närvarande är båda komponenterna prenumererade på en observerbar som returneras av tjänsten och detta orsakar 2 API-förfrågningar om båda renderas. Detta känns fel. Enligt min förståelse borde dessa komponenter få datan till sig och inte själva begära den. För att vara tydlig: datan som returneras av denna tjänst används alltid i Komponent1 medan Komponent2 renderas valfritt.
Här är några utdrag och en liten beskrivning av vad jag har gjort hittills:
Service hämtar data via HTTP från API. Component1 och Component2 är prenumererade på observable som returneras av Service:
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 och Component2 är i princip samma när det gäller funktionalitet. Här är en av dem:
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;
});
}
}Svar #1
Ett något annorlunda tillvägagångssätt än seidmes, som jag personligen skulle föredra:
Ställ in en dataström i GroupService och använd den i dina komponenter.
Service :
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));
}
}
Sedan i dina komponenter, gör bara så här:
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$;
}
}
Sedan i din mall, använd async-pipen: {{ groups | async }}. Den kommer att ta hand om att prenumerera på (och avyttra) observable för dig.
Nu, när du än kallar GroupService.getGroups() från någon komponent, kommer alla andra att uppdateras automatiskt.
Dessutom är det något att föredra att använda OnInit framför att göra saker i konstruktorn, se Skillnaden mellan Constructor och ngOnInit.
Svar #2
Att använda BehaviorSubject som en delegat är förmodligen det mest bekväma alternativet för ditt användningsfall. Registrera BehaviorSubject i tjänsten och prenumerera på den i alla komponenter som behöver uppdateras när någon av dessa komponenter begär ny data.
Så här bör tjänsten se ut:
@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
}
}
Komponent 1, begär nya data:
export class Component1 implements OnInit {
groups: any;
constructor(private _groupService: GroupService) { }
ngOnInit() {
this._groupService.groupsSource.subscribe((groups) => {
this.groups = groups;
});
this._groupService.getGroups();
}
}
Komponent 2 uppdateras automatiskt:
export class Component2 implements OnInit {
groups: any;
constructor(private _groupService: GroupService) { }
ngOnInit() {
this._groupService.groupsSource.subscribe((groups) => {
this.groups = groups;
});
}
}
Med BehaviorSubject kan du få det senaste värde den innehåller utan att ens prenumerera på den:
export class Component3 implements OnInit{
groups: any;
constructor(private _groupService: GroupService) { }
ngOnInit() {
this.groups = this._groupService.groupsSource.getValue();
}
}
