Застосовувати директиву умовно


109

Для додавання я використовую Матеріал 2 md-raised-button. Я хочу застосувати цю директиву лише в тому випадку, якщо певна умова стане істинною.

Наприклад:

<button md-raised-button="true"></button>

Ще один приклад: я створив основну динамічну реактивну форму в планку. Я використовую formArrayNameдирективу реактивної форми для масиву елементів управління. Я хочу застосувати formArrayNameдирективу лише в тому випадку, якщо конкретна умова стане істинною, інакше не додайте formArrayNameдирективу.

Ось посилання на планкер .


Так, md-підвищена кнопка - це директива атрибутів ( material.angular.io/components/component/button )
користувач2899728

Застосування умов, щодо яких використовуються директиви, швидше за все, зробить AoT марним, оскільки ви не зможете складати шаблони, якщо програма не працює.
Реакційний

Відповіді:


55

Я не знаю, чи можна застосовувати директиви, що базуються на умові, але для вирішення проблеми буде 2 кнопки та відображення їх на основі умови .

<button *ngIf="!condition"></button>
<button *ngIf="condition" md-raised-button></button> 

Редагувати: можливо, це буде корисним.


13
Спасибі за вашу відповідь. Але я вже використав цю техніку на прикладі "плункер", який я детально додав. Це хороший варіант, але непогана ідея, якщо код складний. Тому що ця методика руйнує концепцію повторного використання. Ви можете побачити мій приклад у plunker і помітити, як мій код дублюється через такий підхід. Ось чому я не хочу використовувати цю техніку. Я хочу краще рішення, щоб я міг генерувати динамічні елементи за допомогою.
користувач2899728

1
Я бачу. Ви можете обернути код, який дублюється в компоненті.
LLL

3
Це гарна ідея, але, на жаль, вона не працює у випадку реактивних форм. З реактивними формами з’являється інше питання. Якщо я вкладу дані в окремий компонент, то кутовий вимагатиме від мене додати [formGroup] = "form" і в цей дочірній компонент. Але якщо я це зробити, то прив'язка масиву не буде працювати.
користувач2899728

15
Це жахливо рішення, оскільки він дублює код. Уявіть, що це не просто кнопка, а дів з великою кількістю html-коду всередині нього.
Шачар Хар-Шув

87

Якщо вам просто потрібно додати атрибут, щоб запустити правила CSS, ви можете скористатися методом нижче: (це не динамічно створює / знищує директиву)

<button [attr.md-raised-button]="condition ? '' : null"></button>

Застосовано те саме до вашого планку: fork

Оновлення:

Як condition ? '' : null працює як значення:

Коли його порожній рядок ( ''), він стаєattr.md-raised-button="" , коли його nullатрибут не буде існувати.

Оновлення: оновлення plunker: fork (виправлені проблеми з версією. Зверніть увагу, що спочатку питання було засноване на кутовому 4)


@Luke Так, якщо ви маєте на увазі "(зараз)" як: з 2017-01-06, що було 5 місяців до того, як було задано питання. див. кутовий
журнал

@Aldracor кутовий 5.2.1, не працює. І я не розумію, чому це має виглядати "умова?": Нульове ", коли обидва результати в основному хибні. Що має бути замість ''? "справжній" також не працює.
Арсеній Фомін

1
тому для тих, хто не хоче створити html-елемент для того, щоб їх директива працювала і використовувала ng-контейнер, я просто пішов із переходом у [включено] = "booleanVar"
Бен Таліадорос

7
Не працює для мене в кутовій 6. Зразок планку не минає екран завантаження. На основі мого читання, цей підхід може працювати для атрибутів HTML, але не буде працювати для кутових директив. Первісне запитання стосувалося кутових директив з бібліотеки матеріалів.
JeffryHouser

6
@kbpontius дякую за коментар, він працює на атрибутах Html, але не на кутових директивах (як атрибут)
Reza,

19

Як уже зазначалося, це здається неможливим. Одне, що можна використати для запобігання принаймні певного дублювання ng-template. Це дозволяє витягти вміст елемента, на який впливає ngIfрозгалуження.

Якщо ви, наприклад, хочете створити ієрархічний компонент меню, використовуючи Angular Material:

<!-- Button contents -->
<ng-template #contentTemplate>
    <mat-icon *ngIf="item.icon != null">{{ item.icon }}</mat-icon>
    {{ item.label }}
</ng-template>

<!-- Leaf button -->
<button *ngIf="item.children == null" mat-menu-item
    (click)="executeCommand()"
    [disabled]="enabled == false">
    <ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</button>
