Shining
Shining

Reputation: 465

Dynamic loader component with multiple component render

I'm looking for a solution to render dynamically some component in my angular application. So I feel the best approche is to look into https://angular.io/guide/dynamic-component-loader but this is not exactly what I'm looking for.

Just a bit of context, let's say your application permit to your users to see offers depending on their profile/eligibility. My application will do some request and at the end you can consider that we are able to build some methods like

isEligibleToFirstOffer() : boolean
isEligibleToSecondOffer() : boolean
isEligibleToThirdOffer() : boolean

Each offer is really specific and have different business logic that we can't just create a generic component with inputs, I would like to separate each offer in his own component to isolate as much as possible the logic by type of offers.

What I want to achieve is to build a OffersWrapper component which take as input an array of component classes and render it in a main container.

This array would be build with the previous logic, something like:

const componentsToRender = [
  ...(isEligibleToFirstOffer() ? [FirstOfferComponent] : []),
  ...(isEligibleToSecondOffer() ? [SecondOfferComponent] : []),
  ...(isEligibleToThirdOffer() ? [ThirdOfferComponent] : [])
]

Now the question is, what is the best approach to give this array to a generic component and make them render dynamically ?

We could also improve a bit the componentsToRender to be able to inject also data, but this is not the main issue of this question, anyway it could be interesting to give a full answer for futur dev who want to take a look at this solution.

const componentsToRender: {component: any, data: any}[]

at the end, the solution would give us the ability to write this kind of code:

<html>
  <body>
    <main>
      <component-wrapper [components]=componentsToRender></component-wrapper>
      <router-outlet></router-outlet>
    </main>
  </body>
</html>

Thanks!

Upvotes: 3

Views: 107

Answers (1)

Sergey
Sergey

Reputation: 7692

From the question, it appears that you have a set of components and you know what you want to render and for what cases upfront.

If so, then there is not so much dynamic. You can encapsulate everything in a component. The component will decide what to render and when. If needed an additional service could be created to offload decision logic from the component.

Could be as simple as

@Component({
  template: `
  <component-a *ngIf="condition1"></component-a>
  <component-b *ngIf="condition2"></component-b>
  <component-c *ngIf="condition3"></component-c>
`
})
export class Component {
  condition1: boolean;
  condition2: boolean;
  condition3: boolean;

  ngOnInit() {
    this.service.getData().subscribe(res => {
      // set the conditions here
    });
  }
}

If you need to show offers in a queue manner by any chance, then you could make this queue in the ngOnInit.

For example

@Component({
  template: `
  <component-a *ngIf="queue[0] === 'component-a'" (close)="queue.shift()"></component-a>
  <component-b *ngIf="queue[0] === 'component-b'" (close)="queue.shift()"></component-b>
  <component-c *ngIf="queue[0] === 'component-c'" (close)="queue.shift()"></component-c>
`
})
export class Component {
  queue = []; // ['component-a', 'component-b'] for example

  ngOnInit() {
    this.service.getData().subscribe(res => {
      // set the queue here
    });
  }
}

Upvotes: 1

Related Questions