typescript 如何在 Angular 8 中使用服务实现行为主体

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/57355066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:51:02  来源:igfitidea点击:

How to implement behavior subject using service in Angular 8

angulartypescripthttpclientangular8behaviorsubject

提问by kkD97

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

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

I'm creating an app with several sibling components. When I update a value in one component other components don't update. I know that to resolve this issue I should use behaviour subject. But how do I implement it with my service, the components and all the templates?

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

Here is my code -

这是我的代码 -

----------------------My service---------------------------

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

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

    } 

}

----------one component.ts-------------------

----------一个组件.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();  
  }


}

回答by sagat

I'm going to show u a simple way:

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

@Injectable() 
export class ProfileService {

    private profileObs$: BehaviourSubject<Profile> = new BehaviourSubject(null);

    getProfileObs(): Observable<Profile> {
        return this.profileObs$.asObservable();
    }

    setProfileObs(profile: Profile) {
        this.profileObs$.next(profile);
    }
}

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

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

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

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

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

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:

有很多方法可以做到这一点 --> 在 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();
}

Kind regards

亲切的问候

回答by Robert garcia

First create a BehaviourSubject

首先创建一个 BehaviourSubject

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

Define a function to "update" the BehaviourSubject

定义一个函数来“更新” 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

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

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

文档: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

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

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

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

回答by julianobrasil

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

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

1) Build your service like this:

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) And in your components:

2)在你的组件中:

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

附带说明:如果您在 stackoverflow 上进行一些搜索,您会看到这个问题(或类似问题)在这里被问过很多次。看一看,例如在另一种方法中:Multiple subscriptions without recalculate common part

回答by Malik M

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