更新指令中的属性值

时间:2019-03-19 09:12:38

标签: angular angular2-directives

我正在尝试创建自己的指令以计算输入长度值。

  • 在视图初始化上,我在指令中添加了maxlength属性,并将其值发送给指令->确定

  • 在视图初始化之后,我在指令之前添加了一个div,其计数为0/50->确定

当我使用键盘时,我只是有一个更新长度值的问题(属性是更新的,而不是渲染的)。 你能帮我吗?

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'" />

感谢您的帮助,我迷路了。

3 个答案:

答案 0 :(得分:1)

Here is a Stackblitz demo指令

我对您的代码做了一些修改,这是我的建议:

  • 将您的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元素的文本
  • 删除div元素,因为Angular不会跟踪它。为此,您不能使用this.renderer.removeChild(this.el.nativeElement.parent, this.div),因为在删除DOM之后将调用ngOnDestroy,并且parent引用将为空。您必须直接致电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绑定到输入时起作用,并且在模型更改时进行相应更新,则可以通过注入主机ngModel并订阅其{{1 }}可观察:

valueChange

然后,您可以在带有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

答案 1 :(得分:0)

尝试此代码,我已经重写了一些代码

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发生更改的地方更新其值。

还必须在销毁指令时销毁它,以避免内存泄漏

答案 2 :(得分:0)

正确的方法是使用二传手。每次输入更改时,都会调用setter函数。

    @Input() set appInputmaxLength(value:string){
    // Your code here
    console.log(value);
    }

可以在此处找到示例:https://angular.io/guide/structural-directives(您的指令不是结构性指令,但在此示例中是