Home > Software design >  What is the recommended way to use domain-specific services as part of common services in angular?
What is the recommended way to use domain-specific services as part of common services in angular?

Time:09-21

I’m a beginner in angular.

I have a lot of code that is repeated in many of my components. Something like this:

onScroll() {
    this.pageNumber  ;
    if (this.pageNumber <= this.pageLimit) {
        if (this.tableMode === FormMode.READ) {
            this.domainSpecificService.fetchPage(this.pageNumber, this.pageSize).subscribe(responses => {
                this.entities.push(...responses.content);
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        } else if (this.tableMode === FormMode.FILTER) {
            if (this.pageNumber <= this.pageLimit) {
                this.domainSpecificService.fetchPage(this.pageNumber, this.pageSize, this.filter!).subscribe(responses => {
                    this.entities.push(...responses.content);
                    this.numberOfElements  = responses.numberOfElements;
                    this.totalElements = responses.totalElements;
                });
            }
        }
    }
}

openModal(formMode: FormMode, entity?: EntityType) {
    const modalRef = this.modalService.open(EntityModalComponent, { size: 'xl', scrollable: true });
    modalRef.componentInstance.formMode = formMode;
    modalRef.componentInstance.entity = entity;
    this.returnModalResult(modalRef);
}

returnModalResult(modalRef: NgbModalRef) {
    modalRef.componentInstance.returnedEntity.subscribe((response: { entity: EntityType, formMode: FormMode }) => {
        if (response.formMode === FormMode.CREATE) {
            this.pageNumber = 0;
            this.domainSpecificService.fetchPage(0, this.pageSize).subscribe(responses => {
                this.entities = [...responses.content];
                this.numberOfElements = 0;
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        } else if (response.formMode === FormMode.UPDATE) {
            let itemIndex = this.entities.findIndex(item => item.id == response.entity.id);
            this.entities[itemIndex] = response.entity;
        } else if (response.formMode === FormMode.FILTER) {
            this.filter = response.entity;
            this.tableMode = FormMode.FILTER;
            this.pageNumber = 0;
            this.domainSpecificService.fetchPage(0, this.pageSize, this.filter).subscribe(responses => {
                this.entities = [...responses.content];
                this.numberOfElements = 0;
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        }
    })
}

The domainSpecificService and modal are the only ones that vary from component to component. I would like to know what is the recommended method for such cases.

Seperate service where we pass the domainSpecificService as an argument from the component?: onScroll(data: ComponentState, apiService: any)

...Or component inheritance?

I am currently using swagger to generate the api layer, so I can't add a crud interface to it. Although on the any type, I can call any method without interfaces, but it doesn't look nice (apiService.fetchPage(...)).

CodePudding user response:

I would use component inheritance.

You can then also define an api interface without putting it on the domain specific services. You can still get type checking in the base component and when you use the super constructor.

Move all variables that are accessed into the base component and replace all references to this.domainSpecificService with this.apiService:

// base-table.component.ts;
interface ApiService {
   fetchPage: (pageNumber: number, pageSize: number, filter: any) => Observable<any>;
}

@Directive()
public BaseTableComponent {
  public pageNumber: number;
  public pageSize: number;
  public pageLimit: number;
  public entities: any[];
  public numberOfElements: number;
  public totalElements: number;
  public tableMode: FormMode;
  public filter: any;

  constructor(protected apiService: ApiService, protected modalService: ModaleService) {}

onScroll() {
    this.pageNumber  ;
    if (this.pageNumber <= this.pageLimit) {
        if (this.tableMode === FormMode.READ) {
            this.apiService.fetchPage(this.pageNumber, this.pageSize).subscribe(responses => {
                this.entities.push(...responses.content);
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        } else if (this.tableMode === FormMode.FILTER) {
            if (this.pageNumber <= this.pageLimit) {
                this.apiService.fetchPage(this.pageNumber, this.pageSize, this.filter!).subscribe(responses => {
                    this.entities.push(...responses.content);
                    this.numberOfElements  = responses.numberOfElements;
                    this.totalElements = responses.totalElements;
                });
            }
        }
    }
}

openModal(formMode: FormMode, entity?: EntityType) {
    const modalRef = this.modalService.open(EntityModalComponent, { size: 'xl', scrollable: true });
    modalRef.componentInstance.formMode = formMode;
    modalRef.componentInstance.entity = entity;
    this.returnModalResult(modalRef);
}

returnModalResult(modalRef: NgbModalRef) {
    modalRef.componentInstance.returnedEntity.subscribe((response: { entity: EntityType, formMode: FormMode }) => {
        if (response.formMode === FormMode.CREATE) {
            this.pageNumber = 0;
            this.apiService.fetchPage(0, this.pageSize).subscribe(responses => {
                this.entities = [...responses.content];
                this.numberOfElements = 0;
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        } else if (response.formMode === FormMode.UPDATE) {
            let itemIndex = this.entities.findIndex(item => item.id == response.entity.id);
            this.entities[itemIndex] = response.entity;
        } else if (response.formMode === FormMode.FILTER) {
            this.filter = response.entity;
            this.tableMode = FormMode.FILTER;
            this.pageNumber = 0;
            this.apiService.fetchPage(0, this.pageSize, this.filter).subscribe(responses => {
                this.entities = [...responses.content];
                this.numberOfElements = 0;
                this.numberOfElements  = responses.numberOfElements;
                this.totalElements = responses.totalElements;
            });
        }
    })
}
}

Use this in a domain component like this:

// example-domain.component.ts

@Component(...)
public ExampleDomainComponent extends BaseTableComponent {
  constructor(domainService: DomainSpecificService, modalService: ModalService) {
    super(domainService, modalService);
  }
}
  • Related