меню

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

Что это такое Angular Custom Directives?

Angular Custom Directives используются для создания повторно используемых компонентов и добавления специфических функциональностей к элементам HTML. Они определяются с использованием декоратора @Directive, который принимает объект с опциями метаданных. Эти опции включают селектор, входные и выходные параметры и логику директивы.

Вот пример базовая структура кастомной директивы в Angular:

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

@Directive({
  selector: '[appCustomDirective]'
})
export class CustomDirective {
  @Input() appCustomDirective: string;

  constructor(private el: ElementRef) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.el.nativeElement.style.backgroundColor = this.appCustomDirective;
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.el.nativeElement.style.backgroundColor = null;
  }
}
 

В этом примере мы создали пользовательскую директиву с именем appCustomDirective. Она изменяет цвет фона элемента, к которому она применяется, когда указатель мыши входит или выходит из него.

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

  
<div appCustomDirective="lightblue">Hover over me!</div>
  

15 примеров пользовательских директив на каждый день

  1. Пользовательская директива валидации: Директива для пользовательской валидации формы.
  2. Директива Autofocus: Автоматически устанавливает фокус на поле ввода при загрузке страницы.
  3. Директива Lazy Load Images: Ленивая загрузка изображения.
  4. Директива Drag-and-Drop: Реализовывает функциональность Drag-and-Drop элементов.
  5. Директива Ellipsis: Добавляет многоточие к тексту, который выходит за границы контейнера.
  6. Директива Click Outside: Закрывает выпадающий список или модальное окно при щелчке вне его области.
  7. Директива Confirm Dialog: Создает диалоговое окно подтверждения действий.
  8. Директива Infinite Scroll: Реализует бесконечную прокрутку для длинных списков.
  9. Директива Highlight Search Results: Выделяет совпадения поискового запроса в результатах поиска.
  10. Директива Responsive: Показывает или скрывает элементы в зависимости от размера экрана.
  11. Директива Input Mask: Форматирует значения ввода в момент набора.
  12. Директива Tooltip: Отображает подсказки на элементах с дополнительной информацией.
  13. Директива Disable Right-Click: Запрещает правый клик на элементах.
  14. Директива TimeAgo: Отображает время, прошедшее с определенной даты.
  15. Директива Copy to Clipboard: Позволяет пользователям копировать текст в буфер обмена одним щелчком.

Custom Validation Directive

Angular позволяет создавать собственную пользовательскую директиву валидации и реализовать свою логику валидации для элементов управления формы. В этом примере мы создадим пользовательскую директиву валидации, чтобы проверить, содержит ли пароль буквы и цифры. Если пароль не соответствует этим критериям, мы пометим элемент управления формы как недопустимый и отобразим сообщение об ошибке. Вот как можно создать эту пользовательскую директиву валидации:

Создание директивы:

 
ng generate directive password-validator
  

Реализуем Validation Directive:

 
import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms';

@Directive({
  selector: '[appPasswordValidator]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: PasswordValidatorDirective,
      multi: true,
    },
  ],
})
export class PasswordValidatorDirective implements Validator {
  @Input('appPasswordValidator') requiredPattern: string;

  validate(control: AbstractControl): ValidationErrors | null {
    if (control.value) {
      const pattern = new RegExp(this.requiredPattern);
      const isValid = pattern.test(control.value);

      if (!isValid) {
        return { passwordPattern: true };
      }
    }
    return null;
  }
}
  

В данном коде мы создаем кастомную директиву с именем PasswordValidatorDirective. Она реализует интерфейс Validator и предоставляет метод validate. Этот метод вызывается при валидации элемента управления формы.

Использование Custom Validation Directive в шаблоне:

Допустим, что у вас есть форма Angular, вы можете использовать директиву appPasswordValidator на поле ввода, чтобы валидировать пароль.

 
<input
  type="password"
  name="password"
  [(ngModel)]="user.password"
  #password="ngModel"
  appPasswordValidator="[A-Za-z]+[0-9]+"
  required
/>

<div *ngIf="password.invalid && (password.dirty || password.touched)">
  <div *ngIf="password.hasError('required')">Password is required.</div>
  <div *ngIf="password.hasError('passwordPattern')">Password must contain letters and numbers.</div>
