如何从多个模块中删除angular中的所有相关记录

How to delete all related records in angular from multiple modules

我的 angular 应用程序中有多个模块,每个模块都将一些相关数据存储到我的主数据中。现在,我想删除我的主数据,我也想删除所有相关数据。

所以我想有一个带有 delete 方法的服务 (service1) 和一个 observable 让其他服务知道这个数据将被删除,其他依赖服务 (service2, service3, ...) 也会订阅并删除他们的相关数据

@Injectable({
  providedIn: "root"
})
export class Service1Service {
  deleteData$: Subject<string> = new Subject<string>();
  constructor() {
    console.log("Service1Service.constructor");
  }

  delete(id: string) {
    console.log("service1.delete");
    this.deleteData$.next(id);
  }
}
@Injectable({
  providedIn: "root"
})
export class Service2Service {
  constructor(private service1: Service1Service) {
    console.log("Service2Service.constructor");
    this.service1.deleteData$.subscribe(id => this.delete(id));
  }

  delete(id: string) {
    console.log("service2.delete");
  }
}

export class MyComponent {
  constructor(
    private service1: Service1Service,
    ) {}

  delete() {
    this.service1.delete("5");
  }
}

所以这样一来,Service2就会依赖Service1,如果以后开发出新的模块来存储一些其他相关数据,那就是Open/Closed数据。

问题是如果我不在已经加载的组件中注入 Service2,angular 不会创建它们,因此它们不会订阅删除数据的服务。

我试过使用 providedIn: "root" 或直接将它们添加到 app.module providers 没有区别。

注意:我不希望 Service1 依赖于其他服务,即我不希望 service1 调用其他服务删除方法

Satckblitz

出于优化原因,

Angular 不会创建服务,直到第一次需要它为止。此外,如果您的服务未在代码中的任何地方使用,Tree-shaking 会将其从生产代码中删除。有关详细信息,请查看有关 Tree-shakable providers.

的文档

我认为对于这种情况,更好的解决方案是为所有服务定义一个通用接口并使用多个提供程序。这意味着您为同一接口提供多种服务。然后,您可以一次将所有服务注入组件并循环遍历它们并调用 delete 或添加另一个中间服务来执行此操作(如果您不想在组件中使用逻辑)。然后,当您添加一项新服务时,您只需将其作为另一个提供商提供,一切都会自动运行。这样服务是完全独立的,组件或父服务只与抽象接口对话。

这是此类解决方案的示例代码。

export abstract class ServiceBase {
  public abstract delete(id: string): void;
}

@Injectable()
export class Service1Service extends ServiceBase {
  constructor() {
    super();
    console.log("Service1Service.constructor");
  }

  delete(id: string) {
    console.log("service1.delete");
  }
}

@Injectable()
export class Service2Service extends ServiceBase {
  constructor() {
    super()
    console.log("Service2Service.constructor");
  }

  delete(id: string) {
    console.log("service2.delete");
  }
}

export class AppComponent {
  constructor(
    @Inject(ServiceBase)private services: ServiceBase[],
    ) {}

  delete() {
    this.services.forEach((service) => service.delete());
  }
}

然后在应用程序模块中将服务注册为多提供商。

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],
  providers: [
    { provide: ServiceBase, useClass: Service1Service, multi: true },
    { provide: ServiceBase, useClass: Service2Service, multi: true }
  ]
})
export class AppModule { }

这是实现此解决方案的 link 到 fork of your StackBlitz

还有一个变通方法可以让您的解决方案工作,但不是很干净,所以我不建议使用它。为此,您需要强制创建子服务。我发现的一种方法是提供一个自定义应用程序初始化器,它依赖于 Service2Service,这将强制创建。这是建议此解决方案的 的 link。

这是您案例的示例:

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],
  providers: [{
    provide: APP_INITIALIZER,
    useFactory: () => () => {},
    deps: [Service2Service],
    multi: true
  }]
})
export class AppModule { }

实施此解决方法的 link 到 fork of your StackBlitz