【问题标题】:Uncaught ReferenceError: Cannot access 'MaterialModule' before initialization未捕获的 ReferenceError:在初始化之前无法访问“MaterialModule”
【发布时间】:2020-05-06 00:32:46
【问题描述】:

我正在为个人项目制作一个简单的表单,并尝试使用此示例放置电话表单:https://material.angular,.io/components/form-field/examples 之后适合所有内容,它给了我这个错误,尽管删除与电话表单相关的所有内容保持不变.

form.component.ts

import { Component, OnInit } from '@angular/core';
import { Builder } from 'protractor';
import {FocusMonitor} from '@angular/cdk/a11y';
import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {ElementRef, Input, OnDestroy, Optional, Self} from '@angular/core';
import {FormBuilder, FormGroup, ControlValueAccessor, NgControl} from '@angular/forms';
import {MatFormFieldControl} from '@angular/material';
import {Subject} from 'rxjs';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss'],
  providers: [{provide: MatFormFieldControl, useExisting: MyTelInput}],
  host: {
    '[class.example-floating]': 'shouldLabelFloat',
    '[id]': 'id',
    '[attr.aria-describedby]': 'describedBy',
  }
})

export class MyTelInput implements ControlValueAccessor, MatFormFieldControl<MyTel>, OnDestroy {
  static nextId = 0;

  parts: FormGroup;
  stateChanges = new Subject<void>();
  focused = false;
  errorState = false;
  controlType = 'example-tel-input';
  id = `example-tel-input-${MyTelInput.nextId++}`;
  describedBy = '';
  onChange = (_: any) => {};
  onTouched = () => {};

  get empty() {
    const {value: {area, exchange, subscriber}} = this.parts;

    return !area && !exchange && !subscriber;
  }

  get shouldLabelFloat() { return this.focused || !this.empty; }

  @Input()
  get placeholder(): string { return this._placeholder; }
  set placeholder(value: string) {
    this._placeholder = value;
    this.stateChanges.next();
  }
  private _placeholder: string;

  @Input()
  get required(): boolean { return this._required; }
  set required(value: boolean) {
    this._required = coerceBooleanProperty(value);
    this.stateChanges.next();
  }
  private _required = false;

  @Input()
  get disabled(): boolean { return this._disabled; }
  set disabled(value: boolean) {
    this._disabled = coerceBooleanProperty(value);
    this._disabled ? this.parts.disable() : this.parts.enable();
    this.stateChanges.next();
  }
  private _disabled = false;

  @Input()
  get value(): MyTel | null {
    const {value: {area, exchange, subscriber}} = this.parts;
    if (area.length === 3 && exchange.length === 3 && subscriber.length === 4) {
      return new MyTel(area, exchange, subscriber);
    }
    return null;
  }
  set value(tel: MyTel | null) {
    const {area, exchange, subscriber} = tel || new MyTel('', '', '');
    this.parts.setValue({area, exchange, subscriber});
    this.stateChanges.next();
  }

  constructor(
    formBuilder: FormBuilder,
    private _focusMonitor: FocusMonitor,
    private _elementRef: ElementRef<HTMLElement>,
    @Optional() @Self() public ngControl: NgControl) {

    this.parts = formBuilder.group({
      area: '',
      exchange: '',
      subscriber: '',
    });

    _focusMonitor.monitor(_elementRef, true).subscribe(origin => {
      if (this.focused && !origin) {
        this.onTouched();
      }
      this.focused = !!origin;
      this.stateChanges.next();
    });

    if (this.ngControl != null) {
      this.ngControl.valueAccessor = this;
    }
  }

  ngOnDestroy() {
    this.stateChanges.complete();
    this._focusMonitor.stopMonitoring(this._elementRef);
  }

  setDescribedByIds(ids: string[]) {
    this.describedBy = ids.join(' ');
  }

  onContainerClick(event: MouseEvent) {
    if ((event.target as Element).tagName.toLowerCase() != 'input') {
      this._elementRef.nativeElement.querySelector('input')!.focus();
    }
  }

  writeValue(tel: MyTel | null): void {
    this.value = tel;
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  _handleInput(): void {
    this.onChange(this.parts.value);
  }
}
export class MyTel {
  constructor(public area: string, public exchange: string, public subscriber: string) {}
}

export class FormComponent implements OnInit {

  public formGroup: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.formGroup = this.formBuilder.group({
      name: '',
      lastname: '',
      option: '',
      checkbox: '',
      masculino: '',
      femenino: '',
      email:'',
    });
  }

}

form.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { FormRoutingModule } from './form-routing.module';
import { FormComponent } from './form/form.component';
import { MaterialModule } from '../material/material.module';
import { FormBuilder } from '@angular/forms';



@NgModule({
  declarations: [FormComponent],
  imports: [
    CommonModule,
    FormRoutingModule, 
    MaterialModule
  ],
  providers: [
    FormBuilder
  ]
})
export class FormModule { }

