How to implement behavior subject using service in Angular 8

后端 未结 4 695
借酒劲吻你
借酒劲吻你 2021-01-02 06:32

I\'m new to Angular and I\'m having an issue.

I\'m creating an app with several sibling components. When I update a value in one component other components don\'t u

相关标签:
4条回答
  • 2021-01-02 06:58

    Here's how to solve your problem using a behavior subject:

    @Injectable()
    export class CoachService {
      apiURL = environment.apiURL;
    
      constructor(private http: HttpClient) { }
    
      updateProfile(info, token, us_id): Observable<any> {
        return Observable.create((behaviorSubject: BehaviorSubject<any>) => {
          const requestData = {
            token: token,
            us_id: us_id,
            us_lang: info.us_lang,
            us_firstname: info.us_firstname,
            us_lastname: info.us_lastname,
            us_sex: info.us_sex,
            us_birthdate: info.us_birthdate,
            us_national_number: info.us_national_number,
            us_email: info.us_email,
            us_gsm: info.us_gsm,
            online_profile: info.online_profile,
            us_address: info.us_address,
            us_zip: info.us_zip,
            us_city: info.us_city,
            country: {
              id: info.country.id
            }
          };
          const url = [this.apiURL, '/coach/update_profile'].join('');
    
          return this.http.post(url, requestData).subscribe(
            data => {
              behaviorSubject.next(data);
            },
            err => {
              behaviorSubject.error(err);
              if (err && err.status === 401) {
                // Do some err handling
              }
            }
          );
        });
      }
    
    }
    

    Now when you want to post data and subscribe to the result of your Behavior Subject from, say to the in the component you have here, you simply:

     updateCoordonees() {
      this.coachService.updateProfile(this.infos_profile, this.token, this.us_id)
        .subscribe((data: any) => {
    
          if (data.success && data.msg != null) {
            // do something on success
          }
    
        },
          (err) => {
            // do some err handling
          });
    } 
    
    
    0 讨论(0)
  • 2021-01-02 07:00

    First create a BehaviourSubject

    this._source = new BehaviourSubject<yourType>(initialValue);
    this.source = this._source.asObservable();
    

    Define a function to "update" the BehaviourSubject

    updateSource(newValue) {
        this._source.next(newValue)
    }
    

    Now subscribe in your components to the source

    this.service.source.subscribe();
    

    Note the behaviourSubject always needs an initial value and emits the last one

    DOCS: https://www.learnrxjs.io/subjects/behaviorsubject.html

    If you want to share the data from a httpRequest you should use shareReplay() operator instead, you can subscribe to the httpRequest from different components and the request will be made once and the data will be shared

    DOCS: https://www.learnrxjs.io/operators/multicasting/sharereplay.html

    0 讨论(0)
  • 2021-01-02 07:03

    I'm going to show you a simple way:

    @Injectable() 
    export class ProfileService {
    
        private profileObs$: BehaviorSubject<Profile> = new BehaviorSubject(null);
    
        getProfileObs(): Observable<Profile> {
            return this.profileObs$.asObservable();
        }
    
        setProfileObs(profile: Profile) {
            this.profileObs$.next(profile);
        }
    }
    

    Now when you update something anywhere in the application, you can set that change by the ProfileService and each subscriber is receiving the change. I recommend you subscribe in ngOnInit.

    ngOnInit() {
      this.profileService.getProfileObs().subscribe(profile => this.profile = profile);
    }
    

    Never forget to unsubscribe from the observables to prevent memory leaks!

    There are many ways u can do that --> Use a subscription and unsubscribe in ngOnDestroy() or use another subject and deliver it to takeUntil like this:

    unsubscribe$: Subject<boolean> = new Subject();
    
    ...
    
    ngOnInit() {    
      this.profileService.getProfileObs()
                         .pipe(takeUntil(this.unsubscribe$)
                         .subscribe(profile => this.profile = profile);
    }
    
    ngOnDestroy() {
      this.unsubscribe$.next(true);
      this.unsubscribe$.complete();
    }
    
    0 讨论(0)
  • 2021-01-02 07:07

    There are a few ways to do that. One of them is described here.

    1) Build your service like this:

    // ReplaySubject is more flexible than BehaviorSubject, as it
    // allows you to define how many past emissions should be available.
    // But you can get an equivalent code with BehaviorSubject by
    // coding like this:
    // private _coachProfile$: BehaviorSubject<any | null> = 
    //    new BehaviorSubject<any | null>(null);
    private _coachProfile$: ReplaySubject<any> = new ReplaySubject<any>(1);
    
    coachProfile(token :string)
    {  
      return this.http.post<any>(this.apiURL+'/coach/profile_infos',{
        token: token,
      }).subscribe((profile) => this._coachProfile$.next(profile));        
    }
    
    subscribeToGetCoachProfile$()
    {  
      return this._coachProfile$.asObservable();       
    }
    

    2) And in your components:

    ngOnInit() {
      this.coachService.subscribeToGetCoachProfile$()
        .subscribe((profile) => this.coachProfile = profile);
    }
    

    Well there are other approaches you can think of, but I think this is the simpler one given the sample code you pasted on your question.

    As a side note: if you do some search on stackoverflow, you'll see that this question (or similar questions) has been asked many times here. Take a look, for example in this other approach: Multiple subscriptions without recalculate common part

    0 讨论(0)
提交回复
热议问题