5
votes

We have a requirement where depending on a static/global setting which will be set depending on the customer they want a different component to load for a route. The reason being they want slightly different functionality for a part of the application so we are going to write a component for each that caters for their scenarios. Is there a way to choose the component for a route dynamically/at runtime and keep the same route/url. Below is a simplified example of what we would like to achieve:

Component1:

@Component({
  selector: 'customeronecomponent',
  templateUrl: './customeronecomponent.component.html'
})

export class CustomerOneComponent implements OnInit {
}

Component2:

@Component({
  selector: 'customertwocomponent',
  templateUrl: './customertwocomponent.component.html'
})

export class CustomerTwoComponent implements OnInit {
}

Route:

{ path: 'home', component: CustomerComponentProvider },

In this instance the CustomerComponentProvider will internally check the setting and either return CustomerOneComponent or CustomerTwoComponent.

In angular2/4 is that the best way to do this or is it better to have a single component and on that component load the right component, the downside I see there is we would have three components instead of two for each route we need this.

4
Cant you have two route, home-1 and home-2 both registered and based upon customer condition you navigate to either one of them? may be this is totally not applicable, you can provide more detail in your question. - Madhu Ranjan
I have tried to add more information, I cannot find a way to do this in Angular, there may not be a way in which case hopefully someone can provide the best option that keeps the URL the same. We are hoping to use this for additional components and don't want to add route-1, route-2, etc. for many components but rather have providers that get the right component as there may be more than just 2 options. - user351711
How exactly should that component resolve be performed? Is the correct component read from config and then whole application restarted (browser refresh) or you need on-the-fly change without app restart? - dee zg
No on the fly change needed, there will be a const value set and on deployment will be changed and not changed again for that deployment. - user351711
You can use a global variable in routing configuration. The routing generator would be a function that build the routing array based on that/those global variables. - Leonardo Neninger

4 Answers

8
votes

You may already be doing this internally in your CustomerComponentProvider, but in case not - there is Dynamic Component Loader.

The example given in the docs is a bit busy, so here's a dumbed-down version: Plunker

Essentially, a wrapper is used to switch between components depending on config string passed in, or retrieved from a service.

import { Component, Input, OnChanges, 
  ComponentFactoryResolver, ViewContainerRef } from '@angular/core';
import { Component1 } from './component1';
import { Component2 } from './component2';

@Component({
  selector: 'component-wrapper',
  template: `<div></div>`
})
export class ComponentWrapper implements OnChanges {

  @Input() config;

  private componentMap = {
    component1 : Component1,
    component2 : Component2,
  }

  constructor(
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) {}

  ngOnChanges() { 
    this.setComponent();
  }

  setComponent() {
    const componentFactory = this.componentFactoryResolver
      .resolveComponentFactory(this.componentMap[this.config]);
    this.viewContainerRef.clear();
    this.viewContainerRef.createComponent(componentFactory);
  }

}
2
votes

in the template for CustomerComponentProvider , you can display either of the components by checking the setting

say your setting returns the type on a customer (1/2) based on which you can set showCustomerOne/showCustomerTwo to true

<app-customer-one-component *ngIf="showCustomerOne"> </app-customer-one-component>
<app-customer-two-component *ngIf="showCustomerTwo"> </app-customer-two-component>

check for the setting in constructor of CustomComponentProvider and set either showCustomerOne to True or showCustomerTwo to True.

  showCustomerOne;
  showCustomerTwo;

  constructor() {
     if(customer.type == '1'){
         this.showCustomerOne = true;
      }else if (customer.type == '2'){
         this.showCustomerTwo = true;
      }
  };
1
votes

You can update the router configuration whenever you want, so depending on the setting you have you can add or update a route config to resolve to the component that you need.

Have a look at the config property or maybe more suited for this, the resetConfig method on the Router. You could inject the Router in the component where you want to handle this and update the routes according to the global setting that you have.

0
votes

You could try something like reflect-metadata

You would define metadata key for type and then get the type of the component based on whatever is in your config and feed that into routeConfig or by resetting the router through router.resetConfig as @Adrian Faciu already suggested:

https://angular.io/api/router/Router#resetConfig