Угловой 7 |HostListener размытие условно остановить все другие обратные вызовы событий - PullRequest
3 голосов
/ 19 сентября 2019

У меня есть одно требование, когда мы хотим, чтобы пользователь разрешал ошибки в поле ввода, и пока это не будет сделано, пользователю не разрешается выполнять какие-либо другие операции на экране.

Для того же самого я реализовал HostListener наполе ввода и onBlur Я устанавливаю фокус обратно на поле ввода, если есть сценарии проверки сбоя.

И я делаю e.preventDefault () и e.stopPropagtion (), чтобы остановить все другие обратные вызовы событийбыть выполненным на странице (как после установки focus back, blur будет первым событием, которое будет выполнено).

Но так или иначе для любого внешнего события, blur действительно выполняется, но этоне ограничивая другие события, которые будут выполнены.Они также выполняются, без чего я не могу достичь желаемой функциональности.

import { Directive, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appNumberFormat]'
})
export class NumberFormatDirective {

  constructor() { }

  @HostListener('blur', ['$event']) blur(evt) {
    evt.preventDefault();
    console.log('field focus...');
    evt.target.focus();
    return false;
    // if (evt.target.value.trim() === '') {
    //     this.formControl.control.setValue(this.defaultValue);
    // }
  }
}

Я повторил тот же сценарий в stackBlitz.Пожалуйста, посмотрите.

https://stackblitz.com/edit/angular-54ermg

Ответы [ 6 ]

3 голосов
/ 26 сентября 2019

Blur не предотвращает другое событие, потому что оно работает независимо.Установка указателя-события на никто не будет препятствовать щелчку.

onBlur(e) {
    e.preventDefault();
    e.stopPropagation();
    document.body.style.pointerEvents = 'none';
    console.log('field focus...');
    setTimeout(() => {
      e.target.focus();
    }, 10);

    setTimeout(() => {
      document.body.style.pointerEvents = 'initial';
    }, 300);

    return;
  }

Вы также можете добавить оверлей, когда фокус ввода вместо использования pointer-events: none.В обоих случаях вам нужно будет обрабатывать нажатия табуляции.

Чтобы предотвратить табуляцию + введите add для элемента ввода:

(keydown)="onKeyDown($event)" 

В компоненте ts:

onKeyDown(event) {
    if (event.code === 'Tab') {
      event.preventDefault();
      event.stopPropagation();
    }
  }
1 голос
/ 25 сентября 2019

Я не думаю, что это идеальный способ для достижения требуемой функциональности.Я думаю, что другие кнопки / якорные ссылки должны оставаться отключенными, когда есть ошибки в форме.Вы можете привязать свойство disabled для кнопок и якорных ссылок к функции, которая будет возвращать true / false после проверки проверок.

Тем не менее, браузер выполняет события в определенном порядке, и если вам нужно остановитьсобытие клика от прогрессирования, вы должны вернуть false.Я реализовал то же самое с использованием логической переменной, которая будет устанавливать значение true / false на основе проверок проверки, я создал здесь ответвление вашего кода - https://stackblitz.com/edit/angular-uay8rm

  preventOtherActions: boolean = true;
  txtBoxValue: string = "";

  submitForm($event) {
    if(this.preventOtherActions) {
      return false;
    }
    console.log('submitForm');
  }

  onBlur(e) {
    console.log('field focus...');
    setTimeout(() => {
       e.target.focus();
      }, 10);
    this.preventOtherActions = this.txtBoxValue.length < 6;    
    return;
  }
0 голосов
/ 29 сентября 2019

Один из способов сделать это - отключить все события на странице с помощью этого решения (и создать пользовательскую настройку для нажатия клавиш, которая не позволяет вводить клавишу).

Остановить распространение для всех событий

  disableAllUserEvents = () => {
    const events = ["click", "contextmenu", "dblclick", "mousedown", "mouseenter", "mouseleave", "mousemove",
        "mouseover", "mouseout", "mouseup", "blur", "change", "focus", "focusin",
        "focusout", "input", "invalid", "reset", "search", "select", "submit", "drag", "dragend", "dragenter",
        "dragleave", "dragover", "dragstart", "drop", "copy", "cut", "paste", "mousewheel", "wheel", "touchcancel",
        "touchend", "touchmove", "touchstart"];

    const handler = event => {
      event.stopPropagation();
      event.preventDefault();

      return false;
  };

    for (let i = 0, l = events.length; i < l; i++) {
        document.addEventListener(events[i], handler, true);
    }

    return () => {
        for (let i = 0, l = events.length; i < l; i++) {
            document.removeEventListener(events[i], handler, true);
        }
    };
  };

и снова включите событие, когда все в порядке.Это немного грубая сила, но она работает.

https://stackblitz.com/edit/angular-68vdrq

0 голосов
/ 25 сентября 2019

Я не совсем уверен, что вы пытаетесь достичь, но хитрость может заключаться в том, чтобы ограничить выполнение focus () на основе разных случаев, когда вы вызываетесь в onBlur (), потому что вы будете вызываться каждый раз, когда размытиеявляется запросом, поскольку вы связали событие.

Чтобы предотвратить выполнение, вы можете запускать его только тогда, когда вам нужно, но это не совсем идеально: скажем, когда ваш e.target или e.relatedTarget не тот, который вы хотитеили что-то в этом роде, или когда document.activeElement уже является входным сигналом, вам не нужно перефокусировать его на onblur (), но снова ... Не идеально

Надеюсь, это поможет!

0 голосов
/ 25 сентября 2019

Способ решения этой проблемы будет через переменную вашего компонента (которая указывает, является ли форма действительной) и простой элемент CSS, который блокирует все щелчки.

Вы должны быть осторожны, хотяи убедитесь, что вы сосредоточены на правильном элементе, а также на том, что это не будет продолжаться вечно, потому что я должен сказать, что это выглядит довольно раздражающим с точки зрения пользовательского опыта.

В вашем HTML-шаблоне:

<div *ngIf="formIsInvalid" class="click-blocker"></div>

И на вашем css:

.click-blocker {
  position: absolute;
  background-color: rgba(1, 1, 1, 0.1); // adjust the opacity as you wish
  bottom: 0;
  left: 0;
  right: 0;
  top: 0;
  height: 100vh;
  width: 100vw;
  z-index: 1;
}

Я реализовал это в вашем стеке: https://stackblitz.com/edit/angular-za1lgx

0 голосов
/ 23 сентября 2019

Вы можете добавить дополнительное свойство Input для включения / выключения функции фокуса.Если у вас есть Реактивная форма, вы можете подключить ее к состоянию VALID формы.

export class NumberFormatDirective {
  @Input() enableTargetFocus: boolean;

  @HostListener('blur', ['$event']) blur(evt) {
    if (this.enableTargetFocus === false) {
      return;
    }
    ...
  }
}

HTML:

<input type="text" appNumberFormat [enableTargetFocus]="form.invalid" />
...