</div>
 

Отображение ошибок валидации:

Мы используем template-driven формы Angular для привязки поля ввода к директиве ngModel. Когда пользователь взаимодействует с полем ввода, ошибки валидации отображаются на основе ошибки passwordPattern, возвращаемой методом validate нашей директивы.

Autofocus Directive

Создание пользовательской директивы autofocus в Angular позволяет автоматически установить фокус на поле ввода при загрузке страницы. В этом примере мы создадим пользовательскую директиву с названием appAutofocus, чтобы автоматически перевести фокус на примененный к нему элемент при загрузке страницы. Вот как вы можете реализовать эту директиву:

Создание директивы:

В первую очередь, создайте новую директиву с помощью Angular CLI:

  
ng generate directive autofocus
 

Реализуем директиву Autofocus:

Откройте файл autofocus.directive.ts, созданный Angular CLI, и внесите следующие изменения:

  
import { Directive, ElementRef, AfterViewInit } from '@angular/core';

@Directive({
  selector: '[appAutofocus]'
})
export class AutofocusDirective implements AfterViewInit {
  constructor(private el: ElementRef) {}

  ngAfterViewInit() {
    this.el.nativeElement.focus();
  }
}
  

В этом коде мы создаем пользовательскую директиву с названием AutofocusDirective. Она реализует хук жизненного цикла AfterViewInit, который позволяет нам установить фокус на элементе после инициализации представления.

Подкючаем Autofocus Directive в шаблоне:

Теперь вы можете использовать директиву appAutofocus на любом HTML-элементе, чтобы автоматически установить фокус на нем при загрузке страницы.

 
<input type="text" placeholder="Auto-focused input" appAutofocus />
  

В этом примере мы применяем директиву appAutofocus к элементу input. При загрузке страницы, данное поле ввода автоматически получает фокус, что удобно для пользователя, чтобы сразу начать вводить текст.

Lazy Load Images Directive

Создание пользовательской директивы в Angular для ленивой загрузки изображений может помочь улучшить производительность и пользовательский опыт вашего веб-сайта, загружая изображения только когда они видимы на экране. В этом примере мы создадим пользовательскую директиву с названием appLazyLoad для реализации ленивой загрузки изображений.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive lazy-load
 

Реализуем директиву Lazy Load Images:

Откройте файл lazy-load.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appLazyLoad]'
})
export class LazyLoadDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  @HostListener('window:scroll', ['$event'])
  onScroll() {
    if (this.isElementInViewport()) {
      this.loadImage();
    }
  }

  private isElementInViewport(): boolean {
    const rect = this.el.nativeElement.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  }

  private loadImage() {
    const dataSrc = this.el.nativeElement.getAttribute('data-src');
    if (dataSrc) {
      this.renderer.setAttribute(this.el.nativeElement, 'src', dataSrc);
      this.el.nativeElement.removeAttribute('data-src');
    }
  }
}
 

В этом коде мы создаем пользовательскую директиву под названием LazyLoadDirective. Директива прослушивает событие window:scroll, и когда элемент попадает в область видимости, загружает изображение, заменяя атрибут data-src атрибутом src.

Подкючаем директиву Lazy Load Images в шаблоне:

Для применения директивы appLazyLoad к элементу img используйте атрибут data-src, чтобы указать источник изображения. Атрибут src будет установлен динамически, когда изображение будет видимым в окне просмотра (viewport).

 
<img
  src="placeholder.jpg"
  data-src="lazy-image.jpg"
  alt="Lazy-loaded image"
  appLazyLoad
/>
 

В этом примере мы устанавливаем атрибут data-src в URL изображения, которое вы хотите загрузить лениво. Атрибут src сначала устанавливается на изображение-заглушку или спиннер загрузки.

Drag-and-Drop Directive

Создание пользовательской директивы Drag-and-Drop в Angular позволяет пользователям взаимодействовать с элементами на вашей странице. В этом примере мы создадим пользовательскую директиву с именем appDraggable для Drag-and-Drop элементов.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive draggable
 

Реализуем директиву Drag-and-Drop:

Откройте файл draggable.directive.ts, сгенерированный Angular CLI, и внесите следующие изменения:

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

