Home > Enterprise >  Use component @Input as injected service constructor param - or use ServiceFactory pattern instead?
Use component @Input as injected service constructor param - or use ServiceFactory pattern instead?

Time:11-17

in Angular 12 I have a simplified component like that:

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.less']
})
export class ListComponent implements OnInit {

  @Input() dataType: string;

  items: Item[] = [];

  constructor(private ds: DataStorageService) { }

  ngOnInit(): void {
    this.items = this.ds.fetchAll();
  }

and my simplified DataStorageService looks like this:

@Injectable({providedIn: 'root'})
export class DataStorageService {

  private readonly dataType: string;
  private readonly apiEndpoint: string;

  constructor(dataType: string, private http: HttpClient) {
    this.dataType = dataType;
    this.apiEndpoint = environment.config.urlLogin   '/api/'   this.dataType;
  }

  fetchAll(string) {
    return this.http.get(this.apiEndpoint) as Observable<Item[]>;
  }

I want to use

<app-list data-type="products">

and using products as a value in my DataStorageService - without passing it in every function which might make us of it.

I tried injecting it with useValue and was thinking about using a ServiceFactory - but I am stuck and don't know how to continue from here.

Especially since Item is my generic Type for which I have interface extensions again based on dataType string, e.g. Product extends Item for dataType products.

CodePudding user response:

Your service factory can look something like this:

@Injectable(providedIn: 'root')
export class DataServiceFactory {
  constructor(private http: HttpClient) {}
  
  getDataService(dataType: string): DataStorageService {
    return new DataStorageService(dataType, this.http);
  }
}

Then your list component could look like this:

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.less']
})
export class ListComponent implements OnInit {

  @Input() dataType: string;

  items: Item[] = [];
  private dataService: DataStorageService;

  constructor(private serviceFactory: DataServiceFactory) { }

  ngOnInit(): void {
    this.dataService = this.serviceFactory.getDataService(this.dataType);
    this.dataService.fetchAll().subscribe(items => this.items = items);
  }
}

Your DataStorageService does not even need the Injectable decorator at this point, as it will be manually instantiated. You don't rely on the injector to provide it for you.

  • Related