从AppModule到自定义库的Angular 7传递路由器

时间:2019-03-15 23:28:42

标签: angular dependency-injection angular-cli angular-library

我有一个使用Angular 7 CLI创建的自定义库。我在库中有一个服务来处理需要将路由器注入其中的身份验证。我将RouterModule添加到了import集合中,然后在我的应用程序(导入了该自定义库)中,使用路由调用RouterModule.forRoot()。不过,我始终从库内部收到错误"No provider for Router"(从技术上讲这是正确的,因为应该从根应用程序而不是库内部提供路由器)。

这是我图书馆的模块:

import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

import {
  MatTableModule, MatSelectModule, MatSortModule, MatRipple, MatSnackBarModule, MatProgressSpinnerModule,
  MatButtonModule, MatButtonToggleModule, MatInputModule, MatFormFieldModule, MatRippleModule
} from '@angular/material';

import { RubblWebCommonComponent } from './rubbl-web-common.component';
import { PermissionAnyDirective } from './directives/auth/permission-any.directive';
import { PermissionAllDirective } from './directives/auth/permission-all.directive';
import { UserService } from './services/user/user.service';
import { AuthGuard } from './guards/auth/auth.guard';
import { SearchHighlightPipe } from './azure-search/pipes/search-highlight/search-highlight.pipe';
import { AzureSearchService } from './azure-search/services/azure-search.service';
import { AzureSearchTableComponent } from './azure-search/components/azure-search-table/azure-search-table.component';
import { AuthenticationService } from './services/auth/authentication.service';
import { RouterModule } from '@angular/router';
import { IAuthenticationService } from './services/auth/authentication-service.interface';
import { LogService } from './services/core/log.service';

@NgModule({
  declarations: [
    RubblWebCommonComponent,
    PermissionAnyDirective,
    PermissionAllDirective,
    SearchHighlightPipe,
    AzureSearchTableComponent
  ],
  imports: [
    HttpClientModule,
    CommonModule,
    FormsModule,
    RouterModule,
    MatButtonModule,
    MatButtonToggleModule,
    MatFormFieldModule,
    MatInputModule,
    MatProgressSpinnerModule,
    MatRippleModule,
    MatSelectModule,
    MatSortModule,
    MatSnackBarModule,
    MatTableModule,
  ],
  exports: [
    RubblWebCommonComponent,
    PermissionAnyDirective,
    PermissionAllDirective,
    AzureSearchTableComponent
  ]
})
export class RubblWebCommonModule {
  public static forRoot() {
    return {
      ngModule: RubblWebCommonModule,
      providers: [
        UserService,
        AuthGuard,
        AzureSearchService,
        {provide: IAuthenticationService, useClass: AuthenticationService},
        LogService
      ]
    };
  }
}

我的图书馆的package.json:

{
  "name": "rubbl-web-common",
  "version": "0.0.1",
  "scripts": {
    "ng": "ng",
    "patch-common": "npm version patch",
    "build-common": "ng build rubbl-web-common && npm run build-documentation",
    "build-common-watch": "ng build rubbl-web-common --watch && npm run patch-common",
    "build-documentation": "npx compodoc -p tsconfig.lib.json --theme material --name \"rubbl-web-common documentation\"",
    "create-pull-request": "vsts code pr create --auto-complete",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "peerDependencies": {    
    "@angular/animations": "7.2.9",
    "@angular/cdk": "7.3.4",
    "@angular/common": "7.2.9",
    "@angular/compiler": "7.2.9",
    "@angular/core": "7.2.9",
    "@angular/forms": "7.2.9",
    "@angular/material": "7.3.4",
    "@angular/platform-browser": "7.2.9",
    "@angular/platform-browser-dynamic": "7.2.9",
    "@angular/router": "7.2.9",
    "applicationinsights-js": "1.0.20",
    "core-js": "2.6.5",
    "hammerjs": "2.0.8",
    "oidc-client": "1.7.0",
    "rxjs": "6.4.0",
    "tslib": "1.9.3",
    "zone.js": "0.8.29"},
    "dependencies": {

    },
  "devDependencies": {
    "@angular-devkit/build-angular": "0.13.6",
    "@angular-devkit/build-ng-packagr": "0.13.6",
    "@angular/cli": "7.3.6",
    "@angular/compiler-cli": "7.2.9",
    "@angular/language-service": "7.2.9",
    "@compodoc/compodoc": "1.1.9",
    "@types/jasmine": "3.3.9",
    "@types/jasminewd2": "2.0.6",
    "@types/node": "11.11.3",
    "codelyzer": "5.0.0-beta.1",
    "jasmine-core": "3.3.0",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "4.0.1",
    "karma-chrome-launcher": "2.2.0",
    "karma-coverage-istanbul-reporter": "2.0.5",
    "karma-jasmine": "2.0.1",
    "karma-jasmine-html-reporter": "1.4.0",
    "ng-packagr": "4.7.1",
    "protractor": "5.4.2",
    "ts-node": "8.0.3",
    "tsickle": ">=0.34.0",
    "tslint": "5.14.0",
    "typescript": "3.3.3333"
  }
}

我的应用程序的AppModule

export function createTranslateLoader(http: HttpClient) {
    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
    declarations: [
        AppComponent,
        CatalogListComponent,
        CatalogDetailComponent,
        AccountListComponent,
        AccountDetailComponent,
        InventoryDetailComponent,
        InventoryListComponent,
        AccountCreateComponent,
        UserListComponent,
        InventoryCreateComponent,
        UserCreateComponent,
        RoleComponent
    ],
    imports: [
        RouterModule.forRoot(routes),
        RubblWebCommonModule,
        CoreModule,
        SharedModule.forRoot(),
        PagesModule,

        LayoutModule,
        TranslateModule.forRoot({
            loader: {
                provide: TranslateLoader,
                useFactory: (createTranslateLoader),
                deps: [HttpClient]
            }
        })
    ],
    exports: [ RouterModule],
    providers: [
        UserService,
        AuthGuard,
        AzureSearchService,
        {provide: IAuthenticationService, useClass: AuthenticationService},
        LogService
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

和我的应用的angular.json

{
      "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
      "version": 1,
      "newProjectRoot": "projects",
      "projects": {
        "ng2angle": {
          "root": "",
          "sourceRoot": "src",
          "projectType": "application",
          "prefix": "app",
          "schematics": {
            "@schematics/angular:component": {
              "styleext": "scss"
            }
          },
          "architect": {
            "build": {
              "builder": "@angular-devkit/build-angular:browser",
              "options": {
                "outputPath": "dist",
                "index": "src/index.html",
                "main": "src/main.ts",
                "polyfills": "src/polyfills.ts",
                "tsConfig": "src/tsconfig.app.json",
                "assets": [
                  "src/favicon.ico",
                  "src/assets"
                ],
                "styles": [
                  "src/app/core/preloader/preloader.scss",
                  "src/styles.scss"
                ],
                "scripts": [
                  "node_modules/jquery/dist/jquery.js",
                  "src/app/core/preloader/preloader.js",
                  "node_modules/popper.js/dist/umd/popper.js",
                  "node_modules/chart.js/dist/Chart.bundle.js",
                  "node_modules/bootstrap/js/dist/util.js",
                  "node_modules/bootstrap/js/dist/modal.js",
                  "node_modules/bootstrap/js/dist/dropdown.js",
                  "node_modules/bootstrap/js/dist/tooltip.js",
                  "node_modules/moment/min/moment-with-locales.min.js"
                ]
              },
              "configurations": {
                "production": {
                  "fileReplacements": [],
                  "optimization": true,
                  "outputHashing": "all",
                  "sourceMap": false,
                  "extractCss": true,
                  "namedChunks": false,
                  "aot": true,
                  "extractLicenses": true,
                  "vendorChunk": false,
                  "buildOptimizer": true,
                  "budgets": [
                    {
                      "type": "initial",
                      "maximumWarning": "3mb",
                      "maximumError": "5mb"
                    }
                  ]
                }
              }
            },
            "serve": {
              "builder": "@angular-devkit/build-angular:dev-server",
              "options": {
                "browserTarget": "ng2angle:build"
              },
              "configurations": {
                "production": {
                  "browserTarget": "ng2angle:build:production"
                }
              }
            },
            "extract-i18n": {
              "builder": "@angular-devkit/build-angular:extract-i18n",
              "options": {
                "browserTarget": "ng2angle:build"
              }
            },
            "test": {
              "builder": "@angular-devkit/build-angular:karma",
              "options": {
                "main": "src/test.ts",
                "polyfills": "src/polyfills.ts",
                "tsConfig": "src/tsconfig.spec.json",
                "karmaConfig": "src/karma.conf.js",
                "styles": [
                  "src/app/core/preloader/preloader.scss",
                  "src/styles.scss"
                ],
                "scripts": [
                  "node_modules/jquery/dist/jquery.js",
                  "src/app/core/preloader/preloader.js",
                  "node_modules/popper.js/dist/umd/popper.js",
                  "node_modules/chart.js/dist/Chart.bundle.js",
                  "node_modules/bootstrap/js/dist/util.js",
                  "node_modules/bootstrap/js/dist/modal.js",
                  "node_modules/bootstrap/js/dist/dropdown.js",
                  "node_modules/bootstrap/js/dist/tooltip.js",
                  "node_modules/moment/min/moment-with-locales.min.js"
                ],
                "assets": [
                  "src/favicon.ico",
                  "src/assets"
                ]
              }
            },
            "lint": {
              "builder": "@angular-devkit/build-angular:tslint",
              "options": {
                "tsConfig": [
                  "src/tsconfig.app.json",
                  "src/tsconfig.spec.json"
                ],
                "exclude": [
                  "**/node_modules/**"
                ]
              }
            }
          }
        },
        "ng2angle-e2e": {
          "root": "e2e/",
          "projectType": "application",
          "prefix": "",
          "architect": {
            "e2e": {
              "builder": "@angular-devkit/build-angular:protractor",
              "options": {
                "protractorConfig": "e2e/protractor.conf.js",
                "devServerTarget": "ng2angle:serve"
              },
              "configurations": {
                "production": {
                  "devServerTarget": "ng2angle:serve:production"
                }
              }
            },
            "lint": {
              "builder": "@angular-devkit/build-angular:tslint",
              "options": {
                "tsConfig": "e2e/tsconfig.e2e.json",
                "exclude": [
                  "**/node_modules/**"
                ]
              }
            }
          }
        }
      },
      "defaultProject": "ng2angle"
    }

1 个答案:

答案 0 :(得分:1)

路由器模块可以多次导入,只要您仅以根(RouterModule.forRoot(routes))定义一次即可。在单独的文件app-routing.module.ts中定义主路由器并将其导入app.module.ts是一种常见的模式。另外,每个功能模块都可以具有自己的路由器模块,该模块将定义为RouterModule.forChild(childroutes)。最终结果是,只有一个路由器模块实例,其中每个模块都向路由树贡献自己的路由。我认为,就您而言,您可以将您的自定义模块想象为“功能”

some edits/checks to be made (FOR YOUR CODE):  
   app.module.ts: 
       - remove the export of the RouterModule
       - be sure the routes are ok 
   library module
       - change the import: RouterModule.forChild([]);   //or the routes you want