I am using an app initializer to try and populate the routes from a database prior to launch. it should be very straightforward but I am getting the error above and I am not sure why. The type passed in is not ComponentType, it does not have 'ɵcmp' property. it appears to draw the routes and the console log actually has a reply. it's just when I click a link or try to route directly to one of my dynamic routes it fails. on my app module, I also have the entry components set and tried to set them here as well for good measure but to no avail.

Angular Info:

    Angular CLI: 11.1.4
Node: 14.7.0
OS: darwin x64

Angular: 11.1.2
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1101.4
@angular-devkit/build-angular   0.1101.4
@angular-devkit/core            11.1.4
@angular-devkit/schematics      11.1.4
@angular/cli                    11.1.4
@schematics/angular             11.1.4
@schematics/update              0.1101.4
rxjs                            6.6.3
typescript                      4.1.3

Template Config Service

 import { RouteInterface } from './../../interfaces/route.interface';
    import { HttpClient, HttpHeaders } from '@angular/common/http';
    import { Injectable } from '@angular/core';
    import { map } from 'rxjs/operators';
    @Injectable({
      providedIn: 'root'
    })
    export class TemplateConfigService {
        // tslint:disable-next-line: variable-name
        private _configData ?: RouteInterface;
        // tslint:disable-next-line: variable-name
        private _promise ?: Promise<any>;
        // tslint:disable-next-line: variable-name
        private _promiseDone = false;
    
        constructor(private http: HttpClient) { }
      
    
        loadConfig(): Promise<any> {
          console.log('started')
          const url = '/assets/json/config/route.config.json';
    
          if (this._promiseDone) {
                console.log('In Config Service. Promise is already complete.');
                return Promise.resolve();
            }
    
          if (this._promise != null) {
                console.log('In Config Service. Promise exists.  Returning it.');
                return this._promise;
            }
     
          console.log('In Config Service. Loading config data.');
          this._promise = this.http
                .get(url, { headers: new HttpHeaders() }).pipe(
                // map((res: Response) => res))
                map((res: any) => {
                  res = res;
                  return res
                })
                )
                .toPromise()
                .then((res: any) => { 
                  // console.log(res)
                  this._configData = res; this._promiseDone = true; return this._configData})
                .catch((err: any) => { this._promiseDone = true; return Promise.resolve(); });
          return this._promise;
        }
     
        get configData(): any {
          console.log('should be interface', this._configData)
          return this._configData;
        }
    }

AppRouting Module

 import { HomeComponent } from './components/home/home.component';
    
    import { TemplateConfigService } from './services/template-config.service';
    import { APP_INITIALIZER, Component, ComponentDecorator, ComponentFactoryResolver, Injector, NgModule, Type } from '@angular/core';
    import { Router, RouterModule, Routes } from '@angular/router';
    
    const routes: Routes = [
      {path: '', redirectTo: 'home', pathMatch: 'full'},
      {path: 'home', component: HomeComponent}
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule],
      providers: [
          TemplateConfigService,
          { provide: APP_INITIALIZER, useFactory: configServiceFactory, deps: [Injector, TemplateConfigService], multi: true },
      ]
    })
    export class AppRoutingModule {
      constructor(){
      
        // console.log('data', this.configService.configData)
      }
    }
    // tslint:disable-next-line: ban-types
    export function configServiceFactory(injector: Injector, configService: TemplateConfigService): Function {
      return async () => {
          console.log('Getting config in routing module');
          const res = await configService
          .loadConfig().then((res)=>{
          res = res;
          const router: Router = injector.get(Router);
          res.forEach(
        
            (item: any) => {
            console.log(item) 
            router.config.unshift({path: item.path, component: item.comp as Type<Component>})
            console.log('router-config', router.config);
          });
          router.resetConfig(router.config);
        })
    
      };
    }

router interface `

import { Component } from '@angular/core';
export interface RouteInterface {
   routes: Array<[RouterInterface]>;
  }
interface RouterInterface{
    path: string;
    comp: Component;
}

`

and my mock json database `

[{
    "path": "one",
    "comp": "OneComponent"
},
{
    "path": "two",
    "comp": "TwoComponent"
},
{
    "path": "three",
    "comp": "ThreeComponent"
}]

`

2

There are 2 answers

0
Chris Burd On

I ended up using a generic component called outlet.
`

router.config.unshift({path: path$,

                 component:
                   OutletComponent

          });

`

no matter what resolver i use it doesn't work any other way. maybe someday someone can come up with a different work around - but I'm not spending any more cycles on this it will work the way i need it to work.

0
Chris Burd On

entire app-routing.module.ts

    import { APP_INITIALIZER, ComponentFactoryResolver, Injector, NgModule, ViewContainerRef } from '@angular/core';
import { Router, RouterModule, Routes, ɵEmptyOutletComponent } from '@angular/router';

import { retry } from 'rxjs/operators';
import { RouterInterface } from 'src/interfaces/route.interface';

import { OutletComponent } from './components/outlet/outlet.component';
import { OutletService } from './services/outlet.service';
import { TemplateConfigService } from './services/template-config.service';

const routes: Routes = [
  {path: '', redirectTo: 'home', pathMatch: 'full'},
  {path: 'home', component: OutletComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [
      TemplateConfigService, OutletService,
      { provide: APP_INITIALIZER, useFactory: configServiceFactory, deps: [Injector, TemplateConfigService, OutletService], multi: true },
  ]
})
export class AppRoutingModule {
  constructor(private outletService: OutletService, private resolver: ComponentFactoryResolver){
    outletService.subData$.subscribe((data) => {
      data = data;
      return data;
      // sessionStorage.setItem('template', JSON.stringify(data));
    });
    // console.log('data', this.configService.configData)
  }
}
// tslint:disable-next-line: ban-types
export function configServiceFactory(injector: Injector, configService: TemplateConfigService,
                                     outletService: OutletService): any {
  return async () => {
      console.log('Getting config in routing module');
      const res = await configService
      // tslint:disable-next-line: no-shadowed-variable
      .loadConfig().then((res) => {
      res = res;
      const router: Router = injector.get(Router);
    //  const componentItem = '';
    // const instance  = this.elRef.createComponent(componentFactory, 0).instance;
    /** get and or set langkey */
      const langKey = localStorage.getItem('langKey');
      if (langKey === null) {
        localStorage.setItem('langKey', 'us-english');
        retry(2);
      }
      // tslint:disable-next-line: no-non-null-assertion
      outletService.setViewportData(langKey!);
      outletService.subData$.subscribe((data) => {
        data = data;
        return data;
        // sessionStorage.setItem('template', JSON.stringify(data));
      });

      res.forEach((item$: RouterInterface) => {
          console.log(item$);

          const path$ = item$.path;

          /** check if null or unknow and set variable langDefault */
              // tslint:disable-next-line: no-non-null-assertion
             //  outletService.headerData$.subscribe((dat: any) => {
             //   const data$ = {
             //     dat$: dat
             //   };

          router.config.unshift({path: path$,

                 component:
                   OutletComponent

          });
          console.log(router.config);

              });

      // });
      router.resetConfig(router.config);


      });

  };
}