【问题标题】:How to delete all related records in angular from multiple modules如何从多个模块中删除所有相关记录
【发布时间】:2020-02-05 03:28:18
【问题描述】:

我的 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 angular-services solid-principles


    【解决方案1】:

    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 { }
    

    这是实现此解决方案的fork of your StackBlitz 的链接。

    还有一个解决方法可以让您的解决方案不那么干净,所以我不建议使用它。为此,您需要强制创建子服务。我发现的一种方法是提供一个自定义应用程序初始化程序,它依赖于 Service2Service,这将强制创建。这是一个指向建议此解决方案的 post 的链接。

    这是您的案例的示例:

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

    实现此解决方法的fork of your StackBlitz 的链接。

    【讨论】:

      猜你喜欢
      • 2019-08-26
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-22
      • 2017-12-23
      相关资源
      最近更新 更多