如何在ngOnInit()方法中使用ngModel的FormControl实例?

时间:2019-08-25 20:13:24

标签: angular angular-material

我当时正在考虑使用Angular Material自动完成模块,就像他们有一个示例here。 他们在概述中说,可以使用模板驱动的表单。所以我想我去试试。

模板:

<form (ngSubmit)="doSmth()" #f="ngForm">
    <mat-form-field>
        <input type="text" required id="name" (ngModel)="myControl" name="name" matInput [matAutocomplete]="auto">
            <mat-autocomplete #auto="matAutocomplete">
                <mat-option *ngFor="let option of filteredOptions | async" [value]="option">{{ option }}</mat-option>
            </mat-autocomplete>
    </mat-form-field>
    <button type="submit" [disabled]="!f.form.valid">Click</button>
</form>

组件:

@Component({
  selector: 'autocomplete-filter-example',
  templateUrl: 'autocomplete-filter-example.html',
  styleUrls: ['autocomplete-filter-example.css'],
})
export class AutocompleteFilterExample implements OnInit {
  myControl: FormControl();
  options: string[] = ['One', 'Two', 'Three'];
  filteredOptions: Observable<string[]>;

  ngOnInit() {
    this.filteredOptions = this.myControl.valueChanges
      .pipe(
        startWith(''),
        map((value: string) => this.filter(value))
      );
  }

  private filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.options.filter(option => option.toLowerCase().includes(filterValue));
  }
}

问题是当我运行它时,出现错误:

AppComponent.html:1 ERROR TypeError: Cannot read property 'valueChanges' of undefined

所以我猜想ngModel在初始化之后被绑定了吗?或为什么这不起作用?我需要使用FormControl的Sepaparte实例吗?

2 个答案:

答案 0 :(得分:1)

如果要使用ngModel和模板驱动的表单而不是表单控件,则可以将其与ngModelChange一起使用。如果您随后要使用可观察对象或纯字符串数组,则由您决定。这是使用纯字符串数组:

<mat-form-field>
  <input type="text" [ngModel]="myControl" name="name" matInput [matAutocomplete]="auto" (ngModelChange)="doFilter($event)" required>
  <mat-autocomplete #auto="matAutocomplete">
    <mat-option *ngFor="let option of filteredOptions" [value]="option">
      {{ option }}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>

最初,我们可以为filteredOptions赋予options的值。让我们使用传播运算符在两个数组之间不创建引用:

options: string[] = ['One', 'Two', 'Three'];
filteredOptions = [... this.options];
myControl = '';

然后doFilter()函数将如下所示:

doFilter(value) {
  const filterValue = value.toLowerCase();
  this.filteredOptions = this.options.filter(option => option.toLowerCase().includes(filterValue));
}

演示:StackBlitz

如果您不需要模板驱动的表单,则只需执行表单标签即可。

如前所述,如果您打算将来进行http请求以获取自动完成数据,那么您也可以使用可观察对象。如果在这一点上使用可观察到的东西已经可以更加明智,因为它很容易被替换。如果是这样,这是使用observables而不是字符串数组的选项:

import { Observable, of } from 'rxjs';

// ...

filteredOptions = of(this.options);

doFilter(value) {
  const filterValue = value.toLowerCase();
  this.filteredOptions = of(this.options.filter(option => option.toLowerCase().includes(filterValue)));
}

并在视图中使用异步管道:

<mat-option *ngFor="let option of filteredOptions | async" [value]="option">

演示:StackBlitz

答案 1 :(得分:0)

FormControl用于反应形式。您可以尝试以下代码。

myControl: any;
@ViewChild('f') ngForm: NgForm;

ngOnInit() {
  this.subscription = this.ngForm.form.valueChanges.subscribe(x => {
    console.log(x);
  })
}

别忘了退订。另外,您可能需要使用[(ngModel)]而不是(ngModel)。