@Directive({
  selector: '[appDraggable]'
})
export class DraggableDirective {
  private isDragging = false;

  constructor(private el: ElementRef, private renderer: Renderer2) {
    this.renderer.setStyle(this.el.nativeElement, 'cursor', 'grab');
    this.renderer.setStyle(this.el.nativeElement, 'user-drag', 'none');
  }

  @HostListener('mousedown', ['$event'])
  onMouseDown(event: MouseEvent) {
    this.isDragging = true;
    this.renderer.setStyle(this.el.nativeElement, 'cursor', 'grabbing');
    event.preventDefault();
  }

  @HostListener('document:mouseup')
  onMouseUp() {
    if (this.isDragging) {
      this.isDragging = false;
      this.renderer.setStyle(this.el.nativeElement, 'cursor', 'grab');
    }
  }

  @HostListener('document:mousemove', ['$event'])
  onMouseMove(event: MouseEvent) {
    if (this.isDragging) {
      const offsetX = event.clientX - this.el.nativeElement.getBoundingClientRect().left;
      const offsetY = event.clientY - this.el.nativeElement.getBoundingClientRect().top;
      this.renderer.setStyle(this.el.nativeElement, 'position', 'absolute');
      this.renderer.setStyle(this.el.nativeElement, 'left', `${offsetX}px`);
      this.renderer.setStyle(this.el.nativeElement, 'top', `${offsetY}px`);
    }
  }
}
  

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

Подкючаем директиву Drag-and-Drop в шаблоне:

Чтобы применить директиву appDraggable к элементу, добавьте ее в качестве атрибута:

 
<div appDraggable>
  Drag me around!
</div>
 

В этом примере мы применили директиву appDraggable к элементу div. Пользователи могут щелкнуть по элементу и перемещать его по странице.

Ellipsis Directive

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

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive ellipsis
  

Реализуем директиву Drag-and-Drop:

Откройте файл ellipsis.directive.ts, созданный Angular CLI, и измените его следующим образом:

 
import { Directive, ElementRef, Renderer2, AfterViewInit } from '@angular/core';

@Directive({
  selector: '[appEllipsis]'
})
export class EllipsisDirective implements AfterViewInit {
  constructor(private el: ElementRef, private renderer: Renderer2) {}

  ngAfterViewInit() {
    const container = this.el.nativeElement;
    const content = container.innerHTML;
    if (container.scrollWidth > container.clientWidth) {
      this.renderer.setAttribute(container, 'title', content);
      this.renderer.setStyle(container, 'white-space', 'nowrap');
      this.renderer.setStyle(container, 'overflow', 'hidden');
      this.renderer.setStyle(container, 'text-overflow', 'ellipsis');
    }
  }
}
 

В этом коде мы создаем пользовательскую директиву с именем EllipsisDirective. Данная директива автоматически добавляет многоточие к тексту, который выходит за пределы ширины контейнера, устанавливая CSS свойства white-space, overflow и text-overflow.

Подкючаем директиву Ellipsis в шаблоне:

Чтобы применить директиву appEllipsis к элементу, содержащему текст, добавьте ее как атрибут:

 
<div appEllipsis>
  This is a long text that will be truncated with an ellipsis if it overflows its container.
</div>
 

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

Click Outside Directive

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

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive click-outside
 

Реализуем директиву Click Outside:

Откройте файл click-outside.directive.ts, созданный Angular CLI, и измените его следующим образом:

  
import { Directive, ElementRef, Output, EventEmitter, HostListener } from '@angular/core';

@Directive({
  selector: '[appClickOutside]'
})
export class ClickOutsideDirective {
  @Output() appClickOutside = new EventEmitter();

  constructor(private el: ElementRef) {}

  @HostListener('document:click', ['$event'])
  onClick(event: Event): void {
    if (!this.el.nativeElement.contains(event.target)) {
      this.appClickOutside.emit();
    }
  }
}
 

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

Подкючаем директиву Click Outside в шаблоне:

Чтобы применить директиву appClickOutside к элементу выпадающего списка или модального окна, добавьте ее в качестве атрибута.

 
<div appClickOutside (appClickOutside)="closeDropdown()">
  <button (click)="toggleDropdown()">Toggle Dropdown</button>
  <div *ngIf="dropdownOpen" class="dropdown">
    Dropdown content
  </div>
