Обновить значение свойства в директиве

Ответ С.Лотта выше почти работает для меня, но в конечном итоге дает мне частичные линии. Оказывается, он искажает данные на границах блоков, поскольку данные содержат блоки чтения в обратном порядке. Когда вызывается '.join (data), блоки находятся в неправильном порядке. Это исправляет это.

def tail(f, window=20):
    """
    Returns the last `window` lines of file `f` as a list.
    """
    if window == 0:
        return []
    BUFSIZ = 1024
    f.seek(0, 2)
    bytes = f.tell()
    size = window + 1
    block = -1
    data = []
    while size > 0 and bytes > 0:
        if bytes - BUFSIZ > 0:
            # Seek back one whole BUFSIZ
            f.seek(block * BUFSIZ, 2)
            # read BUFFER
            data.insert(0, f.read(BUFSIZ))
        else:
            # file too small, start from begining
            f.seek(0,0)
            # only read what was not read
            data.insert(0, f.read(bytes))
        linesFound = data[0].count('\n')
        size -= linesFound
        bytes -= BUFSIZ
        block -= 1
    return ''.join(data).splitlines()[-window:]
3
задан orphen92300 19 March 2019 в 09:20
поделиться

3 ответа

правильный способ - использовать сеттер. Функция установки вызывается каждый раз, когда изменяется вход.

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

Пример можно найти здесь: https://angular.io/guide/structural-directives (директива You не является структурной директивой, но она в этом примере)

0
ответ дан MullisS 19 March 2019 в 09:20
поделиться

Вот демонстрация Stackblitz директивы

Я внес несколько изменений в ваш код, вот что я предлагаю:

[ 1143]
  • Измените тип appInputMaxLength на номер
  • Используйте API Renderer2 настолько, насколько это возможно, для кросс-платформенной совместимости.
  • Используйте частное свойство 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), так как ngOnDestroy вызывается после удаления DOM, и ссылка parent будет нулевой. Вы должны напрямую позвонить this.div.remove() ( см. Этот выпуск Github ).

    • Обновлен код директивы

      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 и затем подписаться на его 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:

      [113 ]
    0
    ответ дан jo_va 19 March 2019 в 09:20
    поделиться

    попробуйте этот код, я переписал некоторые коды

    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.

    Также вы должны уничтожить его при уничтожении директивы, чтобы избежать утечки памяти.

    0
    ответ дан Sheik Althaf 19 March 2019 в 09:20
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: