angular
February 20

Host-директивы в Angular

Начиная с Angular 15 появилась новая возможность: хост-директивы.


Давайте начнем с примера:

@Component({
 selector: '...',
 host: {
 ...
 '[class.my-disabled-class]': 'disabled',
 '[attr.disabled]': 'disabled || null',
 '[attr.aria-disabled]': 'disabled || null',
 ...
 },
 template: `...`
})
class MyComponent {
 @Input() public disabled = false;
  // many other stuffs
}

Как можно улучшить этот код? Первая мысль - создать директиву.

@Directive({
 selector: '[myDisabledState]',
 standalone: true,
 host: {
 '[attr.disabled]': 'disabled || null',
 '[attr.aria-disabled]': 'disabled || null',
 '[class.rc-disabled]': 'disabled',
 },
})
export class DisabledStateDirective {
 @Input() public disabled = false;
}

И теперь код можно упростить до такого:

@Component({
 selector: '...',
 host: {
 ...
 },
 hostDirectives: [{
 directive: DisabledStateDirective,
 inputs: ['disabled'],
 }],
 template: `...`
})
class MyComponent {
 // many other stuffs
}

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

@Component({
  selector: '...',
  host: {
    ...
  },
  hostDirectives: [{
    directive: DisabledStateDirective,
    inputs: ['disabled'],
  }],
  template: `...`
})
class MyComponent {
  private readonly _disabledState: DisabledStateDirective = inject(DisabledStateDirective, { self: true });

  public myFunction(): void {
    if (this.disabledState.disabled) {
      
    }
  }
}

Мы просто можем использовать метод inject, чтобы получить DisabledStateDirective.