如何在 Angular 8 中使用服务实现行为主体
Posted
技术标签:
【中文标题】如何在 Angular 8 中使用服务实现行为主体【英文标题】:How to implement behavior subject using service in 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();
【问题讨论】:
【参考方案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();
【讨论】:
感谢您的解释。我会关闭这个主题 为什么必须将响应转换为 asObservable()?不是继承吗? 这是对您问题的方便回答:***.com/questions/36986548/…【参考方案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);
您还可以想到其他方法,但鉴于您粘贴在问题上的示例代码,我认为这是更简单的方法。
附带说明:如果您在 *** 上进行一些搜索,您会发现此问题(或类似问题)已在此处被多次询问。看一下,例如在另一种方法中: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
);
【讨论】:
以上是关于如何在 Angular 8 中使用服务实现行为主体的主要内容,如果未能解决你的问题,请参考以下文章
在 Angular 8 中,如何从浏览器控制台访问注入的服务?
下面的代码在 Angular 8 中运行。但我需要在 Angular 6 中执行它。我该如何实现呢?
如何使用带有xml的angular+8的soap asmx服务
如何检查数据是不是已完成加载以使用异步管道 Angular 8
如何使用 Keycloak 保护 Angular 8 前端和使用网关、eureka 的 Java Spring Cloud 微服务后端
如何解决 NullInjectorError: No provider for HttpClient! Ionic 4(Angular 8)中的问题