Как удалить все связанные записи в angular из нескольких модулей

У меня есть несколько модулей в моем приложении angular, и каждый хранит некоторые данные, связанные с моими основными данными. Теперь я хочу удалить свои основные данные, а также все связанные данные.

Итак, я подумал о создании службы (service1) с методом удаления и наблюдаемого, чтобы другие службы знали, что эти данные будут удалены, а другие зависимые службы (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, и он будет открыт / закрыт, если в будущем будет разработан новый модуль для хранения некоторых других связанных данных с данными mater.

Проблема в том, что если я не добавляю Service2 в уже загруженные компоненты, angular их не создает, поэтому они не подписываются на службу для удаления данных.

Я пробовал использовать providedIn: "root" или напрямую добавлять их в app.module providers без разницы.

Примечание: я не хочу, чтобы Service1 зависел от других служб, т.е. я не хочу, чтобы service1 вызывал метод удаления других служб

Satckblitz


person Reza    schedule 07.10.2019    source источник


Ответы (1)


Angular не будет создавать сервис, пока он не потребуется в первый раз по причинам оптимизации. Также, если ваш сервис не используется где-либо в коде, Tree-shaking удалит его из производственного кода. Дополнительные сведения см. В документации о поставщиках с возможностью встряхивания дерева.

Я думаю, что для этого случая лучшим решением было бы определить общий интерфейс для всех сервисов и использовать несколько провайдеров. Это означает, что вы предоставляете несколько услуг для одного и того же интерфейса. Затем вы можете внедрить все службы сразу в компонент и выполнить цикл по ним и вызвать удаление для всех или добавить еще одну промежуточную службу, чтобы сделать это, если вам не нужна логика в компоненте. Затем, когда вы добавляете новую услугу, вы просто предоставляете ее как другого поставщика, и все будет работать автоматически. Таким образом, службы полностью независимы, и компонент или родительская служба взаимодействуют только с абстрактным интерфейсом.

Вот пример кода для такого решения.

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

Вот ссылка на форк вашего StackBlitz, который реализует это решение.

Существует также обходной путь для работы вашего решения, который не так чист, поэтому я не рекомендую его использовать. Для этого вам нужно принудительно создать дочерние службы. Один из способов, который я нашел, - это предоставить настраиваемый инициализатор приложения с зависимостью от Service2Service, который будет принудительно создавать. Вот ссылка на сообщение, предлагающий это решение.

Вот образец для вашего случая:

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

Ссылка на вилку ваш StackBlitz, который реализует этот обходной путь.

person AlesD    schedule 07.10.2019