角度 5 |异步,多个数据绑定 1 CRUD 服务中的冲突



我创建了一个"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 文档。

最新更新