Angular8中如何使用服务实现行为主体
How to implement behavior subject using service in Angular 8
我是 Angular 的新手,我遇到了问题。
我正在创建一个包含多个同级组件的应用程序。当我更新一个组件中的值时,其他组件不会更新。我知道要解决这个问题,我应该使用 行为主题 。但是我如何使用我的服务、组件和所有模板来实现它?
这是我的代码 -
---------------------我的服务------------ --------------
//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
}
})
}
}
------------一个component.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();
}
}
首先创建一个BehaviourSubject
this._source = new BehaviourSubject<yourType>(initialValue);
this.source = this._source.asObservable();
定义函数 "update" 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
有几种方法可以做到这一点。此处描述了其中之一。
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);
}
您还可以想到其他方法,但鉴于您在问题中粘贴的示例代码,我认为这是更简单的方法。
附带说明:如果您在 Whosebug 上进行一些搜索,您会发现这个问题(或类似问题)已在此处被问过很多次。看一下,例如在另一种方法中:
我将向您展示一个简单的方法:
@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);
}
永远不要忘记取消订阅可观察对象以防止内存泄漏!
您可以通过多种方式做到这一点 --> 在 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();
}
以下是使用行为主题解决问题的方法:
@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
}
}
);
});
}
}
现在,当您想要 post 数据并订阅您的行为主体的结果时,比如您在此处拥有的组件中,您只需:
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 的新手,我遇到了问题。
我正在创建一个包含多个同级组件的应用程序。当我更新一个组件中的值时,其他组件不会更新。我知道要解决这个问题,我应该使用 行为主题 。但是我如何使用我的服务、组件和所有模板来实现它?
这是我的代码 -
---------------------我的服务------------ --------------
//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
}
})
}
}
------------一个component.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();
}
}
首先创建一个BehaviourSubject
this._source = new BehaviourSubject<yourType>(initialValue);
this.source = this._source.asObservable();
定义函数 "update" 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
有几种方法可以做到这一点。此处描述了其中之一。
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);
}
您还可以想到其他方法,但鉴于您在问题中粘贴的示例代码,我认为这是更简单的方法。
附带说明:如果您在 Whosebug 上进行一些搜索,您会发现这个问题(或类似问题)已在此处被问过很多次。看一下,例如在另一种方法中:
我将向您展示一个简单的方法:
@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);
}
永远不要忘记取消订阅可观察对象以防止内存泄漏!
您可以通过多种方式做到这一点 --> 在 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();
}
以下是使用行为主题解决问题的方法:
@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
}
}
);
});
}
}
现在,当您想要 post 数据并订阅您的行为主体的结果时,比如您在此处拥有的组件中,您只需:
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
});
}