thre're not a "relation" between a FormControl and a input (a FormControl is independient of the input), so you can not access to the htmlElement input if you not use one around-work: a directive
If the selector of one directive is '[formControl], [formControlName]' it is applied to all the inputs with formControl and FormControlName.
We inject in constructor the NgControl and the ElementRef
constructor(private control:NgControl,private el:ElementRef) { }
So we can access to the function validator of the control using this.control.control.validator. See that in this way we access to the "function". And as all the function we can feed with a FormControl and get the result. In this case we are feeding with a FormControl very large
The directive can be some like
@Directive({
selector: ''[formControl], [formControlName]''
})
export class AddMaxLengthDirective implements OnInit{
constructor(private control:NgControl,private el:ElementRef) { }
ngOnInit()
{
//we need check if the control has "any" validator
const err=this.control.control.validator?
this.control.control.validator(
new FormControl(".".repeat(10000000))):null
if (err && err.maxlength && err.maxlength.requiredLength)
this.el.nativeElement.setAttribute(
'maxlength',err.maxlength.requiredLength)
}
}
When we has the attribute maxlength in our input, we can write in .html some like
<input #input [formControl]="control">
<span *ngIf="input.getAttribute('maxlength') as max">
left {{ +max - input.value.length }} characters
</span>
You can see in this stackblitz. If you use F12, you can inspect the DOM and see how is added the maxlength attribute
NOTE: don't forget add the directive in your module!
Update We can also improve the directive to add automatically the message. For this we can use the Netanel Basal's idea in his article Makes your angular form's error appear magically
We create a counterComponent
@Component({
selector: 'app-help',
template: `<p class="count-help">{{_text}}</p>`,
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./count.component.css']
})
export class CountComponent {
_text;
@Input() set text(value) {
if (value !== this._text) {
this._text = value;
this.cdr.detectChanges();
}
};
constructor(private cdr: ChangeDetectorRef) { }
}
And our directive makes use of the Netanel Basal's idea
export class AddMaxLengthDirective implements OnInit {
ref: ComponentRef<CountComponent>
max:number=0;
subscription:any;
constructor(
private control: NgControl,
private el: ElementRef,
private vcr: ViewContainerRef,
private resolver: ComponentFactoryResolver
) {}
ngOnInit() {
const err = this.control.control.validator
? this.control.control.validator(new FormControl('.'.repeat(10000000)))
: null;
if (err && err.maxlength && err.maxlength.requiredLength) {
this.max=err.maxlength.requiredLength;
this.el.nativeElement.setAttribute(
'maxlength',
this.max
);
const factory = this.resolver.resolveComponentFactory(CountComponent);
this.ref = this.vcr.createComponent(factory);
this.subscription=this.control.valueChanges.pipe(startWith(this.control.value))
.subscribe(res=>{
this.ref.instance.text='left '+(this.max-res.length)+' characters'
})
}
}
ngOnDestroy()
{
this.subscription && this.subscription.unsubscribe()
}
}
See the new stackblitz
maxlengtherror object hasrequiredLengthandactualLengthproperties that may help you.