首页 > 解决方案 > 传入的类型不是 ComponentType,它没有 'ɵcmp' 属性。路由未使用配置服务注入注入 AngularRouter

问题描述

我正在使用应用初始化程序在启动之前尝试从数据库中填充路由。它应该非常简单,但我收到了上面的错误,我不知道为什么。传入的类型不是 ComponentType,它没有 'ɵcmp' 属性。它似乎绘制了路线,控制台日志实际上有回复。只是当我单击链接或尝试直接路由到我的动态路由之一时它会失败。在我的应用程序模块上,我还设置了入口组件,并尝试在此处设置它们以取得良好的效果,但无济于事。

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

模板配置服务

 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;
        }
    }

应用路由模块

 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);
        })
    
      };
    }

路由器接口 `

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

`

和我的模拟 json 数据库 `

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

`

标签: angulartypescriptangular-routingangular11service-factory

解决方案


整个 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);


      });

  };
}

推荐阅读