Search code examples
angulardependency-injectionangular-providers

How to alternate service class implementation on-the-fly in component based provider?


I'm still new in Angular. Currently, I have two implementation of REST service based on one abstract class in one of our component. Just like this scenario, the only difference is that I inject the service in component level:

@Component({
  selector: 'this-is-tag',
  template: htmlStr,
  providers: [{ provide: RESTToken, useClass: FirstRESTService }],
  ...

Question is, can I switch the implementation on the runtime, based on specific config? Or, should I use different approach for this problem?

EDIT:

Seems like I need to use interface, instead of abstract class here. link


Solution

  • So, I ended up using interface, instead of abstract class for this solution. And also, the inheritance method fails when I tried to use base class for two of my services, like this question.

    This is my working solution, both in JIT and AOT compilation:

    @Component({
      selector: 'invoice-list',
      templateUrl: './invoice-list.component.html',
      providers: [{ provide: RESTToken, useClass: InvoiceRESTService }],
      ...
    

    The service that is actually being used in the component:

    @Injectable()
    export class InvoiceRESTService {
    
        public invoiceType: InvoiceType;
    
        constructor(
            private _visma: VismaRESTService,
            private _fortnox: FortnoxRESTService
        ) {}
    
        public get instance(): RESTServiceInterface {
    
            if (this.invoiceType === InvoiceType.Visma) {
                return this._visma;
            } else if (this.invoiceType === InvoiceType.Fortnox) {
                return this._fortnox;
            } else {
                console.log('Please set the invoice type.');
            }
        }
    
    }
    

    The interface itself:

    export interface RESTServiceInterface {
    
      getExportDataFunctionURL(): string;
    
      // So far, only for Visma
      getAuthUrl?(): string;
    
      getButtonTitlle(): string;
    
      synchData(instanceUid: string, code?: string): Observable<Object>;
    
      updateInvoice(payload: any): Observable<Object>;
    
      // Loading messages
      getWaitingMessage(): string;
    
      getSuccessMessage(): string;
    
      getErrorMessage(code: VismaErrorCode | FortnoxErrorCode | BKErrorCode): string;
    
    }
    

    The services that implement the interface:

    @Injectable({
      providedIn: 'root'
    })
    
    export class FortnoxRESTService implements RESTServiceInterface {
       ...
       ...
       ...
    }
    
    
    @Injectable({
        providedIn: 'root'
    })
    
    export class VismaRESTService implements RESTServiceInterface {
       ...
       ...
       ...
    }