</div>
 

В этом примере мы применили директиву appClickOutside к элементу div, содержащему выпадающий список. Привязка события (appClickOutside)="closeDropdown()" вызовет метод closeDropdown при клике за пределами div.

Confirm Dialog Directive

Создание пользовательской директивы в Angular для реализации диалогового окна подтверждения может помочь вам стандартизировать и упростить процесс подтверждения действий перед их выполнением, например, удаление элементов или совершение непрерываемых изменений. В этом примере мы создадим пользовательскую директиву с именем appConfirmDialog для открытия диалогового окна подтверждения перед выполнением действия.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive confirm-dialog
  

Реализуем директиву Confirm Dialog:

Откройте файл confirm-dialog.directive.ts, созданный Angular CLI, и измените его следующим образом:

 
import { Directive, Input, TemplateRef, ViewContainerRef, HostListener } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component'; // Make sure to import your confirmation dialog component

@Directive({
  selector: '[appConfirmDialog]'
})
export class ConfirmDialogDirective {
  @Input() confirmMessage: string;

  constructor(
    private dialog: MatDialog,
    private templateRef: TemplateRef,
    private viewContainer: ViewContainerRef
  ) {}

  @HostListener('click', ['$event'])
  onClick(event: Event): void {
    event.preventDefault();
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: { message: this.confirmMessage }
    });

    dialogRef.afterClosed().subscribe((result) => {
      if (result) {
        this.viewContainer.createEmbeddedView(this.templateRef);
      }
    });
  }
}
 

В этом коде мы создаем пользовательскую директиву с именем ConfirmDialogDirective. Она прослушивает события клика, открывает диалоговое окно подтверждения с использованием диалога Angular Material и выполняет действие, указанное в шаблоне директивы, если пользователь подтверждает.

Подкючаем директиву Confirm Dialog в шаблоне:

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

  
<button [appConfirmDialog]="'Are you sure you want to perform this action?'">Delete</button>
  

В этом примере мы применили директиву appConfirmDialog к кнопке. При нажатии на кнопку появится диалоговое окно подтверждения с предоставленным сообщением. Действие будет выполнено только в случае подтверждения пользователем.

Infinite Scroll Directive

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

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive infinite-scroll
 

Реализуем директиву Infinite Scroll:

Откройте файл infinite-scroll.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appInfiniteScroll]'
})
export class InfiniteScrollDirective {
  @Input() scrollThreshold = 100;
  @Output() scrolled = new EventEmitter();

  constructor(private el: ElementRef) {}

  @HostListener('scroll', ['$event'])
  onScroll(event: Event): void {
    const element = event.target as HTMLElement;
    const atBottom = element.scrollHeight - element.scrollTop <= element.clientHeight + this.scrollThreshold;

    if (atBottom) {
      this.scrolled.emit();
    }
  }
}
  

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

Подкючаем директиву Infinite Scroll в шаблоне:

Для применения директивы appInfiniteScroll к контейнеру со скроллированием, добавьте ее в виде атрибута и укажите привязку события (scrolled):

 
<div class="scrollable-content" appInfiniteScroll (scrolled)="loadMoreData()">
  <!-- Your list of items -->
</div>
  

В данном примере мы применили директиву appInfiniteScroll к прокручиваемому блоку div. Когда пользователь прокручивает до нижней части блока, вызывается функция loadMoreData(), обычно для получения и добавления дополнительных данных в список.

Highlight Search Results Directive

Создание пользовательской директивы в Angular для выделения результатов поиска внутри блока текста может улучшить пользовательский опыт при поиске определенных терминов в вашем приложении. В этом примере мы создадим пользовательскую директиву с именем appHighlightSearch для выделения результатов поиска в блоке текста.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

  
ng generate directive highlight-search
  

Реализуем директиву Highlight Search Results:

Откройте файл highlight-search.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appHighlightSearch]'
})
export class HighlightSearchDirective implements OnChanges {
  @Input() searchQuery: string;

  constructor(private el: ElementRef) {}

