6

I am working on a simple form for a personal project and try to put a phone form use this example: https://material.angular,.io/components/form-field/examples and after that fits everything it gives me this error and although Remove everything related to the phone form remains the same.

enter image description here

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

material.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 { }

Please help

5
  • 1
    Please provide your code. Commented Jan 20, 2020 at 1:18
  • I've seen similar errors when using an annotation before the class is declared. Commented Jan 20, 2020 at 13:34
  • I am running into this exact same issue. It occurs when I try to wrap an angular-material-design control/component within a separate module, while both modules are imported in the root app module. I'm not sure why it is occurring yet either. @EGC can you elaborate on "your code"? The endeavor of wrapping the mat component in a separate module is new and experimental for me, and was intended to create convenience tool, so if it cannot be done then that's fine, I just want to know why it cannot be done. Commented Jun 15, 2020 at 17:36
  • @Lopsided the errors here are from bad module declarations. Commented Jun 15, 2020 at 18:09
  • Please create a minimal reproduction using stackblitz Commented Jun 15, 2020 at 18:34

1 Answer 1

6
+50

you have 2 major errors here:

  1. importing a component to a module. Can't be done, only modules can be imported. Components can be declared and exported. This is causing the error you're seeing.

  2. Circular module imports by importing FormModule to MaterialModule and vice versa. Can't do it. Imports can only go in one direction. This is causing the warning you're seeing which is actually an error preventing you from recompiling.

And some minor errors, like you're mixing up module logic and double importing modules

fixes below....

material module, let it do what it's supposed to do, import and export material modules, NOTHING ELSE, remover reactive forms import, remove circular reference to FormsModule, remove form component import:

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

form module, import the reactive forms module here (dont provide the form builder), export your forms component to use it in other modules:

@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 module, don't try to import the form component, just the module. Don't reimport material modules, you do that in the material module:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    NoopAnimationsModule,
    MaterialModule, // do you really NEED the material module here?
    FormModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, Bryan. I'm still grasping the concept, but I'm almost there. Is there a way to sort of enforce the direction of the imported dependencies? e.g., I want ModuleC to use ModuleB, and I want both to be imported into ModuleA?
B to C is fine, and C/B to A is also fine. You just can’t have a circular import, so you couldn’t have A go back to B or C. Your compiler will throw errors at you if you try.
I had a similar issue and I spent hours finding out the cyclic dependency. Finally, I found this tool which help me to find it. github.com/acrazing/dpdm#readme

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.