为了账号安全,请及时绑定邮箱和手机立即绑定

Angular ng-content 不适用于 mat-form-field

Angular ng-content 不适用于 mat-form-field

大话西游666 2023-03-03 13:34:36
我的目标:我正在尝试构建一个带有清除按钮的可重复使用的 mat-form-field。我如何尝试实现我的目标:我创建了一个“mat-clearable-input”组件并像这样使用它:<mat-clearable-input>        <mat-label>Put a Number here pls</mat-label>        <input matInput formControlName="number_form_control">    </mat-clearable-input>mat-clearable-input.component.html<mat-form-field>    <ng-content></ng-content></mat-form-field>预期结果:ng-content 标签获取标签和输入并将它们放入 mat-form-field 标签中。实际结果:Error: mat-form-field must contain a MatFormFieldControl.    at getMatFormFieldMissingControlError (form-field.js:226)    at MatFormField._validateControlChild (form-field.js:688)    at MatFormField.ngAfterContentChecked (form-field.js:558)    at callHook (core.js:2926)    at callHooks (core.js:2892)    at executeInitAndCheckHooks (core.js:2844)    at refreshView (core.js:7239)    at refreshComponent (core.js:8335)    at refreshChildComponents (core.js:6991)    at refreshView (core.js:7248)看起来我遗漏了一些东西而且我没有正确使用 ng-content 标签。我无法在 angular 网站上找到 ng-content 标签的文档。感谢您的任何帮助。在下面回答后编辑所以我尝试了这个建议的方法:export class MatClearableInputComponent implements OnInit {  @ContentChild(MatFormFieldControl) _control: MatFormFieldControl<any>;  @ViewChild(MatFormField) _matFormField: MatFormField;  // see https://stackoverflow.com/questions/63898533/angular-ng-content-not-working-with-mat-form-field/  ngOnInit() {    this._matFormField._control = this._control;  }}不幸的是,当我尝试在表单中使用它时,它仍然失败并出现错误“错误:mat-form-field 必须包含 MatFormFieldControl”。我尝试以某种形式使用此组件的代码:<mat-clearable-input>    <mat-label>Numero incarico</mat-label>    <buffered-input matInput formControlName="numero"></buffered-input></mat-clearable-input>在 stackblitz 上重现:https://stackblitz.com/edit/angular-material-starter-xypjc5 ?file=app/clearable-form-field/clearable-form-field.component.html请注意 mat-form-field 功能如何不起作用(没有轮廓,没有浮动标签),同时打开控制台,您将看到错误错误:mat-form-field 必须包含 MatFormFieldControl。选项 2 发布后编辑我试过这样做:<mat-form-field>  <input matInput hidden>  <ng-content></ng-content></mat-form-field>它有效,但是当我在我的表单字段中添加一个 mat-label 时,如下所示:      
查看完整描述

3 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

另一种解决方案是使用指令来实现行为。


import {

  AfterViewInit,

  Component,

  ComponentFactory,

  ComponentFactoryResolver,

  ContentChild,

  Directive,

  Injector,

  Input,

  Optional,

  SkipSelf,

  TemplateRef,

  ViewContainerRef,

} from '@angular/core';

import { MatFormFieldControl } from '@angular/material/form-field';



@Directive({

  selector: '[appClearable]'

})

export class ClearableDirective implements AfterViewInit {


  @ContentChild(MatFormFieldControl) matInput: MatFormFieldControl<any>;

  @Input() appClearable: TemplateRef<any>;

  private factory: ComponentFactory<ClearButtonComponent>;


  constructor(

    private vcr: ViewContainerRef,

    resolver: ComponentFactoryResolver,

    private injector: Injector,

  ) {

    this.factory = resolver.resolveComponentFactory(ClearButtonComponent);

  }


  ngAfterViewInit(): void {

    if (this.appClearable) {

      this.vcr.createEmbeddedView(this.appClearable);

    } else {

      this.vcr.createComponent(this.factory, undefined, this.injector);

    }

  }


  /**

   * This is used to clear the formControl oder HTMLInputElement

   */

  clear(): void {

    if (this.matInput.ngControl) {

      this.matInput.ngControl.control.reset();

    } else {

      this.matInput.value = '';

    }

  }

}


/**

 * This is the markup/component for the clear-button that is shown to the user.

 */

@Component({

  selector: 'app-clear-button',

  template: `

  <button (click)="clearHost()">Clear</button>

  `

})

export class ClearButtonComponent {

  constructor(@Optional() @SkipSelf() private clearDirective: ClearableDirective) { }


  clearHost(): void {

    if (this.clearDirective) {

      this.clearDirective.clear();

    }

  }

}

这会appClearable为后备布局创建一个名为的指令和一个可选的组件。确保将组件和指令添加到declarations模块的 -array 中。您可以指定用于提供用户界面的模板,也可以将其ClearButtonComponent用作通用的解决方案。标记如下所示:


<!-- Use it with a template reference -->

<mat-form-field [appClearable]="clearableTmpl">

  <input type="text" matInput [formControl]="exampleInput">

</mat-form-field>


<!-- use it without a template reference -->

<mat-form-field appClearable>

  <input type="text" matInput [formControl]="exampleInput2">

</mat-form-field>


<ng-template #clearableTmpl>

  <button (click)="exampleInput.reset()">Marked-Up reference template</button>

</ng-template>

无论是否使用 ngControl/FormControl,这都适用,但您可能需要根据您的用例对其进行调整。


查看完整回答
反对 回复 2023-03-03
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

从 2022 年的 Angular 14 开始,MatFormField 的问题已经针对angular/angular#37319关闭,没有解决方案。如果您需要它工作,以下似乎是现在可以使用<ng-content>with的最佳解决方案mat-form-field


@Component({

  selector: 'my-input-wrapper',

  template: `

    <mat-form-field appearance="standard">

      <ng-content></ng-content>

      <!-- make sure this is destroyed so all bindings/subscriptions are removed-->

      <input *ngIf="isBeforeViewInit$$ | async" hidden matInput />

    </mat-form-field>

  `,

});

class MyInputWrapper implement AfterViewInit {

  isBeforeViewInit$$ = new BehaviorSubject(true);

  @ContentChild(MatFormFieldControl) matFormControl: MatFormFieldControl<unknown>;

  @ViewChild(MatFormField) matFormField: MatFormField;


  ngAfterViewInit() {

    // replace the reference to the dummy control

    this.matFormField._control = this.matFormControl;

    // force the form field to rebind everything to the actual control

    this.matFormField.ngAfterContentInit();

    this.isBeforeViewInit$$.next(false);

  }

}


查看完整回答
反对 回复 2023-03-03
?
千万里不及你

TA贡献1784条经验 获得超9个赞

更新:


选项 1 不适用于新的角度版本,因为在钩子@ViewChild()中返回未定义。ngOnInit()另一个技巧是使用假人MatFormFieldControl-


选项 2


<mat-form-field>

  <input matInput hidden>

  <ng-content></ng-content>

</mat-form-field>

编辑:


抛出该错误是因为MatFormField组件查询使用的子内容@ContentChild(MatFormFieldControl)如果您使用嵌套则不起作用ng-content(MatFormField 也使用内容投影)。


选项 1(已弃用)


以下是如何让它工作 -


@Component({

  selector: 'mat-clearable-input',

  template: `

    <mat-form-field>

      <ng-content></ng-content>

    </mat-form-field>

  `

})

export class FieldComponent implements OnInit { 

    @ContentChild(MatFormFieldControl) _control: MatFormFieldControl<any>;

    @ViewChild(MatFormField) _matFormField: MatFormField;


    ngOnInit() {

        this._matFormField._control = this._control;

    }

}

请检查这个 stackBlitz。此外,已经创建了这个问题github



查看完整回答
反对 回复 2023-03-03
  • 3 回答
  • 0 关注
  • 84 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信