2

I have been using BehaviorSubject to share data between components. Say, relative url /article belongs to ArticleComponent. Then comes /article/list in ArticlelistComponent which contains a table with list of article details.On click of any row, i need that row detail to be passed to all the other component and that's my agenda. Issue i face is,ngOnInit works only on page reload. Initially,only default {} gets reflected in articlecomponent which is nothing but the default result i have set for BehaviorSubject.WHen i click on a row in table, that data doesnot get updated and subscribed automatically in ngOnInit.the old value {} is retained throughout .I ain't sure where to place it inorder to make the changes reflect immediately. Please help resolving. My code is below:

articlelist.component.ts

getSpecificDetail(value){
        this.articleService.getArticleDetail(value);
   }

article.service.ts

 public articledata=new BehaviorSubject<Object>({});
    currentdata=this.articledata.asObservable();
  getArticleDetail(data){         //data comes from articlelist.component
          return this.articledata.next(data);
    }

article.component.ts

 ngOnInit(){
    this.articleService.currentdata.subscribe(data=>{
    this.data=data;
    console.log(this.data);
    })
   }

Edit: I have extended my observation in Angular2:RxJS Subject not responding to events

Gayathri
  • 1,776
  • 5
  • 23
  • 50
  • How do you changing the `articledata` data on changes? – Rajez Aug 23 '17 at 17:49
  • the data which is passed from getArticleDetail differs on each click on any single row in table. – Gayathri Aug 23 '17 at 17:50
  • Flow is this,. On click on a row, i pass that data from articlelist component to this service. – Gayathri Aug 23 '17 at 17:52
  • Okay . So here the `return` statement is unecessary. – Rajez Aug 23 '17 at 17:53
  • without that, method would be considered void right ? – Gayathri Aug 23 '17 at 17:54
  • Yes. But that is not a problem. Bz it is setter function, we maynot need the value. – Rajez Aug 23 '17 at 17:58
  • @Gayathri there are two things you can do one is use ngrx r[edux](https://rahulrsingh09.github.io/AngularConcepts/ngrx) approach or change the way you use shared [services](https://rahulrsingh09.github.io/AngularConcepts/faq). These links might help – Rahul Singh Aug 23 '17 at 18:00
  • I am using shared service as in https://www.youtube.com/watch?v=I317BhehZKM&feature=youtu.be – Gayathri Aug 23 '17 at 18:01
  • this should work @Gayathri i dnt see any reason can you replicate a plu ker for this ? . – Rahul Singh Aug 23 '17 at 18:04
  • Or let me give you another information too. whatever be the change, be an addition of row in table. It's only on reload, the changes get reflected with respect to ngOnInit – Gayathri Aug 23 '17 at 18:06
  • What is "patientService"? just a different name for the same service instance? or an entirely new service? – diopside Aug 23 '17 at 18:10
  • sorry..that was typo. i just renamed services and components in my code for this question . – Gayathri Aug 23 '17 at 18:12

2 Answers2

1

Depending on what you are doing with that data, another way to share data between components that are binding to that data is by leveraging Angular's change detection instead of using your own BehaviorSubject.

import { Injectable } from '@angular/core';

@Injectable() 
export class DataService {
  serviceData: string; 
}

I have a blog post about it here: https://blogs.msmvps.com/deborahk/build-a-simple-angular-service-to-share-data/

And a plunker here: https://plnkr.co/edit/KT4JLmpcwGBM2xdZQeI9?p=preview

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • The appeal of this method: the ease with which you can share values between different instances, is also its downfall. As an app grows, and you begin to have 10+ instances accessing, or even modifying, the same 'global' value or object, things become extremely unpredictable. View states start to 'leak' unpredictably. This is one of the reasons the react model of UI development became so popular - it ensures separation. Subscribers are getting the same data, but nothing they do it can affect the source data. It only affects their new personal copy. It makes debugging so much easier. – diopside Aug 23 '17 at 18:31
  • Agreed. That's why it really depends on what your doing with the data. If you have simple CRUD operations or a simple master and detail layout, then this is a nice, simple option. If you have, like you said, 10 components updating values, then something more complex may be warranted. But it seems `BehaviorSubject` may not be the best answer then either; rather something like ngrx/store. – DeborahK Aug 23 '17 at 18:40
1

It should work like this (this is how I've always used Observables and Subjects). I always try to make sure I'm triggering and providing the subscription from the host service, to keep concerns separated.

article component

  getSpecificDetail(value){
       this.articleService.setData(value);
  }

article.service.ts

  articledata=new BehaviorSubject<Object>({});

  getData() : Observable<Object> {
     return this.articleData.asObservable();
  }
  setData(data) : void { this.articleData.next(data); } 

article.component.ts

 ngOnInit(){
    this.patientService.getData().subscribe( data =>{
        this.data=data;
         console.log(this.data);
     })
 }

Any reason you're using a Behavior Subject specifically?

diopside
  • 2,981
  • 11
  • 23
  • I think, my problem here is,ngOnInit gets loaded only on reload only. – Gayathri Aug 23 '17 at 18:35
  • I face the same I faced before. Just {} and nothing else. – Gayathri Aug 23 '17 at 18:36
  • And that {} is nothing but the default i have set in behaviorsubject – Gayathri Aug 23 '17 at 18:37
  • I think, getting to know how to load data on ngOnInit without refresh itself will solve this – Gayathri Aug 23 '17 at 18:39
  • It only needs to load once to subscribe. The subscription will remain valid and active regardless of whether it gets called again. Problems can occur if your components try to subscribe before the service has instantiated the subject / subscription tho. I would use ReplaySubject over BehaviorSubject in your case... that way if components are slow and subscribe after a first value has been sent out, they will receive the last value sent out, instead of receiving just a blank object like you have specified. If nothing has been sent - they wont receive anything, unlike behavior state – diopside Aug 23 '17 at 18:46
  • I believe the problems you are experiencing are bc of the way you configured your methods. You are returning the function that is supposed to update/emit the Subject in the service. I've never tried that, but I imagine it might literally return the method to the component calling it, rather than calling the method in the service that hosts it. Thus, observers keep receiving the default {} state as it never gets updated. – diopside Aug 23 '17 at 18:53
  • The Subject is not getting emitted on event. That is the ultimate issue. – Gayathri Aug 24 '17 at 07:06
  • 1
    The problem wasnt with code . I declared service as providers in patientlist component too. that was making the mess. A new issue now. https://stackoverflow.com/questions/45864989/angular2sharing-data-between-components-via-routes-subject – Gayathri Aug 25 '17 at 13:54
  • Thanks @Gayathri. Your last comment on this thread saved my day. :) – Mr. A Aug 24 '20 at 02:36