Как я могу создать переменную в сервисе, которая получает свои данные из обещания, но является общей для двух компонентов?

#angular #typescript

#angular #typescript

Вопрос:

У меня есть сервис в Angular 2 с использованием TypeScript. Я хочу иметь возможность совместно использовать массив значений, которые я получаю от этого сервиса. когда один компонент вносит изменения в массив, мне нужно, чтобы это было отражено в другом компоненте.

Это основы моего сервиса и объекта, который он использует

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


}
  

И вот один из компонентов, который получает массив избранных.

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

}
  

В каждом компоненте, использующем сервис, у него есть свой собственный массив избранного, который назначается при загрузке. Однако мне нужна одноэлементная переменная в сервисе, где изменения могут быть отражены в двух компонентах. Я не уверен, как это сделать с promises. Я рад уточнить, если это необходимо. Любая помощь будет высоко оценена.

Комментарии:

1. В вашем компоненте получите / установите массив избранного из модели сервиса. this.favoriteService.favorites будет работать как одноэлементный.

2. @user32 Если я создам метод get, он вернется до того, как обещание будет выполнено. как мне сделать так, чтобы она возвращалась при успешном выполнении обещания?

Ответ №1:

Хотя это, вероятно, можно сделать с помощью обещаний, я могу ответить в виде наблюдаемых, по крайней мере, если вы хотите прочитать о них…

Дано ComponentA , и ComponentB оба смотрят на a SharedService для их источника SomeObject[] данных:

Сервис:

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

Компоненты затем имеют:

 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 будет выглядеть аналогично — подписка на одно и то же SharedList$ свойство в сервисе. Когда getList() вызывается метод сервиса и он передает новое SomeObject[] значение через observables ( this.listObserver.next(..) ) , компоненты, подписанные на это свойство, смогут считывать переданное ему значение.

Редактировать: предоставил addItem метод в сервисе, который компоненты могут вызывать для добавления элементов в список. Затем сервис передает его через observable, ( this.listObserver.next(...) ) в том же стиле, что и при получении данных с помощью другого метода (т.Е. http).

Комментарии:

1. Я попробую это и сообщу

2. Итак, вот где я застрял сейчас. Как мне добавить элемент в SharedList $ или listObserver? итак, если для одного компонента мне нужно добавить другой объект, как мне это сделать?

3. Чтобы добавить переменную в список, которым делится моя служба, нужно ли мне немедленно сохранить в базе данных и снова получить этот список? Я хочу иметь возможность сделать что-то подобное в компоненте a addToList(SomeObject ){ this.service.addToList(SomeObject) } , а затем отобразить этот объект в компоненте B. В этом весь смысл наличия сервиса. Я мог бы просто восстановить эти значения по отдельности в каждом компоненте в противном случае.

4. @Точно ничего. Я обновлю свой ответ, чтобы вы включили это.

5. Редактировать неважно, я заставил это работать. это была проблема с импортом, потребовалась эта строка import { Observable, Observer } from 'rxjs/Rx'; , большое спасибо, что вы меня спасли. Я отмечу ваш ответ как правильный.

Ответ №2:

Ответ @Krenom был правильным. с одним импортом, который необходимо изменить в моей настройке.

Мне нужно было import { Observable, Observer } from 'rxjs/Rx';import { Observable, Observer } from 'rxjs/Rx';

Ответ №3:

В вашем компоненте

 //set favorites
    getFavorites(): void{
        this.favoriteService
            .getFavorites()
            .then(favorites => this.favoriteService.favorites = favorites);
    }  

// get favorite
this.favorites = this.favoriteService.favorites;//access it from service
  

Комментарии:

1. Похоже, это создает копию, а не передает ссылку. Таким образом, он становится пустым до завершения обещания