Alaa Khalila
Alaa Khalila

Reputation: 169

Reusable component using ngOnInit

I'm trying to make a reusable component but I can't find a way to make ngOnInit get the data depends on the component input.

Service :

export class BookService {
  private apiUrl = 'http://localhost:5000/';
  constructor(private http: HttpClient) {}
  getBooks(): Observable<DragItem[]> {
    return this.http.get<DragItem[]>(this.apiUrl + 'books');
  }
  getNames(): Observable<DragItem[]> {
    return this.http.get<DragItem[]>(this.apiUrl + 'names');
  }
}

the component :

  ngOnInit(): void {
    this.booksService
      .getBooks() // => how can I make this dynamic depends on component props so I can pick (getBooks / getNames)
      .subscribe((response) => (this.items = response));
  }

Upvotes: 0

Views: 287

Answers (3)

Alaa Khalila
Alaa Khalila

Reputation: 169

solved by changing the service to one method

service :

export class BookService {
  private apiUrl = 'http://localhost:5000/';
  constructor(private http: HttpClient) {}

  getData(str: string): Observable<DragItem[]> {
    return this.http.get<DragItem[]>(this.apiUrl + str);
  }
}

component :

  @Input() type: string = '';
  @Input() methodName = '';
  items: DragItem[] = [];
  selectedItems: DragItem[] = [];
  searchInput = new FormControl('');
  page: number = 1;
  pageSize: number = 10;

  constructor(private booksService: BookService) {}

  ngOnInit(): void {
    this.booksService
      .getData(this.methodName)
      .subscribe((response: DragItem[]) => (this.items = response));
  }

Upvotes: 0

John Malkoln
John Malkoln

Reputation: 461

You can use Angular's dependency providers to achieve your goal. Check details: https://angular.io/guide/dependency-injection-providers#specifying-an-alternative-class-provider

First of all we need base service:

export abstract class DataItemsService {
    abstract fetch(): Observable<DataItem[]>;
}

This service needs to be injected to your reusable component:

export class FeatureComponent implements OnInit {

    dataItems$: Observable<DataItem[]>;

    constructor(private readonly dataItemsService: DataItemsService) {}

    ngOnInit(): void {
        this.dataItems$ = this.dataItemsService.fetch();
    }
}

Then implement any services you need:

@Injectable({
    providedIn: 'root'
})
export class BookService implements DataItemsService {
    fetch(): Observable<DataItem[]> {
        return of([{value: 'book1'}, {value: 'book2'}]);
    }
}

@Injectable({
    providedIn: 'root'
})
export class NamesService implements DataItemsService {
    fetch(): Observable<DataItem[]> {
        return of([{value: 'name1'}, {value: 'name2'}]);
    }
}

The only left is to specify the desired service in providers list of the parent component.

Using BookService:

@Component({
    selector: 'app-demo1',
    template: `
        <app-feature></app-feature>
    `,
    providers: [
        { provide: DataItemsService, useClass: BookService },
    ],
})
export class Demo1Component {}

Using NameService:

@Component({
    selector: 'app-demo1',
    template: `
        <app-feature></app-feature>
    `,
    providers: [
        { provide: DataItemsService, useClass: NamesService },
    ],
})
export class Demo1Component {}

Upvotes: 0

Apoorva Chikara
Apoorva Chikara

Reputation: 8773

You can use @Input/Suscriber/localstorage in the component to get which method you want to call dynamic method. I assume you already have the name of dynamic method, you can call it like this:

public methodName: string = "Assign your method name dynamically to it"
ngOnInit(): void {
    this.booksService[`${methodName}`]() 
      .subscribe((response) => (this.items = response));
  }

Upvotes: 1

Related Questions