ma​​terial.module.ts

import { NgModule } from '@angular/core';
import { 
  MatTableModule, 
  MatPaginatorModule, 
  MatFormFieldModule, 
  MatSelectModule, 
  MatInputModule, 
  MatCheckboxModule, 
  MatRadioModule} from '@angular/material';
import { ReactiveFormsModule } from '@angular/forms';
import { FormModule } from '../form/form.module';
import { FormComponent } from '../form/form/form.component';

const materialModules = [
  MatTableModule,
  MatPaginatorModule,
  MatFormFieldModule,
  ReactiveFormsModule,
  MatSelectModule,
  MatInputModule,
  MatRadioModule,
  FormModule, 
  FormComponent,
  MatCheckboxModule,
];

@NgModule({
  exports: materialModules,
  imports: materialModules
})
export class MaterialModule { }

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from './modules/material/material.module';
import { MatSelectModule, MatInputModule, MatCheckbox, MatRadioModule } from '@angular/material';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormModule } from './modules/form/form.module';
import { FormComponent } from './modules/form/form/form.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    NoopAnimationsModule,
    MaterialModule,
    MatSelectModule,
    MatInputModule,
    MatFormFieldModule,
    MatRadioModule,
    FormModule,
    FormComponent
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

form-routing.component.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { FormComponent } from './form/form.component';


const routes: Routes = [{path: '', component: FormComponent}];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class FormRoutingModule { }

请帮忙

【问题讨论】:

  • 请提供您的代码。
  • 在声明类之前使用注解时,我看到过类似的错误。
  • 我遇到了同样的问题。当我尝试将 angular-material-design 控件/组件包装在单独的模块中时会发生这种情况,而这两个模块都被导入到根应用程序模块中。我也不确定它为什么会发生。 @EGC你能详细说明“你的代码”吗?将 mat 组件包装在一个单独的模块中的努力对我来说是新的和实验性的,并且旨在创建方便的工具,所以如果它不能完成那很好,我只想知道 为什么 它无法完成。
  • @Lopside 这里的错误来自错误的模块声明。
  • 请使用 stackblitz 创建一个最小的复制品

标签: html angular typescript


【解决方案1】:

这里有 2 个主要错误:

  1. 将组件导入模块。做不到,只能导入模块。可以声明和导出组件。这导致了您看到的错误。

  2. 通过将 FormModule 导入 MaterialModule 来导入圆形模块,反之亦然。做不到。进口只能是一个方向。这会导致您看到的警告实际上是阻止您重新编译的错误。

还有一些小错误,比如你混淆了模块逻辑和双重导入模块

以下修复....

材料模块,让它做它应该做的事情,导入和导出材料模块,NOTHING ELSE,remover 响应式表单导入,移除对 FormsModule 的循环引用,移除表单组件导入:

import { NgModule } from '@angular/core';
import { 
  MatTableModule, 
  MatPaginatorModule, 
  MatFormFieldModule, 
  MatSelectModule, 
  MatInputModule, 
  MatCheckboxModule, 
  MatRadioModule} from '@angular/material';

const materialModules = [
  MatTableModule,
  MatPaginatorModule,
  MatFormFieldModule,
  MatSelectModule,
  MatInputModule,
  MatRadioModule,
  MatCheckboxModule,
];

@NgModule({
  exports: materialModules,
  imports: materialModules
})
export class MaterialModule { }

表单模块,在此处导入响应式表单模块(不提供表单生成器),导出表单组件以在其他模块中使用它:

@NgModule({
  declarations: [FormComponent],
  imports: [
    CommonModule, // if you have a common module, you could import / export the reactive forms module there if it's more appropriate and then you don't need to import it again here.
    FormRoutingModule, 
    MaterialModule,
    ReactiveFormsModule // do this here, don't provide the form builder
  ],
  exports: [
    FormComponent // if you want to use this component in other modules, export here and import the MODULE
  ]
})
export class FormModule { }

app 模块,不要尝试导入表单组件,只需导入模块即可。不要重新导入材料模块,你在材料模块中这样做:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    NoopAnimationsModule,
    MaterialModule, // do you really NEED the material module here?
    FormModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

【讨论】:

  • 谢谢,布莱恩。我仍在掌握这个概念,但我快到了。有没有办法强制导入依赖项的方向?例如,我希望ModuleC 使用ModuleB,并且我希望将两者都导入ModuleA
  • B 到 C 很好,C/B 到 A 也很好。你只是不能循环导入,所以你不能让 A 回到 B 或 C。如果你尝试,你的编译器会向你抛出错误。
  • 我有一个类似的问题,我花了几个小时找出循环依赖。最后,我找到了这个工具来帮助我找到它。 github.com/acrazing/dpdm#readme
猜你喜欢
  • 2020-12-12
  • 2021-03-10
  • 2020-06-02
  • 2020-06-02
  • 2022-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-29
相关资源
最近更新 更多