меню

Пользовательские директивы (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 Swiper Image Touch Slider

Учебный материал по swipe слайдеру изображений в Angular, swiper. В этом подробном руководстве мы объясним, как создать swipe слайдер изображений/контента или карусель в приложении angular с помощью пакета npm ngx-useful-swiper.

Связывание свойств и событий

Создание кастомных событий и их обработчиков. Импорт свойств родительского компонента.

Изменяют ли автономные компоненты способ написания кода в Angular?

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

10 лучших UI библиотек для Angular

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

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

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

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

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

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

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

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