  ngOnChanges() {
    if (this.searchQuery && this.searchQuery.length > 0) {
      const text = this.el.nativeElement.innerText;
      const regex = new RegExp(`(${this.escapeRegExp(this.searchQuery)})`, 'gi');
      const highlightedText = text.replace(regex, '$1');
      this.el.nativeElement.innerHTML = highlightedText;
    }
  }

  private escapeRegExp(query: string): string {
    return query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
  }
}
 

В этом коде мы создаем пользовательскую директиву с именем HighlightSearchDirective. Она прослушивает изменения во входном параметре searchQuery и выделяет результаты поиска в текстовом содержимом элемента с помощью HTML-элемента <mark>.

Подкючаем директиву Highlight Search Results в шаблоне:

Чтобы применить директиву appHighlightSearch к элементу, содержащему текст, добавьте ее в качестве атрибута и укажите входной параметр searchQuery.

  
<p [appHighlightSearch]="searchQuery">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed quisquam iste, qui ex ea voluptate velit
</p>
 

В этом примере мы применили директиву appHighlightSearch к элементу p. Входной параметр searchQuery связан с поисковым запросом, который вы хотите выделить в тексте.

Responsive Directive

Создание пользовательской директивы в Angular для управления видимостью элементов в зависимости от размера экрана поможет вам создать отзывчивый дизайн. В этом примере мы создадим пользовательскую директиву с именем appResponsive, чтобы показывать или скрывать элементы в зависимости от размера экрана.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive responsive
  

Реализуем директиву Responsive:

Откройте файл responsive.directive.ts, созданный Angular CLI, и измените его следующим образом:

 
import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appResponsive]'
})
export class ResponsiveDirective implements OnInit {
  @Input() appResponsive: string; // Comma-separated screen size breakpoints (e.g., 'md, lg')
  private currentScreenWidth: string = 'md'; // Default screen size

  constructor(
    private templateRef: TemplateRef,
    private viewContainer: ViewContainerRef
  ) {}

  ngOnInit() {
    this.detectScreenSize();
  }

  private detectScreenSize() {
    const screenWidth = this.getScreenWidth();
    if (this.appResponsive.includes(screenWidth)) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }

  private getScreenWidth(): string {
    const width = window.innerWidth;
    if (width >= 1200) {
      return 'lg';
    } else if (width >= 992) {
      return 'md';
    } else if (width >= 768) {
      return 'sm';
    } else {
      return 'xs';
    }
  }
}
  

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

Подкючаем директиву Responsive в шаблоне:

Чтобы применить директиву appResponsive к элементу, добавьте ее как атрибут и укажите требуемые точки разрыва размера экрана:

 
<div [appResponsive]="'md, lg'">
  This content is visible on medium and large screens.
</div>
  

В этом примере мы применили директиву appResponsive к элементу div. Содержимое внутри div будет видимым на средних (md) и больших (lg) экранах.

Input Mask Directive

Создание пользовательской директивы в Angular для применения маски ввода может помочь гарантировать, что пользователи вводят данные в определенном формате. В этом примере мы создадим пользовательскую директиву с именем appInputMask для форматирования и проверки ввода в виде номера телефона.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

  
ng generate directive input-mask
  

Реализуем директиву Input Mask:

Откройте файл input-mask.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appInputMask]'
})
export class InputMaskDirective {
  @Input() appInputMask: string = '';

  constructor(private el: ElementRef) {}

  @HostListener('input', ['$event']) onInput(event: InputEvent) {
    const input = event.target as HTMLInputElement;
    const originalValue = input.value.replace(/\D/g, '');
    let maskedValue = '';

    let valueIndex = 0;
    for (let maskIndex = 0; maskIndex < this.appInputMask.length; maskIndex++) {
      if (/\d/.test(this.appInputMask[maskIndex])) {
        if (originalValue[valueIndex]) {
          maskedValue += originalValue[valueIndex++];
        } else {
          break;
        }
      } else {
        maskedValue += this.appInputMask[maskIndex];
      }
    }

    input.value = maskedValue;
  }
}
  

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

Подкючаем директиву Input Mask в шаблоне:

Для применения директивы appInputMask к элементу input добавьте ее в качестве атрибута и укажите маску ввода:

  
<input type="text" [appInputMask]="'(999) 999-9999'">
  

В этом примере нам потребовалось применить директиву appInputMask к элементу input. Указанная маска ввода будет форматировать введенное значение как номер телефона, например, (123) 456-7890.

