I'm using ng-bootstrap to display an error tooltip for a bunch of input fields inside a form. Since most of the code is repeated, I thought about creating a directive to set the attributes to the elements based on some few parameters:
From this:
<div 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>
To this:
<div [form]="form" [submitted]="submitted" [controlName]="'serial'">
<input formControlName="serial" type="text" placeholder="Serial Number" />
</div>
Using this directive:
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);
}
}
First, I noticed that the value in the HostBinding does not update automatically, the same way as the host
attributes, so I created getters/setter.
But still, the tooltip does not appear. If I add the attributes manually, the tooltip appears normally.
Here's the rendered result of the manual way:
<div tooltip ng-reflect-tooltip- ng-reflect-ngb-tooltip="Error example" ng-reflect-open-delay="300" ng-reflect-close-delay="500" ng-reflect-ng->
<input formcontrolname="serial" type="text" placeholder="Serial Number" ng-reflect-name="serial" >
</div>
And here's the rendered result of using a directive:
<div tooltip 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" >
</div>
From what I could understand, it looks like the attributes are not being "parsed", not appearing as ng-reflect-
.
Clearly, trying to simple add the name of the attributes as starting with ng-reflect-
didn't work. :)
What's going on and how to fix it?
CodePudding user response:
selector
is how you apply the directive - a simple keyword should be enough.
In your case you're mostly interested in host class properties which is understandable and that part looks about right.
You could start by fixing the selector section and try to re-apply your directive.
Here is an example of a tooltip directive: https://stackblitz.com/edit/angular-tooltip-directive-editable-egzs44?file=app/tooltip.directive.ts
CodePudding user response:
I think your HostBinding
syntax may be incorrect
@HostBinding('[attr.ngbTooltip]')
ngbTooltip: string = '';
should be:
@HostBinding('attr.ngbTooltip')
ngbTooltip: string = '';