1
votes

I have a service which provides me an observable through a http get request and a following map operation. In my component I subscribe to the observable in the ngOnInit method. As I have a pagination functionality I would like to fire another request to the service when the user clicks on another page of the paginator. How can I achieve this? Do I have to subscribe to the service in a new method again or is it possible to initialize an observable within the component so I can use it in any method?

export class ListItemsComponent implements OnInit {
  private _listItems = [];
  page = 1;
  constructor(private _listItemsService:ListItemsServiceService) { }

  ngOnInit() {
    this._listItemsService.getListItems (this.page)
     .subscribe(listItems => this._listItems = listItems);
  }

  pageChange(page){
     this._listItemsService.getListItems (this.page)
     .subscribe(listItems => this._listItems = listItems);
  }

}
2

2 Answers

1
votes

Your service can expose listItems$ as an observable event, using a private BehaviourSubject:

@Injectable()
export class ListItemsService{
    public listItems$: Observable<[]>
    private _listItems: BehaviorSubject<[]>;

    private dataStore: {
        listItems: []
    };

    constructor( @Inject(Http) private http: Http) {
        this.baseUrl = 'http://localhost/listitemservice/';
        this.dataStore = { listItems: [] };
        this._listItems = new BehaviorSubject<[]>([]);
        this.listItems$ = this._listItems.asObservable();

    }
    loadAll() {
       this.pageChange(1);
    }

    pageChange(page) {
         this.http.get(this.baseUrl  + page.id)
         .subscribe(items => {
             this.dataStore.listItems = items;
             this._listItems.next(items);
         });
    }

Then in your component, subscribe to the listItems$ event. When it fires, store the list in a member variable of your component class:

export class ListItemsComponent implements OnInit {
  private _listItems = [];
  constructor(private _listItemsService:ListItemsServiceService) { }

  ngOnInit() {
    this._listItemService.listItems$.subscribe(t=> {
       this._listItems = t;
    });
    this._listItemsService.loadAll();    
  }

  pageChange(page){
     this._listItemsService.pageChange(page);
  }

}

On pageChange, call the pageChange method of the ListItemsService whcich in turn triggers the listItems$ event.

1
votes

If you want to avoid code duplication you can do something like this:

export class ListItemsComponent implements OnInit {
  private _listItems = [];
  page = 1;
  constructor(private _listItemsService:ListItemsServiceService) { }

  ngOnInit() {
    this.pageChange(this.page);
  }

  subscription;
  pageChange(page){
     if(this.subscription){
         this.subscribtion.unsubscribe();
     }

     this.subscription = this._listItemsService.getListItems(this.page)
         .subscribe(listItems => this._listItems = listItems);
  }
}

If your observable always use same data and you do not want to send requests on each subscribing you need to add caching to your observable. For example:

this.yourObservable
       .first()
       .publishReplay(1)
       .refCount();

More about caching here: What is the correct way to share the result of an Angular 2 Http network call in RxJs 5?