Angular 指令:自定义属性未正确解析
Angular Directive: Custom attribute not properly resolving
我正在使用 ng-bootstrap 为表单中的一堆输入字段显示错误工具提示。
由于大部分代码是重复的,我考虑创建一个指令来根据一些参数将属性设置为元素:
来自这里:
<div class="value" tooltipClass="tooltip-error"
[ngbTooltip]="'getError(form, 'serial')'"
[openDelay]="300" [closeDelay]="500"
[ngClass]="{ 'is-invalid': submitted && form.get('serial').errors }">
<input formControlName="serial" type="text" placeholder="Serial Number" />
</div>
为此:
<div class="value" [form]="form" [submitted]="submitted" [controlName]="'serial'">
<input formControlName="serial" type="text" placeholder="Serial Number" />
</div>
使用这个指令:
import { Directive, Input, HostBinding } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { formError } from '@core/helpers';
@Directive({
selector: '[submitted][form][controlName],[submitted][form][controlName][disabled]',
host: {
'tooltipClass': 'tooltip-error',
'[attr.openDelay]': '300',
'[attr.closeDelay]': '500',
'[class.is-invalid]': 'submitted && form.get(controlName).errors',
'[class.not-allowed-cursor]': 'disabled',
'[class.no-text-selection]': 'disabled',
}
})
export class FormControlDirective {
_controlName: string = '';
_form!: FormGroup;
_submitted!: boolean;
@Input()
public get submitted(): boolean {
return this._submitted;
}
public set submitted(v : boolean) {
this._submitted = v;
this.resolveTooltip();
}
@Input()
public get form(): FormGroup {
return this._form;
}
public set form(v : FormGroup) {
this._form = v;
this.resolveTooltip();
}
@Input()
public get controlName(): string {
return this._controlName;
}
public set controlName(v : string) {
this._controlName = v;
this.resolveTooltip();
}
@Input() disabled: boolean = false;
@HostBinding('[attr.ngbTooltip]')
ngbTooltip: string = '';
resolveTooltip() {
//This method gets an error message based on the type of error.
//I tried to put the value between ' ', with no avail.
this.ngbTooltip = formError(this.submitted, this.form, this.controlName);
}
}
首先,我注意到 HostBinding 中的值不会自动更新,就像 host
属性一样,所以我创建了 getters/setter.
但是,工具提示仍然没有出现。如果我手动添加属性,工具提示会正常显示。
手动方式渲染结果如下:
<div tooltipclass="tooltip-error" class="value is-invalid" ng-reflect-tooltip-class="tooltip-error" ng-reflect-ngb-tooltip="Error example" ng-reflect-open-delay="300" ng-reflect-close-delay="500" ng-reflect-ng-class="[object Object]">
<input formcontrolname="serial" type="text" placeholder="Serial Number" ng-reflect-name="serial" class="ng-dirty ng-invalid ng-touched">
</div>
这是使用指令的渲染结果:
<div tooltipclass="tooltip-error" class="value is-invalid" ng-reflect-form="[object Object]" ng-reflect-submitted="true" ng-reflect-control-name="serial" opendelay="300" closedelay="500" ngbtooltip="'Serial number is required'">
<input formcontrolname="serial" type="text" placeholder="Serial Number" ng-reflect-name="serial" class="ng-dirty ng-invalid ng-touched">
</div>
据我所知,属性似乎没有被“解析”,没有显示为 ng-reflect-
。
尝试简单地添加以 ng-reflect-
开头的属性名称是行不通的。 :)
这是怎么回事,如何解决?
编辑:
我想我明白发生了什么。
我试图在我的自定义指令中触发另一个指令的选择器([ngbTooltip]
,来自 ng-boostrap
)。
如果我创建更简单的东西,像这样:
'[attr.ngbTooltip]': 'tooltipText',
//...
tooltipText: string = '';
//...
resolveTooltip() {
this.tooltipText = formError(this.submitted, this.form, this.controlName);
}
我将获得一个名为 ngbTooltip=""
而不是 [ngbTooltip]=""
的属性,它是 ng-bootstrap
中 ngbTooltip
的触发器。
有什么方法可以从自定义指令中触发另一个指令的选择器吗?
答案?
这看起来确实是错误的,但它确实有效。
今天实在想不下去了
我所做的是从 ngbTooltip
扩展并将值设置为工具提示使用的内部属性。
import { Directive, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { formError } from '@core/helpers';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
@Directive({
selector: '[submitted]',
host: {
'[class.is-invalid]': 'submitted && form.get(controlName).errors',
'[class.not-allowed-cursor]': 'disabled',
'[class.no-text-selection]': 'disabled'
}
})
export class FormControlDirective extends NgbTooltip implements OnInit {
_controlName: string = '';
_form!: FormGroup;
_submitted: boolean = false;
@Input()
public get submitted(): boolean {
return this._submitted;
}
public set submitted(v : boolean) {
this._submitted = v;
this.resolveTooltip();
}
@Input()
public get form(): FormGroup {
return this._form;
}
public set form(v : FormGroup) {
this._form = v;
this.resolveTooltip();
}
@Input()
public get controlName(): string {
return this._controlName;
}
public set controlName(v : string) {
this._controlName = v;
this.resolveTooltip();
}
@Input() disabled: boolean = false;
ngOnInit(): void {
this.tooltipClass = 'tooltip-error';
this.openDelay = 300;
this.closeDelay = 500;
super.ngOnInit();
}
resolveTooltip() {
this.ngbTooltip = formError(this.submitted, this.form, this.controlName);
}
}
selector
是您应用指令的方式 - 一个简单的关键字就足够了。
在您的情况下,您最感兴趣的是主机 class 属性,这是可以理解的,这部分看起来是正确的。
您可以先修复选择器部分,然后尝试 re-apply 您的指令。
这是工具提示指令的示例:https://stackblitz.com/edit/angular-tooltip-directive-editable-egzs44?file=app%2Ftooltip.directive.ts
我认为您的 HostBinding
语法可能不正确
@HostBinding('[attr.ngbTooltip]')
ngbTooltip: string = '';
应该是:
@HostBinding('attr.ngbTooltip')
ngbTooltip: string = '';
此外,据我所知,指令选择器 名称只能用于单个 @Input
,但您将其用于多个输入,例如 [submitted]="submitted" [controlName]="'serial'"
- 我认为这行不通
Tim Deschryver 在此处使用 PrimeNg 指令解决了类似的用例:
https://dev.to/this-is-angular/use-angular-directives-to-extend-components-that-you-dont-own-1jio
在我看来,仅通过自定义指令应用指令的属性并不是一个好方法,因为您会创建强大的 link,但我并不是说这行不通完全没有。
Tim 解决方案看起来不错,但您需要映射 ng-bootstrap 现有指令,而不是您映射的指令。
你扩展 class 的解决方案看起来像你说的那样“边缘”;)
干杯!
我正在使用 ng-bootstrap 为表单中的一堆输入字段显示错误工具提示。 由于大部分代码是重复的,我考虑创建一个指令来根据一些参数将属性设置为元素:
来自这里:
<div class="value" tooltipClass="tooltip-error"
[ngbTooltip]="'getError(form, 'serial')'"
[openDelay]="300" [closeDelay]="500"
[ngClass]="{ 'is-invalid': submitted && form.get('serial').errors }">
<input formControlName="serial" type="text" placeholder="Serial Number" />
</div>
为此:
<div class="value" [form]="form" [submitted]="submitted" [controlName]="'serial'">
<input formControlName="serial" type="text" placeholder="Serial Number" />
</div>
使用这个指令:
import { Directive, Input, HostBinding } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { formError } from '@core/helpers';
@Directive({
selector: '[submitted][form][controlName],[submitted][form][controlName][disabled]',
host: {
'tooltipClass': 'tooltip-error',
'[attr.openDelay]': '300',
'[attr.closeDelay]': '500',
'[class.is-invalid]': 'submitted && form.get(controlName).errors',
'[class.not-allowed-cursor]': 'disabled',
'[class.no-text-selection]': 'disabled',
}
})
export class FormControlDirective {
_controlName: string = '';
_form!: FormGroup;
_submitted!: boolean;
@Input()
public get submitted(): boolean {
return this._submitted;
}
public set submitted(v : boolean) {
this._submitted = v;
this.resolveTooltip();
}
@Input()
public get form(): FormGroup {
return this._form;
}
public set form(v : FormGroup) {
this._form = v;
this.resolveTooltip();
}
@Input()
public get controlName(): string {
return this._controlName;
}
public set controlName(v : string) {
this._controlName = v;
this.resolveTooltip();
}
@Input() disabled: boolean = false;
@HostBinding('[attr.ngbTooltip]')
ngbTooltip: string = '';
resolveTooltip() {
//This method gets an error message based on the type of error.
//I tried to put the value between ' ', with no avail.
this.ngbTooltip = formError(this.submitted, this.form, this.controlName);
}
}
首先,我注意到 HostBinding 中的值不会自动更新,就像 host
属性一样,所以我创建了 getters/setter.
但是,工具提示仍然没有出现。如果我手动添加属性,工具提示会正常显示。
手动方式渲染结果如下:
<div tooltipclass="tooltip-error" class="value is-invalid" ng-reflect-tooltip-class="tooltip-error" ng-reflect-ngb-tooltip="Error example" ng-reflect-open-delay="300" ng-reflect-close-delay="500" ng-reflect-ng-class="[object Object]">
<input formcontrolname="serial" type="text" placeholder="Serial Number" ng-reflect-name="serial" class="ng-dirty ng-invalid ng-touched">
</div>
这是使用指令的渲染结果:
<div tooltipclass="tooltip-error" class="value is-invalid" ng-reflect-form="[object Object]" ng-reflect-submitted="true" ng-reflect-control-name="serial" opendelay="300" closedelay="500" ngbtooltip="'Serial number is required'">
<input formcontrolname="serial" type="text" placeholder="Serial Number" ng-reflect-name="serial" class="ng-dirty ng-invalid ng-touched">
</div>
据我所知,属性似乎没有被“解析”,没有显示为 ng-reflect-
。
尝试简单地添加以 ng-reflect-
开头的属性名称是行不通的。 :)
这是怎么回事,如何解决?
编辑:
我想我明白发生了什么。
我试图在我的自定义指令中触发另一个指令的选择器([ngbTooltip]
,来自 ng-boostrap
)。
如果我创建更简单的东西,像这样:
'[attr.ngbTooltip]': 'tooltipText',
//...
tooltipText: string = '';
//...
resolveTooltip() {
this.tooltipText = formError(this.submitted, this.form, this.controlName);
}
我将获得一个名为 ngbTooltip=""
而不是 [ngbTooltip]=""
的属性,它是 ng-bootstrap
中 ngbTooltip
的触发器。
有什么方法可以从自定义指令中触发另一个指令的选择器吗?
答案?
这看起来确实是错误的,但它确实有效。 今天实在想不下去了
我所做的是从 ngbTooltip
扩展并将值设置为工具提示使用的内部属性。
import { Directive, Input, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { formError } from '@core/helpers';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
@Directive({
selector: '[submitted]',
host: {
'[class.is-invalid]': 'submitted && form.get(controlName).errors',
'[class.not-allowed-cursor]': 'disabled',
'[class.no-text-selection]': 'disabled'
}
})
export class FormControlDirective extends NgbTooltip implements OnInit {
_controlName: string = '';
_form!: FormGroup;
_submitted: boolean = false;
@Input()
public get submitted(): boolean {
return this._submitted;
}
public set submitted(v : boolean) {
this._submitted = v;
this.resolveTooltip();
}
@Input()
public get form(): FormGroup {
return this._form;
}
public set form(v : FormGroup) {
this._form = v;
this.resolveTooltip();
}
@Input()
public get controlName(): string {
return this._controlName;
}
public set controlName(v : string) {
this._controlName = v;
this.resolveTooltip();
}
@Input() disabled: boolean = false;
ngOnInit(): void {
this.tooltipClass = 'tooltip-error';
this.openDelay = 300;
this.closeDelay = 500;
super.ngOnInit();
}
resolveTooltip() {
this.ngbTooltip = formError(this.submitted, this.form, this.controlName);
}
}
selector
是您应用指令的方式 - 一个简单的关键字就足够了。
在您的情况下,您最感兴趣的是主机 class 属性,这是可以理解的,这部分看起来是正确的。
您可以先修复选择器部分,然后尝试 re-apply 您的指令。
这是工具提示指令的示例:https://stackblitz.com/edit/angular-tooltip-directive-editable-egzs44?file=app%2Ftooltip.directive.ts
我认为您的 HostBinding
语法可能不正确
@HostBinding('[attr.ngbTooltip]')
ngbTooltip: string = '';
应该是:
@HostBinding('attr.ngbTooltip')
ngbTooltip: string = '';
此外,据我所知,指令选择器 名称只能用于单个 @Input
,但您将其用于多个输入,例如 [submitted]="submitted" [controlName]="'serial'"
- 我认为这行不通
Tim Deschryver 在此处使用 PrimeNg 指令解决了类似的用例:
https://dev.to/this-is-angular/use-angular-directives-to-extend-components-that-you-dont-own-1jio
在我看来,仅通过自定义指令应用指令的属性并不是一个好方法,因为您会创建强大的 link,但我并不是说这行不通完全没有。
Tim 解决方案看起来不错,但您需要映射 ng-bootstrap 现有指令,而不是您映射的指令。
你扩展 class 的解决方案看起来像你说的那样“边缘”;) 干杯!