Search code examples
angularabstract-class

dynamic, multiple provider for abstract class in angular 4


I am using an abstract class to show some data from different sources. Every source is injected in the abstract class to show the data in a component.

This is my Component, which is using the abstract class to get the data:

    import {AbstractclassService} from '../../../../abstractclass.service';
    import {Source2-Service} from '../../../../Source2.service';
    import {Source1-Service} from '../../../../Source1.service';

    @Component({
      selector: 'app-gauge',
      templateUrl: './gauge.component.html',
      providers: [
        {
          provide: AbstractclassService,
          useValue: Source1-Service , Source2-Service 
          multi: true
        }
    ],
     styleUrls: ['./gauge.component.css']
    })

    export class GaugeComponent implements  OnInit {

    data = [
        {
          name: 'test',
          value: 'test'
        }
      ];

      constructor( public abstractclassService: AbstractclassService  ) {}


      ngOnInit () {

        this.abstractclassService.onMessage = (msg: string) => {
          this.data = [{name: 'test', value: msg}];
      };


    }

And this is my abstract-class as service:

@Injectable()
export abstract class AbstractclassService {


  public onMessage(msg: string): void {
    console.log("Testing");
  }

}

Now, i didn't get it how to inject in useValue the different sources?


Solution

  • Use value in provider is not the good way for your use case.

    Source1-Service and Source2-Service must be classes which extends the abstract class. After that you inject into two distinct providers your services.

    When a class extends an abstract class, the extended classes have to define the method onMessage (here).

    So, your component can be look like:

    import { Component, Inject } from '@angular/core';
    import { Observable } from "rxjs"
    
    abstract class AbstractClassService{
      abstract onMessage(msg: string): {name: string, value: string}
    }
    
    class Source1-Service extends AbstractClassService{
      onMessage(msg: string) {
        return {name: "test", value: msg}
      }
    }
    
    class Source2-Service extends AbstractClassService{
      onMessage(msg: string) {
        return {name: "test2", value: msg}
      }
    }
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ],
      providers: [
        {provide: "Impl1", useClass: Source1-Service},
        {provide: "Impl2", useClass: Source2-Service}
      ]
    })
    export class AppComponent  {
    
      msg1: {name: string,value:string}[]
      msg2: {name: string,value:string}[]
    
      constructor(@Inject("Impl1") private service1:AbstractClassService,
                  @Inject("Impl2") private service2:AbstractClassService) {
    
          this.msg1 = [this.service1.onMessage("msg1")]
          this.msg2 = [this.service2.onMessage("msg2")]
      }
    
    }
    

    For the full code: https://stackblitz.com/edit/angular-e8sbg8?file=app%2Fapp.component.ts

    For futher

    I think it's not a good idea to use the abstract class in this case. You should prefer to use an interface

    And, I invite to you to read the DI angular documentation here: https://angular.io/guide/dependency-injection#providers to have more information