我创建了一个"Master CRUD Service"。
当我在 2 个不同的组件中使用它以从传递的 URL 获取数据并使用 | 异步时,它失败了
当在一个组件中检索数据时,另一个组件将更改为该流
每个组件都有一个声明的可观察,但名称不同,为什么会发生这种情况?
组件 1 HTML
<kendo-grid [data]="component1| async" />
组件 1 请求
export class Component1 implements OnInit {
public component1: Observable<GridDataResult>;
public gridState: State = {
skip: 0,
take: 100
};
constructor(private fetchDataEditService: FetchDataEditService) {
}
public requestClick(): void {
this.component1 = this.fetchDataEditService.map((data: any) =>
(<GridDataResult>{
data: data.results,
total: data.count,
})
)
this.fetchDataEditService.read(this.url, this.gridState);
}
组件 2 HTML
<kendo-grid [data]="component2| async" />
组件 2 请求
export class Component2 implements OnInit {
public component2: Observable<GridDataResult>;
public gridState: State = {
skip: 0,
take: 100
};
constructor(private fetchDataEditService: FetchDataEditService) {
}
public requestClick(): void {
this.component2 = this.fetchDataEditService.map((data: any) =>
(<GridDataResult>{
data: data.results,
total: data.count,
})
)
this.fetchDataEditService.read(this.url, this.gridState);
}
获取数据编辑服务
@Injectable()
export class FetchDataEditService extends BehaviorSubject<any[]> {
constructor(private http: HttpClient) {
super([]);
}
public data: any[] = [];
public read(url: string, state: DataSourceRequestState = {}) {
const data = [];
this.fetch('', url, state)
.do((data: any) =>
(<GridDataResult>{
data: data.results,
total: data.count,
})
)
.subscribe((data: any) => {
super.next(data);
});
};
public save(url: string, state: DataSourceRequestState, data: any, isNew?: boolean) {
const action = isNew ? CREATE_ACTION : UPDATE_ACTION;
this.reset();
this.fetch(action, url, state, data)
.subscribe(() => this.read(url, state), () => this.read(url, state));
}
public remove(url: string, state: DataSourceRequestState, data: any) {
this.reset();
this.fetch(REMOVE_ACTION, url, state, data)
.subscribe(() => this.read(url, state), () => this.read(url, state));
}
public resetItem(url: string, dataItem: any) {
if (!dataItem) { return; }
const originalDataItem = this.data.find(item => item.djangoid === dataItem.djangoid);
Object.assign(originalDataItem, dataItem);
super.next(this.data);
}
private reset() {
this.data = [];
}
private fetch(action: string = '', url: string = '', state?: DataSourceRequestState, data?: any): Observable<GridDataResult> {
const queryStr = `${toDataSourceRequestString(state)}`;
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
}
if (action == "") {
return this.http
.get<GridDataResult>(`${API_URL + url}/?${queryStr}`)
.retry(3).pipe(catchError(this.handleError))
}
if (action == "create") {
return this.http
.post(API_URL + url + '/', data, httpOptions)
.pipe(catchError(this.handleError))
}
if (action == "update") {
alert
return this.http
.put(API_URL + url + '/' + data.djangoid + '/', data, httpOptions)
.pipe(catchError(this.handleError))
}
if (action == "destroy") {
return this.http
.delete(API_URL + url + '/' + data.djangoid + '/', httpOptions)
.pipe(
tap(res => console.log(`deleted id=${data.djangoid}`)),
catchError(this.handleError))
}
throw Error('Internal REST Command Error')
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json() || 'Server Error');
}
}
任何想法
谢谢
编辑 1 - 响应在哪里提供服务
我在数据模块中提供服务,并将其导入到核心模块中,最后将其导入到我的应用程序模块中
Data.module.ts
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FetchDataEditService } from './edit.service';
import { SeniorSandpitService } from './seniorsandpit.service';
import { UtilsService } from './utils.service';
const SERVICES = [
FetchDataEditService,
SeniorSandpitService,
UtilsService,
];
@NgModule({
imports: [
CommonModule,
],
providers: [
...SERVICES,
],
})
export class DataModule {
static forRoot(): ModuleWithProviders {
return <ModuleWithProviders>{
ngModule: DataModule,
providers: [
...SERVICES,
],
};
}
}
Core.Module.ts
import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';
import { CommonModule } from '@angular/common';
import { throwIfAlreadyLoaded } from './module-import-guard';
import { DataModule } from './data/data.module';
import { AnalyticsService } from './utils/analytics.service';
const NB_CORE_PROVIDERS = [
...DataModule.forRoot().providers,
AnalyticsService,
];
@NgModule({
imports: [
CommonModule,
],
exports: [
],
declarations: [],
})
export class CoreModule {
constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
throwIfAlreadyLoaded(parentModule, 'CoreModule');
}
static forRoot(): ModuleWithProviders {
return <ModuleWithProviders>{
ngModule: CoreModule,
providers: [
...NB_CORE_PROVIDERS,
],
};
}
}
您的问题在于您的两个组件共享完全相同的服务实例。这通常不是问题,但是您的服务本身就是一个主题,因此导致数据被广播出去的任何调用都将被两个组件看到。这是因为 Angular 中的服务在提供它们的地方是单例(除非您注册工厂来创建它们(。
我有一种感觉,如果您在配置对象中为每个组件提供服务,您不会看到这种行为,因为它们将是单独的主题。
@Component({
...
providers: [FetchDataEditService]
})
我建议看看关于依赖注入的 Angular 文档。