我正在尝试创建自己的指令来计算输入长度值。
我在使用键盘时更新长度值时遇到问题(属性已更新,但未更新)。你能帮我吗?
import {
AfterViewInit,
Directive, ElementRef, HostListener, Input, OnInit, Renderer2
} from '@angular/core';
@Directive({
selector: '[appInputmaxLength]'
})
export class InputmaxLengthDirective implements OnInit, AfterViewInit {
@Input() appInputmaxLength: string;
private currentValue = 0;
constructor(
private el: ElementRef,
private renderer: Renderer2
) {}
@HostListener('keydown') isChange() {
let countNb = this.el.nativeElement.value.length + 1;
if (countNb <= 1) {
this.currentValue = 0;
} else {
this.currentValue = countNb;
}
console.log('test: ', this.el.nativeElement.value.length + 1);
}
ngOnInit() {
this.renderer.setAttribute(this.el.nativeElement, 'maxLength', this.appInputmaxLength);
}
ngAfterViewInit() {
const html = '<div>' + this.currentValue + ' / ' + this.appInputmaxLength + '</div>'
const target = this.el;
target.nativeElement.insertAdjacentHTML('afterEnd', html);
}
}
这就是我使用指令的方式:
<input type="text" [appInputmaxLength]="'5'" />
谢谢你的帮助,我迷路了。
我对你的代码做了一些修改,这是我的建议:
appInputMaxLength
类型更改为数字Renderer2
API与跨平台兼容。div
属性来保存你的div并稍后更新它,用this.renderer.createElement('div')
创建它this.renderer.insertBefore(this.el.nativeElement.parentNode, this.div, this.el.nativeElement.nextSibling)
在主机之后插入它input
事件收听更改,并从事件中获取值,然后获取其长度并更新div
currentValue
变量,只需从输入的值或事件中获取长度this.renderer.setProperty(this.div, 'innerText', ...);
更新div元素的文本this.renderer.removeChild(this.el.nativeElement.parent, this.div)
,因为在删除DOM之后调用ngOnDestroy
,然后parent
引用将为null。你必须直接打电话给this.div.remove()
(see this github issue)。import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnInit, Renderer2, OnDestroy } from '@angular/core';
@Directive({
selector: '[appInputMaxLength]'
})
export class InputMaxLengthDirective implements OnInit, AfterViewInit, OnDestroy {
@Input() appInputMaxLength: number;
private div: HTMLDivElement;
constructor(private el: ElementRef, private renderer: Renderer2) {}
@HostListener('input', ['$event']) onChange(event) {
this.update(event.target.value.length);
}
ngOnInit() {
this.renderer.setAttribute(this.el.nativeElement, 'maxLength', this.appInputMaxLength.toString());
}
ngOnDestroy() {
if (this.div) {
this.div.remove();
}
}
ngAfterViewInit() {
this.div = this.renderer.createElement('div');
this.renderer.insertBefore(this.el.nativeElement.parentNode, this.div, this.el.nativeElement.nextSibling);
this.update(this.el.nativeElement.value.length);
}
private update(length: number) {
this.renderer.setProperty(this.div, 'innerText', `${length} / ${this.appInputMaxLength}`);
}
}
像这样使用它,带有一个数字输入值:
<input type="text" [appInputMaxLength]="10">
如果你希望你的指令在ngModel
被绑定到输入时工作并且如果模型改变则相应地更新,你可以通过注入主机ngModel
然后订阅它的valueChange
observable:
import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnInit, Renderer2, Optional, OnDestroy } from '@angular/core';
import { NgModel } from '@angular/forms';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Directive({
selector: '[appInputMaxLength]'
})
export class InputMaxLengthDirective implements OnInit, AfterViewInit, OnDestroy {
@Input() appInputMaxLength: number;
private div: HTMLDivElement;
private destroyed$ = new Subject();
constructor(private el: ElementRef, private renderer: Renderer2, @Optional() private ngModel: NgModel) {}
@HostListener('input', ['$event']) onChange(event) {
if (!this.ngModel) {
this.update(event.target.value.length);
}
}
ngOnInit() {
this.renderer.setAttribute(this.el.nativeElement, 'maxLength', this.appInputMaxLength.toString());
if (this.ngModel) {
this.ngModel.valueChanges.pipe(takeUntil(this.destroyed$)).subscribe(value => {
this.update(value.length);
})
}
}
ngAfterViewInit() {
this.div = this.renderer.createElement('div');
this.renderer.insertBefore(this.el.nativeElement.parentNode, this.div, this.el.nativeElement.nextSibling);
this.update(this.el.nativeElement.value.length);
}
ngOnDestroy() {
this.destroyed$.next();
this.destroyed$.complete();
if (this.div) {
this.div.remove();
}
}
private update(length: number) {
this.renderer.setProperty(this.div, 'innerText', `${length} / ${this.appInputMaxLength}`);
}
}
然后你可以在带有ngModel
的输入上使用你的指令:
<input type="text" [appInputMaxLength]="10" [(ngModel)]="value">
正确的方法是使用二传手。每次输入更改时都会调用setter函数。
@Input() set appInputmaxLength(value:string){
// Your code here
console.log(value);
}
可以在这里找到一个例子:https://angular.io/guide/structural-directives(你的指令不是结构指令,但是在这个例子中)
尝试这个代码我已经重写了一些代码
import {
AfterViewInit,
Directive,
ElementRef,
HostListener,
Input,
OnInit,
Renderer2,
OnDestroy
} from '@angular/core';
@Directive({
selector: '[appInputmaxLength]'
})
export class InputmaxLengthDirective implements OnInit, AfterViewInit, OnDestroy {
@Input() appInputmaxLength: string;
private currentValue = 0;
countDiv: HTMLDivElement;
parent: any;
constructor(private el: ElementRef<HTMLInputElement>, private renderer: Renderer2) {}
@HostListener('keyup') isChange() {
const countNb = this.el.nativeElement.value.length + 1;
if (countNb <= 1) {
this.currentValue = 0;
this.updateCount();
} else {
this.currentValue = countNb;
this.updateCount();
}
console.log('test: ', this.el.nativeElement.value.length + 1);
}
ngOnInit() {
this.renderer.setAttribute(this.el.nativeElement, 'maxLength', this.appInputmaxLength);
}
ngOnDestroy() {
this.renderer.removeChild(this.parent, this.countDiv);
this.renderer.destroyNode(this.countDiv);
}
updateCount() {
this.countDiv.innerText = this.currentValue + ' / ' + this.appInputmaxLength;
}
ngAfterViewInit() {
this.countDiv = this.renderer.createElement('div');
this.parent = this.renderer.parentNode(this.el.nativeElement);
this.renderer.appendChild(parent, this.countDiv);
this.updateCount();
}
}
在这段代码中,我使用渲染器来创建一个div元素,并在currentValue
发生变化时更新其值。
当指令被销毁时,你必须销毁它以避免内存泄漏