问题描述
我的前端有2种服务,一种用于API调用,另一种用于共享两个不同组件的数据.因此,第二项服务正在使用API服务.
I'm having 2 services in my angular frontend, one for API calls and one for sharing data two different components. So the second service is using the API service.
如果我仅使用API服务并在组件内部订阅我的Observable,则一切正常(在xxx.component.html中查看).
If I only use the API service and subscribe my Observables inside my component, everything works fine(view in xxx.component.html).
因此,如果我将这两个服务声明为app.module内的提供者,并将API服务注入共享服务内,则它将不再起作用.
So if I declare the two services as providers inside app.module and inject the API Service inside the sharing service, it won't work any more.
使用调试器,我总是得到settings.service.ts中未定义的变量"tmp"
Using debugger, I always get variable "tmp" not defined in settings.service.ts
我知道,我也可以使用@Input来实现子组件的功能,但是我认为使用服务对于解耦组件也是一种更好的方法.
I know, I could do this also with also with @Input for child components, but i think using a service is a much nicer way also for decoupling components.
有什么建议吗?)
在我的代码下面:
api.service.ts
api.service.ts
export class ApiService {
API_URL = 'https://localhost:44381/api/v1';
constructor(private httpClient: HttpClient) { }
/** GET settings from API*/
getSettings(): Observable<Setting[]> {
return this.httpClient.get<Setting[]>(this.API_URL + '/settings')
.pipe(
catchError(this.handleError('getSettings', [])));
}
}
settings.service.ts
settings.service.ts
export class SettingsService {
tmp: Setting[];
constructor(private apiService: ApiService) { }
getSettings(): void {
this.apiService.getSettings()
.subscribe(settings =>
this.tmp = settings);
}
getData(): Setting[] {
this.getSettings();
return this.tmp;
}
}
settings.component.ts
settings.component.ts
export class SettingsComponent implements OnInit {
settings: Setting[];
constructor(private settingService: SettingsService) { }
// Load Setting while starting
ngOnInit() {
// this.getSettings();
this.settings = this.settingService.getData();
}
// old code when using only API service which works..
/*getSettings(): void {
this.apiService.getSettings()
.subscribe(settings => this.settings = settings);
}*/
}
settings.component.hmtl
settings.component.hmtl
<div>
<table>
<tr>
<th>keyname</th>
<th>value</th>
<th>defaultValue</th>
<th align="right">text</th>
</tr>
<tr *ngFor="let s of settings">
<td>{{s.keyName}}</td>
<td>{{s.wert}}</td>
<td>{{s.defaultValue}}</td>
<td align="right">{{s.description}}</td>
</tr>
</table>
</div>
推荐答案
您的问题在于异步功能. subscribe
方法用于等待异步操作.这意味着当您执行特定请求(例如,远程请求)时,您不想停止整个流执行以等待响应.但是,相反,您希望在服务器正在处理您的请求并发送其响应的同时发出请求并执行所有其他代码.
Your problem resides into async functionality. The subscribe
method is used to wait for an async operation. That means that when you execute a particular request, for example a remote request, you don't want to stop the entire flow execution waiting for the response. But rather you want to make the request and execute all other code in the meanwhile that the server is processing your request and is sending it's response.
所以让我们分析一下这段代码执行的流程
So let's analyze what is the flow of this code execution
getSettings(): void {
this.apiService.getSettings()
.subscribe(settings =>
this.tmp = settings);
}
getData(): Setting[] {
this.getSettings();
return this.tmp;
}
-
this.getSettings()
执行一个请求并订阅它回应 - 然后,当它仍在等待订阅的响应时,您会立即返回
this.tmp
,它仍然是未定义的 - 订阅的请求结束后,您将获得响应并将该值分配给您的
this.tmp
变量
this.getSettings()
executes a request and subscribe for it'sresponse- then while it's still waiting for subscribed response you return immediately
this.tmp
, that is still undefined - after a time your subscribed request ends, you obtain your response and assign that value to your
this.tmp
variable
如果您已将逻辑分为2个服务来管理同步问题,请考虑使用Subject
If you have splitted your logic into 2 services to manage syncronism problems, consider to use Subject
可能的主题解决方案
服务
export class SettingsService {
API_URL = 'https://localhost:44381/api/v1';
settingsSource = new Subject<Setting>();
settings$ = this.settingsSource.asObservable();
constructor(private httpClient: HttpClient) { }
getSettings(): void {
this.apiService.getSettings().subscribe(settings =>
this.settingsSource.next(settings);
);
}
getData(): Setting[] {
this.getSettings();
return this.tmp;
}
get result$(): Observable<Setting> {
return this.settings$;
}
}
组件
export class SettingsComponent implements OnInit {
subscription: Subscription;
settings: Setting[];
constructor(private settingService: SettingsService) { }
// Load Setting while starting
ngOnInit() {
// subscribe for settings
this.resSubscription = this.searchService.result$.subscribe(result => {
this.resList = result.result;
});
// request settings
this.settings = this.settingService.getData();
}
}
您可以看到SettingsComponent
订阅settings$
Observable
($
是Observable
的约定),然后它向服务请求数据.当服务收到响应数据时,将其推送到settingsSource
,它是Observable
版本(settings$
)接收数据,并且建议所有订阅的组件
As you can see SettingsComponent
subscribe to settings$
Observable
(the $
is a convention for Observable
), then it ask for data to the service.When the service receives response data push them into settingsSource
, it's Observable
version (settings$
) receives data and all subscribed components get advised
这篇关于使用服务向组件角度共享数据失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!