Tooltip Directive

Создание пользовательской директивы в Angular для отображения всплывающих подсказок может улучшить пользовательский интерфейс, предоставляя дополнительную информацию при взаимодействии пользователей с определенными элементами. В этом примере мы создадим пользовательскую директиву с названием appTooltip для показа всплывающих подсказок при наведении мыши.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive tooltip
 

Реализуем директиву Tooltip:

Откройте файл tooltip.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appTooltip]'
})
export class TooltipDirective implements OnInit {
  @Input() appTooltip: string;

  private tooltipElement: HTMLDivElement;
  private isVisible: boolean = false;

  constructor(private el: ElementRef, private renderer: Renderer2) {}

  ngOnInit() {
    this.createTooltipElement();
  }

  @HostListener('mouseenter')
  onMouseEnter() {
    this.showTooltip();
  }

  @HostListener('mouseleave')
  onMouseLeave() {
    this.hideTooltip();
  }

  private createTooltipElement() {
    this.tooltipElement = this.renderer.createElement('div');
    this.renderer.addClass(this.tooltipElement, 'tooltip');
    this.tooltipElement.innerHTML = this.appTooltip;
    this.renderer.setStyle(this.tooltipElement, 'display', 'none');
    this.renderer.appendChild(this.el.nativeElement, this.tooltipElement);
  }

  private showTooltip() {
    const rect = this.el.nativeElement.getBoundingClientRect();
    const top = rect.top - this.tooltipElement.clientHeight - 10;
    const left = rect.left + rect.width / 2 - this.tooltipElement.clientWidth / 2;

    this.renderer.setStyle(this.tooltipElement, 'top', `${top}px`);
    this.renderer.setStyle(this.tooltipElement, 'left', `${left}px`);
    this.renderer.setStyle(this.tooltipElement, 'display', 'block');
    this.isVisible = true;
  }

  private hideTooltip() {
    this.renderer.setStyle(this.tooltipElement, 'display', 'none');
    this.isVisible = false;
  }
}
  

В этом коде мы создаем пользовательскую директиву с названием TooltipDirective. Она прослушивает события mouseenter и mouseleave и отображает или скрывает элемент всплывающей подсказки на основе входного параметра appTooltip.

Подкючаем директиву Tooltip в шаблоне:

Для применения директивы appTooltip к элементу добавьте ее в качестве атрибута и укажите текст подсказки:

 
<button [appTooltip]="'Click me to learn more'">Learn More</button>
 

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

Disable Right-Click Directive

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

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive disable-right-click
 

Реализуем директиву Disable Right-Click:

Откройте файл disable-right-click.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appDisableRightClick]'
})
export class DisableRightClickDirective {
  constructor() {}

  @HostListener('contextmenu', ['$event'])
  onRightClick(event: Event): void {
    event.preventDefault();
  }
}
  

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

Подкючаем директиву Disable Right-Click в шаблоне:

Для применения директивы appDisableRightClick к элементу, добавьте ее в качестве атрибута.

 
<div appDisableRightClick>
  Right-clicking is disabled on this element.
</div>
 

В этом примере мы применили директиву appDisableRightClick к элементу div. Щелчок правой кнопкой мыши на этом элементе будет отключен.

TimeAgo Directive

Создание пользовательской директивы в Angular для отображения времени в формате "time ago" (относительное время) может быть полезным для показа, сколько времени прошло с момента события. В этом примере мы создадим пользовательскую директиву с именем appTimeAgo для отображения разницы во времени в удобном для пользователя формате.

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

  
ng generate directive time-ago
  

Реализуем директиву TimeAgo:

Откройте файл time-ago.directive.ts, созданный Angular CLI, и измените его следующим образом:

 
import { Directive, Input, ElementRef, Renderer2, OnChanges, SimpleChanges } from '@angular/core';

@Directive({
  selector: '[appTimeAgo]'
})
export class TimeAgoDirective implements OnChanges {
  @Input() appTimeAgo: Date;