<!-- Node button -->
<ng-container *ngIf="item.children != null">
    <button mat-menu-item
        [matMenuTriggerFor]="subMenu">
        <ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
    </button>

    <mat-menu #subMenu="matMenu">
        <menu-item *ngFor="let child of item.children" [item]="child"></menu-item>
    </mat-menu>
</ng-container>

Тут умовно застосовувана директива matMenuTriggerFor, яку слід застосовувати лише до пунктів меню з дітьми. Вміст кнопки вставляється в обох місцях через ngTemplateOutlet.


6
Це єдина відповідь, яка дозволяє розробнику використовувати умовні директиви, а також повторну корисність коду.
Ravinder Payal

16

Це може пізно, але це життєздатний та елегантний метод умовного застосування директиви.

У класі директив створіть вхідну змінну:

@Input('myDirective') options: any;

При застосуванні директиви встановіть властивість застосовувати вхідну змінну:

<div [myDirective] = {apply: someCondition}></div>

У методі директиви перевірте змінну this.options.apply і застосуйте логіку директиви виходячи з умови:

ngAfterViewInit(): void {
    if (!this.options.apply) {
        return;
    }

    // directive logic
}

3
Це не працює для мене, оскільки директива все ще існує в компоненті, вона просто не має логіки. Я хотів би, щоб існування директиви застосовувалося умовно, зокрема, тому що існує css, який перевіряє цю директиву.
Ран Лоттем

У вас інша проблема, ніж перерахована тут (Застосовуйте директиву умовно). Опублікуйте свою проблему, і люди допоможуть вам. Спочатку ви можете поставити директиву на div і поставити ng-контейнер із * ngIf навколо нього, щоб застосувати вашу умову. ngIf видаляє дівовий вузол з DOM, тож він може працювати. Я просто здогадуюсь, вам потрібно опублікувати свою проблему із зразками коду / описом для ppl, щоб допомогти вам.
Тіха

Це не гарне рішення. Директива все ще ініціалізується.
Діно

8

Як також заявили інші, directives їх неможливо застосовувати динамічно.

Однак якщо ви просто хочете переключити md-buttonстиль з плоского на піднятий , то це

<button md-button [class.mat-raised-button]="isRaised">Toggle Raised Button</button>

зробив би трюк. Плункер


3

Це може бути вирішенням також:

[md-raised-button]="condition ? 'true' : ''"


Він працює для кутового 4, іонного 3, як це:

[color]="condition ? 'primary' : ''"де conditionфункція, яка вирішує, активна сторінка це чи ні. Весь код виглядає приблизно так:

<button *ngFor="let page of ..." [color]="isActivePage(page) ? 'primary' : ''">{{ page.title }}</button>


2

В даний час існує NO спосіб умовно застосувати директиву до компонента. Це не підтримується. Компоненти, які ви створили, можна додавати або видаляти умовно.

Вже є випуск, створений для того ж з angular2 , тому це має бути і з angular4.

Крім того, ви можете піти на варіант з ng-if

<button ngIf="!condition"></button>
<button ngIf="condition" md-raised-button></button> 

1
вже висвітлюється у відповіді LLL
Sumit Ramteke

2

Я не зміг знайти приємне існуюче рішення, тому я створив власну директиву, яка це робить.

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

@Directive({
  selector: '[dynamic-attr]'
})
export class DynamicAttrDirective {
  @Input('dynamic-attr') attr: string;
  private _el: ElementRef;

  constructor(el: ElementRef) {
    this._el = el;
  }

  ngOnInit() {
    if (this.attr === '') return null;
    const node = document.createAttribute(this.attr);
    this._el.nativeElement.setAttributeNode(node);
  }
}

Тоді ваш html:

<div dynamic-attr="{{hasMargin: 'margin-left' ? ''}}"></div>


Ви можете використовувати лише @HostBinding('attr.dynamic-attr') @Input('dynamic-attr') attr: string;замість ngOnInit + ElementRef.
pinguinjkeke

2
Це не відповідь на питання про те, як динамічно додати директиву , а не атрибут.
Кріс Хайнс

2

Можливо, це комусь допоможе.

У наведеному нижче прикладі я маю my-button.component.htmlта хочу застосувати *appHasPermissionдирективу до <button>єдиного, якщо roleатрибут встановлений.

<ng-container *ngIf="role; else buttonNoRole" >
  <ng-container *appHasPermission="role">
    <!-- button with *appHasPermission -->
    <ng-template *ngTemplateOutlet="buttonNoRole;"></ng-template>
  </ng-container>
</ng-container>

<ng-template #buttonNoRole>
  <!-- button without *appHasPermission -->
  <button
    mat-raised-button type="button"
    [color]="color"
    [disabled]="disabled"
    [(appClickProgress)]="onClick"
    [key]="progressKey">
    <mat-icon *ngIf="icon">{{ icon }}</mat-icon> {{ label }}
  </button>
