gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 07:05:58 27 4
gpt4 key购买 nike

我的目标:

我正在尝试构建一个带有清除按钮的可重复使用的 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>

ma​​t-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 功能如何不起作用(没有轮廓,没有 float 标签),同时打开控制台,您将看到错误错误:mat-form-field 必须包含 MatFormFieldControl。

在选项 2 发布后进行编辑

我试过这样做:

<mat-form-field>
<input matInput hidden>
<ng-content></ng-content>
</mat-form-field>

它可以工作,但是当我在我的表单字段中添加一个 mat-label 时,如下所示:

<mat-clearable-input>
<mat-label>Numero incarico</mat-label>
<buffered-input matInput formControlName="numero"></buffered-input>
</mat-clearable-input>

标签永远不会 float ,它只是一直停留在那里作为一个正常的跨度。

所以我尝试分配给 this._matFormField._control._label带有标签的子内容,但这不起作用,因为 _label 是私有(private)的,没有它的 setter 。

看起来我运气不好,如果不经过大量努力,这是无法在 Angular 中完成的。

如果您有任何进一步的想法,请随时 fork stackblitz 并尝试!

在@evilstiefel 回答后编辑

该解决方案仅适用于 native <input matInput> .当我尝试用我的自定义输入组件替换它时,它不再起作用了。

工作设置:

<mat-form-field appClearable>
<mat-label>ID incarico</mat-label>
<input matInput formControlName="id">
</mat-form-field>

相同的设置,但使用我的自定义“缓冲输入”组件(不工作 :( )

<mat-form-field appClearable>
<mat-label>ID incarico</mat-label>
<buffered-input matInput formControlName="id"></buffered-input>
</mat-form-field>

当我单击清除按钮时,控制台会记录此错误:

TypeError: Cannot read property 'ngControl' of undefined
at ClearableDirective.clear (clearable.directive.ts:33)
at ClearButtonComponent.clearHost (clearable.directive.ts:55)
at ClearButtonComponent_Template_button_click_0_listener (clearable.directive.ts:47)
at executeListenerWithErrorHandling (core.js:14293)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:14328)
at HTMLButtonElement.<anonymous> (platform-browser.js:582)
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Object.onInvokeTask (core.js:27126)
at ZoneDelegate.invokeTask (zone-evergreen.js:398)
at Zone.runTask (zone-evergreen.js:167)

最佳答案

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

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 数组中。您可以指定用于提供用户界面的模板,也可以只使用 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,这都适用,但您可能需要根据您的用例对其进行调整。

关于javascript - Angular ng-content 不适用于 mat-form-field,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63898533/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com