  constructor(private el: ElementRef, private renderer: Renderer2) {}

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.appTimeAgo) {
      this.updateTimeAgo();
    }
  }

  private updateTimeAgo(): void {
    if (this.appTimeAgo instanceof Date) {
      const timeDifference = Date.now() - this.appTimeAgo.getTime();
      const secondsAgo = Math.floor(timeDifference / 1000);

      let text: string;

      if (secondsAgo < 60) {
        text = 'just now';
      } else if (secondsAgo < 3600) {
        const minutes = Math.floor(secondsAgo / 60);
        text = `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
      } else if (secondsAgo < 86400) {
        const hours = Math.floor(secondsAgo / 3600);
        text = `${hours} hour${hours > 1 ? 's' : ''} ago`;
      } else {
        const days = Math.floor(secondsAgo / 86400);
        text = `${days} day${days > 1 ? 's' : ''} ago`;
      }

      this.renderer.setProperty(this.el.nativeElement, 'textContent', text);
    }
  }
}
 

В этом коде мы создаем пользовательскую директиву с именем TimeAgoDirective. Она отслеживает изменения входного параметра appTimeAgo, который должен быть объектом JavaScript Date, и обновляет содержимое текста элемента для отображения относительной разницы во времени.

Подкючаем директиву TimeAgo в шаблоне:

Чтобы применить директиву appTimeAgo к элементу, добавьте ее как атрибут и привяжите входной параметр appTimeAgo к объекту типа Date.

  
<p [appTimeAgo]="postDate">

В этом примере мы применили директиву appTimeAgo к элементу p, и привязали свойство postDate к входному параметру appTimeAgo. Директива будет отображать относительную разницу во времени между текущим временем и указанной postDate.

Copy to Clipboard Directive

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

Создание директивы:

Создадим новую директиву с помощью Angular CLI:

 
ng generate directive copy-to-clipboard
 

Реализуем директиву Copy to Clipboard:

Откройте файл copy-to-clipboard.directive.ts, созданный Angular CLI, и измените его следующим образом:

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

@Directive({
  selector: '[appCopyToClipboard]'
})
export class CopyToClipboardDirective {
  @Input() appCopyToClipboard: string;

  constructor(private el: ElementRef) {}

  @HostListener('click')
  onClick() {
    if (this.appCopyToClipboard) {
      const textarea = document.createElement('textarea');
      textarea.value = this.appCopyToClipboard;
      document.body.appendChild(textarea);
      textarea.select();
      document.execCommand('copy');
      document.body.removeChild(textarea);
    }
  }
}
  

В этом коде мы создаем пользовательскую директиву с именем CopyToClipboardDirective. Она прослушивает события щелчка по элементу, к которому применяется, создает временный элемент textarea, копирует содержимое и удаляет элемент textarea из DOM.

Подкючаем директиву Copy to Clipboard в шаблоне:

Чтобы применить директиву appCopyToClipboard к элементу, добавьте ее в качестве атрибута и свяжите входное значение appCopyToClipboard с текстом, который вы хотите скопировать.

 
<button [appCopyToClipboard]="'Text to copy'">Copy to Clipboard</button>
  

В этом примере мы применили директиву appCopyToClipboard к элементу кнопки. При нажатии пользователем на кнопку, текст "Text to copy" будет скопирован в буфер обмена.

Чтобы обеспечить распознавание и правильный импорт всех директив, вы можете попытаться импортировать их непосредственно в свой компонент или создать отдельный модуль Angular и импортировать все пользовательские директивы в этот модуль. Вот как вы можете это сделать:

Создайте новый модуль для ваших пользовательских директив (например, custom-directives.module.ts):

  
import { NgModule } from '@angular/core';

// Import all your custom directives here
import { CustomValidationDirective } from './custom-validation.directive';
import { AutofocusDirective } from './autofocus.directive';
import { LazyLoadImagesDirective } from './lazy-load-images.directive';
import { DragAndDropDirective } from './drag-and-drop.directive';
import { EllipsisDirective } from './ellipsis.directive';
import { ClickOutsideDirective } from './click-outside.directive';
import { ConfirmDialogDirective } from './confirm-dialog.directive';
import { InfiniteScrollDirective } from './infinite-scroll.directive';
import { HighlightSearchDirective } from './highlight-search.directive';
import { ResponsiveDirective } from './responsive.directive';
import { InputMaskDirective } from './input-mask.directive';
import { TooltipDirective } from './tooltip.directive';
import { DisableRightClickDirective } from './disable-right-click.directive';
import { TimeAgoDirective } from './time-ago.directive';
import { CopyToClipboardDirective } from './copy-to-clipboard.directive';

@NgModule({
  declarations: [
    // Add all your custom directives here
    CustomValidationDirective,
    AutofocusDirective,
    LazyLoadImagesDirective,
    DragAndDropDirective,
    EllipsisDirective,
    ClickOutsideDirective,
    ConfirmDialogDirective,
    InfiniteScrollDirective,
    HighlightSearchDirective,
    ResponsiveDirective,
    InputMaskDirective,
    TooltipDirective,
    DisableRightClickDirective,
    TimeAgoDirective,
    CopyToClipboardDirective,
  ],
  exports: [
    // Export all the directives so they can be used in other modules
    CustomValidationDirective,
    AutofocusDirective,
    LazyLoadImagesDirective,
    DragAndDropDirective,
    EllipsisDirective,
    ClickOutsideDirective,
    ConfirmDialogDirective,
    InfiniteScrollDirective,
    HighlightSearchDirective,
    ResponsiveDirective,
    InputMaskDirective,
    TooltipDirective,
    DisableRightClickDirective,
    TimeAgoDirective,
    CopyToClipboardDirective,
  ],
})
export class CustomDirectivesModule {}
 

Импортируйте и используйте этот CustomDirectivesModule в модуле, где вы хотите использовать ваши пользовательские директивы. Не забудьте добавить CustomDirectivesModule в массив импортируемых модулей вашего модуля.

 
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CustomDirectivesModule } from './custom-directives.module';

@NgModule({
  declarations: [
    // Your components and other declarations
  ],
  imports: [
    BrowserModule,
    CustomDirectivesModule, // Import your custom directives module here
  ],
  bootstrap: [YourAppComponent],
})
export class YourAppModule {}
 

Заключение

Пользовательские директивы являются фундаментальной частью разработки на Angular и предлагают способ создания повторно используемых компонентов и добавления функциональности к элементам HTML. В этой статье мы рассмотрели концепцию кастомных директив и создали 15 примеров, чтобы продемонстрировать их универсальность. Используя и разрабатывая пользовательскиие директивы, вы можете сделать ваши приложения на Angular более модульными, легко поддерживаемыми и удобными для пользователей. Начните экспериментировать с пользовательскими директивами в своих проектах, чтобы раскрыть их полный потенциал.


Возможно, вам будет интересно

Улучшение читаемости кода в проектах Angular: мастерство работы с Enum и лучшие практики

Enum в TypeScript помогает упростить работу с определенными ограниченными наборами значений, делая код более удобным и понятным.

Angular тестирование component с помощью Jest

Тестирование компонентов в Angular формально является задачей тестирования двух сущностей: Html шаблона и Typescript класса. И адекватное тестирование компонента заключается проверке корректной работы шаблона и класса.

Angular Signals

Версия Angular 16 была выпущена в начале мая, и эта версия полна новых функций. Но одной из особенностей, о которой все говорят, является новая возможность - Сигналы. Это настоящий поворотный момент, который находится в стадии предварительного просмотра разработчиками и будет выпущен позже в этом году, в версии 17.

Обнаружение локальных изменений в Angular 17

Как использовать сигналы Angular и стратегию обнаружения изменений OnPush для улучшения производительности с локальным обнаружением изменений.

Оформление заявки

Документы на создание сайта

Изучите наше коммерческое предложение, заполните БРИФ и отправьте его на почту maxidebox@list.ru. Изучив все пожелания из БРИФ-а, обратным ответом оповестим Вас по стоимости разработке, ответим на вопросы.

КП на создание сайта Коммерческое предложение на созданеи сайта

Мы берем на себя ответственность за все стадии работы и полностью избавляем клиентов от забот и необходимости вникать в тонкости.

Скачать БРИФ (акета) на создание сайта Скачать БРИФ (акета) на создание сайта

Зополните у БРИФ-а все необходимые поля. Сделайте краткое описание к каждому из пунктов анкеты, привидите примеры в соответсвующий пунктах - это позволит лучше понять Ваши ожидания и требования к сайту