1

我一直试图在生产中将 ng-zorro-antd 日期选择器组件渲染到我的客户端中,但是每次我使用 ng serve --prod 渲染它时,我都会收到此错误:

ERROR Error: Uncaught (in promise): NullInjectorError: StaticInjectorError(AppModule)[CdkConnectedOverlay -> Overlay]: 
  StaticInjectorError(Platform: core)[CdkConnectedOverlay -> Overlay]: 
    NullInjectorError: No provider for Overlay!
NullInjectorError: StaticInjectorError(AppModule)[CdkConnectedOverlay -> Overlay]: 
  StaticInjectorError(Platform: core)[CdkConnectedOverlay -> Overlay]: 
    NullInjectorError: No provider for Overlay!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:1225)
    at resolveToken (core.js:1463)
    at tryResolveToken (core.js:1407)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1311)
    at resolveToken (core.js:1463)
    at tryResolveToken (core.js:1407)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1311)
    at resolveNgModuleDep (core.js:18446)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:19135)
    at resolveDep (core.js:19506)
    at resolvePromise (zone.js:852)
    at resolvePromise (zone.js:809)
    at zone.js:913
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:24328)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask (zone.js:502)
    at ZoneTask.invoke (zone.js:487)

我正在使用以下软件包运行此应用程序:

  "name": "clocky-hub-client",
  "version": "0.1.0-alpha.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@agm/core": "1.0.0-beta.5",
    "@angular/animations": "8.0.0",
    "@angular/cdk": "8.0.0",
    "@angular/common": "8.0.0",
    "@angular/compiler": "8.0.0",
    "@angular/core": "8.0.0",
    "@angular/forms": "8.0.0",
    "@angular/http": "7.2.15",
    "@angular/material": "^8.1.4",
    "@angular/platform-browser": "8.0.0",
    "@angular/platform-browser-dynamic": "8.0.0",
    "@angular/router": "8.0.0",
    "@asymmetrik/ngx-leaflet": "5.0.2",
    "@fullcalendar/angular": "4.1.1",
    "@fullcalendar/core": "4.1.0",
    "@fullcalendar/daygrid": "4.1.0",
    "@ng-bootstrap/ng-bootstrap": "^5.1.0",
    "@ngrx/store": "7.4.0",
    "@ngrx/store-devtools": "7.4.0",
    "@swimlane/ngx-charts": "11.1.0",
    "@types/jest": "^24.0.18",
    "@types/jquery": "3.3.29",
    "angular-particle": "^1.0.4",
    "angular-particle-updated": "^1.0.4-1",
    "animate.css": "3.7.1",
    "chart.js": "2.8.0",
    "core-js": "3.1.3",
    "d3": "5.9.2",
    "date-fns": "1.30.1",
    "echarts": "4.2.1",
    "echarts-gl": "1.1.1",
    "highlight.js": "9.15.8",
    "leaflet": "1.5.1",
    "ng-zorro-antd": "7.4.1",
    "ng2-charts": "2.2.4",
    "ng2-dragula": "2.1.1",
    "ngx-echarts": "4.1.1",
    "ngx-highlightjs": "3.0.3",
    "ngx-malihu-scrollbar": "7.0.0",
    "particles.js": "2.0.0",
    "rxjs": "6.5.2",
    "tslib": "1.9.3",
    "web-animations-js": "2.3.1",
    "webpack-bundle-analyzer": "^3.4.1",
    "zone.js": "0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^0.800.0",
    "@angular/cli": "8.0.0",
    "@angular/compiler-cli": "8.0.0",
    "@angular/language-service": "8.0.0",
    "@types/jasmine": "3.3.13",
    "@types/jasminewd2": "2.0.6",
    "@types/node": "12.0.3",
    "codelyzer": "5.0.1",
    "jasmine-core": "3.4.0",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "4.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-coverage-istanbul-reporter": "2.0.5",
    "karma-jasmine": "2.0.1",
    "karma-jasmine-html-reporter": "1.4.2",
    "node-sass": "4.12.0",
    "protractor": "5.4.2",
    "ts-node": "8.2.0",
    "tslint": "5.16.0",
    "typescript": "3.4.5"
  }
}

编译选项是这样的:

src/tsconfig.app.json

