I have a service in an Angular 2 using TypeScript. I want to be able to share an array of values that I get from that service. when one component makes a change to the array I need it to be reflected in another component.
This is the basics of my service and the object it uses
export class deviceObj {
device_Id:number;
deviceGroup_Id:number;
name:string;
favoriteFlag:boolean;
visibleFlag:boolean;
}
export class Favorite {
favorite_Id: number;
device: deviceObj;
constructor(){this.device = new deviceObj()};
}
@Injectable()
export class FavoriteService {
private headers = new Headers({'Content-Type': 'application/json'});
private favoritesURL = 'URL THAT FEETCHES DATA';
favorites: Favorite[];
constructor(private http: Http) {
this.getFavorites().then(favorites => this.favorites = favorites);
}
getFavorites(): Promise<Favorite[]> {
return this.http.get(this.favoritesURL).toPromise().then(response => response.json() as Favorite[]).catch(this.handleError);
}
protected handleError2(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'server error');
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); //
return Promise.reject(error.message || error);
}
}
And here is one of the components that gets the array of favorites.
import {FavoriteService} from'../../services/favorite/favorite.service';
declare var jQuery: any;
@Component({
selector: '[sidebar]',
directives: [
ROUTER_DIRECTIVES,
SlimScroll
],
template: require('./sidebar.html')
})
export class Sidebar implements OnInit {
constructor(config: ConfigService, el: ElementRef, router: Router, location: Location,
private favoriteService:FavoriteService) {
}
getFavorites(): void{
this.favoriteService
.getFavorites()
.then(favorites => this.favorites = favorites);
}
In each component that uses the service it has its own favorites array that gets assigned on load. However I want a singleton variable in the service where changes can be reflected in two components. I'm not sure how to do this with promises. I am happy to clarify further if needed. Any help would greatly be apreciated.
While it can probably be done with Promises, I can answer in the form of Observables at the very least, if you're of a mind to read about them...
Given ComponentA
and ComponentB
both looking at a SharedService
for their source of SomeObject[]
data:
The service:
import { Injectable } from '@angular/core';
import { Observable, Observer } from 'rxjs/rx';
import 'rxjs/add/operator/share';
import { SomeObject } from './some-object';
@Injectable()
export class SomeService{
SharedList$: Observable<SomeObject[]>;
private listObserver: Observer<SomeObject[]>;
private sharedList: SomeObject[];
constructor(private http: Http){
this.sharedList = [];
this.SharedList$ = new Observable<SomeObject[]>(x => this.listObserver = x).share();
}
getList(){
// Get the data from somewhere, i.e. http call
this.http.get(...)
.map(etc)
.subscribe(res => {
this.sharedList = res;
this.listObserver.next(this.sharedList);
});
// the important part is after getting the data you want, observer.next it
}
addItem(item: SomeObject): void {
this.sharedList.push(item);
this.listObserver.next(this.sharedList);
}
}
Components then have:
import { Component, OnInit } from '@angular/core';
import { Observable, Observer } from 'rxjs/rx';
import { SharedService } from './some.service';
import { SomeObject } from './some-object';
@Component({...})
export class CommponentA implements OnInit {
private list: SomeObject[];
constructor(private service: SharedService){
this.list = [];
}
ngOnInit(){
this.service.SharedList$.subscribe(lst => this.list = lst);
this.service.getList();
}
private onClick(item: SomeItem): void {
this.service.addItem(item);
}
}
ComponentB
would look similar - subscribing to the same SharedList$
property on the service. When the service's getList()
method is called, and it pushes a new SomeObject[]
through the observables (this.listObserver.next(..)
), the components subscribed to that property will be able to read the value pushed to it.
Edit: Exposed an addItem
method on the service that the components can call to push items to the list. The service then pushes it through the observable, (this.listObserver.next(...)
) in the same style as when getting the data through x other method (i.e. http).
@Krenom's answer was corrrect. with one import needing to be changed on my setup.
I needed import { Observable, Observer } from 'rxjs/Rx';import { Observable, Observer } from 'rxjs/Rx';
In your component
//set favorites
getFavorites(): void{
this.favoriteService
.getFavorites()
.then(favorites => this.favoriteService.favorites = favorites);
}
// get favorite
this.favorites = this.favoriteService.favorites;//access it from service
来源:https://stackoverflow.com/questions/39897670/how-can-i-create-a-variable-in-a-service-that-gets-its-data-from-a-promise-yet-i