</ng-template>

Таким чином ви не дублюєте <button>код.


0

так це можливо.

html-сторінка з директивою appActiveAhover :)

  <li routerLinkActive="active" #link1="routerLinkActive">
        <a [appActiveAhover]='link1.isActive?false:true' routerLink="administration" [ngStyle]="{'background':link1.isActive?domaindata.get_color3():none}">
          <i class="fa fa-users fa-lg" aria-hidden="true"></i> Administration</a>
      </li>
      <li  routerLinkActive="active" #link2="routerLinkActive">
        <a [appActiveAhover]='link2.isActive?false:true' routerLink="verkaufsburo" [ngStyle]="{'background':link2.isActive?domaindata.get_color3():none,'color':link2.isActive?color2:none}">
          <i class="fa fa-truck fa-lg" aria-hidden="true"></i> Verkaufsbüro</a>
      </li>
      <li  routerLinkActive="active" #link3="routerLinkActive">
        <a [appActiveAhover]='link3.isActive?false:true' routerLink="preisrechner" [ngStyle]="{'background':link3.isActive?domaindata.get_color3():none}">
          <i class="fa fa-calculator fa-lg" aria-hidden="true" *ngIf="routerLinkActive"></i> Preisrechner</a>
      </li>

директива

@Directive({
  selector: '[appActiveAhover]'
})
export class ActiveAhoverDirective implements OnInit {
  @Input() appActiveAhover:boolean;
  constructor(public el: ElementRef, public renderer: Renderer, public domaindata: DomainnameDataService) {
}

  ngOnInit() {
  }

  @HostListener('mouseover') onMouseOver() {
    if(this.appActiveAhover){
      this.renderer.setElementStyle(this.el.nativeElement, 'color', this.domaindata.domaindata.color2);
    }
  }

  @HostListener('mouseout') onMouseOut() {
    if(this.appActiveAhover){
      this.renderer.setElementStyle(this.el.nativeElement, 'color', 'white');
    }
  }

}

2
В якості примітки, Отображатель застаріла, замість цього використовувати Renderer2: alligator.io/angular/using-renderer2
tam.teixeira


-1

Використовуйте NgClass

[ngClass]="{ 'mat-raised-button': trueCondition }"

Приклад справжнього стану:

this.element === 'Today'

або булева функція

getTruth()

повний приклад:

  <button [ngClass]="{ 'mat-raised-button': trueCondition }">TEXT</button>

Якщо ви хочете клас за замовчуванням:

  <button [ngClass]="{ 'mat-raised-button': trueCondition, 'default-class': !trueCondition }">TEXT</button>

6
Це не те, про що я питав. Ви показуєте приклад для класу. Я говорю про атрибут-директиву.
користувач2899728

@ user2899728 На жаль, іншого способу це зробити немає. (Ви не можете встановити md-raised-buttonатрибут як хибний)
Edric

@ user2899728 Немає можливості умовно застосовувати директиви. Я намагався дати вам те, що ви шукали (кінцевий результат) з іншим підходом ("засоби").
Моше

Коли ви пропонуєте креативну альтернативу, зазвичай це допомагає спершу скласти рядок коментарів, щоб описати, куди ви йдете зі своєю відповіддю.
bvdb

1
@bvdb дякую за добрі слова. Я писав без вказівки, і це була помилка. В майбутньому я сподіваюсь відредагувати цю публікацію, оскільки вона могла б допомогти навіть одній людині.
Моше

-1

Я отримав ще одне уявлення про те, що ти можеш зробити.

Ви можете зберігати html, який ви хочете замінити у змінній, як рядок, а потім додавати / видаляти директиву з нього за своїм бажанням, використовуючи bypassSecurityTrustHtmlметод DomSanitizer .

У мене не виходить чисте рішення, але принаймні вам не потрібно повторювати код.


-3

Станом на 18 січня 2019 року, саме так я умовно додав директиву в Angular 5 і вище. Мені потрібно було змінити колір <app-nav>компонента на основі darkMode. Якщо сторінка була в темному режимі чи ні.

Це працювало для мене:

<app-nav [color]="darkMode ? 'orange':'green'"></app-nav>

Я сподіваюся, що це комусь допоможе.

EDIT

Це змінює значення атрибута (кольору) на основі умови. Просто буває так, що колір визначається за допомогою директиви. Тому будь-хто, хто читає це, не плутайтесь, це не застосовує директиву умовно (тобто, це означає додавання та видалення директиви до дому на основі умови)


3
Ви застосовуєте директиву в обох випадках лише з різними параметрами (наприклад, помаранчевим або зеленим). Питання вимагає взагалі ігнорувати директиву на основі умови.
Mojtaba
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.