【问题标题】:How to implement behavior subject using service in Angular 8如何在 Angular 8 中使用服务实现行为主体
【发布时间】:2019-08-05 08:48:33
【问题描述】:

我是 Angular 新手,但遇到了问题。

我正在创建一个包含多个同级组件的应用。当我更新一个组件中的值时,其他组件不会更新。我知道要解决这个问题,我应该使用 behaviour subject。但是如何使用我的服务、组件和所有模板来实现它?

这是我的代码 -

------------------------我的服务---------------- ------------

//import


@Injectable() 
export class CoachService {

    apiURL = environment.apiURL;

    constructor(private http: HttpClient ) { }

    coachProfile(token :string)
    {  
    return this.http.post<any>(this.apiURL+'/coach/profile_infos',{
      token: token
      })        
    }

    updateProfile(info: any, token: string, us_id: string) {
      return this.http.post<any[]>(this.apiURL + '/coach/update_profile', {
        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
        }
        })

    } 

}

---------一个组件.ts--------

//import
//component decorator

export class CoordonneesComponent implements OnInit, OnDestroy {

private coachProfile;
  token: string = localStorage.getItem('token');
  us_id : string;
  us_lang: string; 
  infos_profile: any;
  online: any;


  constructor(private translate: TranslateService,private coachService: CoachService, private router: Router) { }

  ngOnInit() {

    this.coachProfile=this.coachService.coachProfile(this.token)
      .subscribe((data) => {
        this.infos_profile = data.results;
        this.online = this.infos_profile.online_profile;
        this.translate.use(this.infos_profile.us_lang)
        this.infos_profile.lang= this.infos_profile.us_lang;

      });

   .....
  }


updateCoordonees() {
  this.coachService.updateProfile(this.infos_profile, this.token, this.us_id)
    .subscribe((data: any) => {

      if(data.success && data.msg!=null)
      { 
  // do something
      }
      else
      {
       // do something
      }

    },
      (err) => {
        // do something
      });

}  



  ngOnDestroy() {
    this.countrieList.unsubscribe();
    this.coachProfile.unsubscribe();  
  }


}

【问题讨论】:

    标签: angular typescript httpclient angular8 behaviorsubject


    【解决方案1】:

    我将向你展示一个简单的方法:

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

    现在,当您在应用程序的任何位置更新某些内容时,您可以通过 ProfileService 设置该更改,并且每个订阅者都会收到更改。我建议你订阅ngOnInit

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

    永远不要忘记取消订阅 observables 以防止内存泄漏!

    您可以通过多种方式做到这一点 --> 在ngOnDestroy() 中使用订阅和取消订阅,或者使用其他主题并将其交付给 takeUntil,如下所示:

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

    【讨论】:

    【解决方案2】:

    首先创建一个 BehaviourSubject

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

    定义一个函数来“更新” BehaviourSubject

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

    现在在您的组件中订阅源代码

    this.service.source.subscribe();
    

    注意 behaviorSubject 总是需要一个初始值并发出最后一个

    文档:https://www.learnrxjs.io/subjects/behaviorsubject.html

    如果你想从 httpRequest 共享数据,你应该使用 shareReplay() 操作符,你可以从不同的组件订阅 httpRequest,请求将被发出一次,数据将被共享

    文档:https://www.learnrxjs.io/operators/multicasting/sharereplay.html

    【讨论】:

      【解决方案3】:

      有几种方法可以做到这一点。此处描述了其中之一。

      1) 像这样构建您的服务:

      // 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) 在你的组件中:

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

      您还可以想到其他方法,但鉴于您粘贴在问题上的示例代码,我认为这是更简单的方法。

      附带说明:如果您在 stackoverflow 上进行一些搜索,您会发现此问题(或类似问题)已在此处被多次询问。看一下,例如在另一种方法中:Multiple subscriptions without recalculate common part

      【讨论】:

      • 感谢您对重播主题的解释!但我用的是行为主题而不是它。
      • @kkD97 和 BehaviorSubject 的逻辑是一样的
      【解决方案4】:

      以下是使用行为主题解决问题的方法:

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

      现在,当您想要发布数据并订阅您的 Behavior Subject 的结果时,比如说您在此处拥有的组件,您只需:

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

      【讨论】:

        猜你喜欢
        • 2011-03-10
        • 2020-02-09
        • 2020-02-19
        • 2020-07-31
        • 2020-04-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多