{
  "extends": "../tsconfig.json",
  "typescript.tsdk": "./node_modules/typescript/lib",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "types": ["jest"],
    "experimentalDecorators": true
  },
  "exclude": [
    "test.ts",
    "**/*.spect.ts"
  ]
}

src/tslint.json

{
  "extends": "../tslint.json",
  "rules": {
    "directive-selector": [
      true,
      "attribute",
      "tc",
      "camelCase"
    ],
    "component-selector": [
      true,
      "element",
      "tc",
      "kebab-case"
    ]

  }
}

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ]
  }
}

我像这样导入它:

src/app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { StoreModule } from '@ngrx/store';

import { ROUTES, RoutingModule } from './routing/routing.module';
import { AppComponent } from './app.component';
import { LayoutModule } from './layout/layout.module';
import { PagesModule } from './pages/pages.module';
import { UIModule } from './ui/ui.module';

import {OverlayModule} from '@angular/cdk/overlay';

import { pageDataReducer } from './store/reducers/page-data.reducer';
import { appSettingsReducer } from './store/reducers/app-settings.reducer';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';

@NgModule({
     declarations: [
          AppComponent
     ],
     imports: [
         BrowserModule,
         LayoutModule,
         HttpClientModule,
         BrowserAnimationsModule,
         RouterModule.forRoot(ROUTES, { useHash: true }), 
         StoreModule.forRoot({
              pageData: pageDataReducer,
              appSettings: appSettingsReducer,
         }),
         RoutingModule,
         PagesModule,
         UIModule,
         OverlayModule,
         StoreDevtoolsModule.instrument({ maxAge: 25, logOnly:         
              environment.production })
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

src/app/pages.module.ts:

...
    import { NgZorroAntdModule } from 'ng-zorro-antd';
    import { NZ_I18N, en_US } from 'ng-zorro-antd';
    import { PageDatePickerComponent } from './ui/forms/date-picker/date- 
    picker.component';
...
    @NgModule({
        imports: [
            CommonModule,
            FormsModule,
            ReactiveFormsModule,
            RouterModule,
            NgbModule,
            ChartsModule,
            NgxChartsModule,
            NgxEchartsModule,
            AgmCoreModule.forRoot({
                apiKey: 'AIzaSyAbIFQ5ffgouATqs-sp8hgQf3zV4dTLzaU',
            }),
            LeafletModule,
            NgZorroAntdModule,
            HighlightModule.forRoot({ languages: hljsLanguages }),
            FullCalendarModule,
            UIModule,
            LayoutModule,
        ],
    declarations: [
    ...
        PageDatePickerComponent
    ...
    ],
    providers   : [ { provide: NZ_I18N, useValue: en_US } ]
    })
export class PagesModule { }

我在组件中这样使用它

src/app/pages/ui/forms/date-picker/date-picker.component.ts:

import { Component, OnInit, OnDestroy } from '@angular/core';

import * as getISOWeek from 'date-fns/get_iso_week';
import * as endOfMonth from 'date-fns/end_of_month';
import { en_US, zh_CN, NzI18nService } from 'ng-zorro-antd';

import { Store } from '@ngrx/store';
import { BasePageComponent } from '../../../base-page';
import { IAppState } from '../../../../interfaces/app-state';
import { HttpService } from '../../../../services/http/http.service';

@Component({
  selector: 'page-date-picker',
  templateUrl: './date-picker.component.html',
  styleUrls: ['./date-picker.component.scss']
})
export class PageDatePickerComponent extends BasePageComponent implements OnInit, OnDestroy {
  date = null;

  startValue: Date | null;
  endValue: Date | null;
  endOpen: boolean;
  isEnglish: boolean;
  ranges: any;

  dateMode: string;

  plainFooter: string;
  footerRender = () => 'extra footer';

  constructor(
    private i18n: NzI18nService,
    store: Store<IAppState>,
    httpSv: HttpService
  ) {
    super(store, httpSv);

    this.demoCode = `
<tc-form-group>
    <nz-date-picker></nz-date-picker>
</tc-form-group>`;

    this.pageData = {
      title: 'Date picker',
      loaded: true,
      breadcrumbs: [
        {
          title: 'UI Kit',
          route: 'dashboard'
        },
        {
          title: 'Forms',
          route: 'dashboard'
        },
        {
          title: 'Date picker'
        }
      ]
    };

    this.ranges = { Today: [new Date(), new Date()], 'This Month': [new Date(), endOfMonth(new Date())] };

    this.startValue = null;
    this.endValue = null;
    this.endOpen = false;
    this.isEnglish = true;
    this.plainFooter = 'plain extra footer';
    this.dateMode = 'time';
  }

  onChange(result: Date): void {
    console.log('onChange: ', result);
  }

  getWeek(result: Date): void {
    console.log('week: ', getISOWeek(result));
  }

  changeLanguage(): void {
    this.i18n.setLocale(this.isEnglish ? zh_CN : en_US);
    this.isEnglish = !this.isEnglish;
  }

  ngOnInit() {
    super.ngOnInit();
  }

  ngOnDestroy() {
    super.ngOnDestroy();
  }

  onStartChange(date: Date): void {
    this.startValue = date;
  }

  onEndChange(date: Date): void {
    this.endValue = date;
  }

  handleStartOpenChange(open: boolean): void {
    if (!open) {
      this.endOpen = true;
    }
    console.log('handleStartOpenChange', open, this.endOpen);
  }

  handleEndOpenChange(open: boolean): void {
    console.log(open);
    this.endOpen = open;
  }

  handleDateOpenChange(open: boolean): void {
    if (open) {
      this.dateMode = 'time';
    }
  }

  handleDatePanelChange(mode: string): void {
    console.log('handleDatePanelChange: ', mode);
  }

  onTimeChange(result: Date): void {
    console.log('Selected Time: ', result);
  }

  onOk(result: Date): void {
    console.log('onOk', result);
  }

  disabledStartDate = (startValue: Date): boolean => {
    if (!startValue || !this.endValue) {
      return false;
    }
    return startValue.getTime() > this.endValue.getTime();
  };

  disabledEndDate = (endValue: Date): boolean => {
    if (!endValue || !this.startValue) {
      return false;
    }
    return endValue.getTime() <= this.startValue.getTime();
  };
}

src/app/pages/ui/forms/date-picker/date-picker.component.html:

<div class="col-12">
    <tc-card [title]="'Range picker'">
        <tc-form-group>
            <nz-range-picker nzFormat="yyyy-MM-dd" (ngModelChange)="onChange($event)" nzShowTime></nz-range-picker>
        </tc-form-group>

        <tc-form-group class="mb-0">
            <div class="elem-list">
                <nz-date-picker
                    [nzDisabledDate]="disabledStartDate"
                    [nzFormat]="'yyyy-MM-dd'"
                    class="mr-4"
                    [(ngModel)]="startValue"
                    nzPlaceHolder="Start"
                    (ngModelChange)="onStartChange($event)"
                    (nzOnOpenChange)="handleStartOpenChange($event)"
                ></nz-date-picker>

                <nz-date-picker
                    [nzDisabledDate]="disabledEndDate"
                    [nzFormat]="'yyyy-MM-dd'"
                    [(ngModel)]="endValue"
                    nzPlaceHolder="End"
                    [nzOpen]="endOpen"
                    (nzOnOpenChange)="handleEndOpenChange($event)"
                    (ngModelChange)="onEndChange($event)"
                ></nz-date-picker>
            </div>
        </tc-form-group>
    </tc-card>
</div>

我正在使用带有 Angular 8 的 Ninet-NrGx 模板

它适用于开发模式而不是生产模式的事实让我非常好奇。

我尝试在 app.module 上导入 angular/cdk/overlay 模块,但没有成功。

4

2 回答 2

0

看起来您忘记将 包含OverlayModule在您的应用程序共享的模块中(通常是SharedModule

看看文档https://material.angular.io/cdk/overlay/api

于 2019-09-03T08:17:09.397 回答
0

从版本 7 开始,主要版本ng-zorro-antd与 Angular 保持一致。

您的ng-zorro-antd依赖项在版本 7 上,但您的 Angular 和 Material CDK 依赖项在版本 8 上。

您应该ng-zorro-antd将版本更新到 8 或将 Angular 和 Material CDK 的版本降级到 7。

于 2019-09-04T10:45:11.173 回答