Zastosuj dyrektywę warunkowo

112

Do dodania używam materiału 2 md-raised-button. Chcę stosować tę dyrektywę tylko wtedy, gdy spełnią się określone warunki.

Na przykład:

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

Inny przykład: stworzyłem podstawową dynamiczną formę reaktywną w plunkerze. Używam formArrayNamedyrektywy formy reaktywnej dla tablicy kontrolek. Chcę zastosować formArrayNamedyrektywę tylko wtedy, gdy określony warunek stanie się prawdziwy, w przeciwnym razie nie dodawaj formArrayNamedyrektywy.

Oto link do plunkera .

user2899728
źródło
Tak, przycisk podniesiony md, to dyrektywa atrybutów ( material.angular.io/components/component/button )
user2899728
Zastosowanie warunków, w których są używane dyrektywy, prawdopodobnie uczyniłoby AoT bezużytecznym, ponieważ nie byłby w stanie skompilować szablonów, gdyby aplikacja nie była uruchomiona.
Reactgular

Odpowiedzi:

55

Nie wiem, czy można zastosować dyrektywy na podstawie warunku, ale obejściem byłoby posiadanie 2 przycisków i wyświetlanie ich na podstawie warunku .

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

Edycja: może to będzie pomocne.

LLL
źródło
13
Dziękuję za odpowiedź. Ale użyłem już tej techniki w przykładzie plunkera, który szczegółowo dodałem. To dobra opcja, ale nie jest to dobry pomysł, jeśli kod jest złożony. Ponieważ ta technika rujnuje koncepcję ponownego użycia. Możesz zobaczyć mój przykład w plunkerze i zauważyć, jak mój kod jest duplikowany z powodu tego podejścia. Dlatego nie chcę używać tej techniki. Chcę lepszego rozwiązania, aby móc generować elementy dynamiczne za pomocą.
user2899728
1
Widzę. Możesz opakować kod, który jest zduplikowany w komponencie.
LLL
3
To dobry pomysł, ale niestety nie działa w przypadku form reaktywnych. W przypadku formularzy reaktywnych pojawia się inny problem. Gdybym wstawił dane wejściowe do oddzielnego komponentu, angular wymagałby dodania [formGroup] = "form" również w tym komponencie potomnym. Ale jeśli to zrobię, moje powiązanie tablicy nie zadziała.
user2899728
15
To straszne rozwiązanie, ponieważ duplikuje kod. Wyobraź sobie, że to nie tylko przycisk, ale element div z dużą ilością kodu HTML w środku.
Shachar Har-Shuv
Nie jest konieczne dołączanie formGroupdo komponentu podrzędnego, który zawija się, inputponieważ możesz po prostu przekazać go formControljako @Input() control: FormControlkomponent wewnątrz opakowania i zastosować go do natywnego inputza pośrednictwem[formControl]="control"
Oleg Kuibar
88

Jeśli potrzebujesz tylko dodać atrybut, aby wywołać reguły CSS, możesz użyć poniższej metody: (nie powoduje to dynamicznego tworzenia / niszczenia dyrektywy)

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

Zastosowałem to samo do twojego plunkera: widelec

Aktualizacja:

Jak condition ? '' : nulldziała jako wartość:

Kiedy jest pustym ciągiem ( ''), staje się attr.md-raised-button="", gdy jego nullatrybut nie będzie istniał.

Aktualizacja: aktualizacja plunkera: widelec (naprawiono problemy z wersją, proszę zauważyć, że pierwotnie pytanie było oparte na angular 4)

Aldracor
źródło
@Luke Tak, jeśli masz na myśli „(teraz)” jako: od 06.01.2017, czyli 5 miesięcy przed zadaniem pytania. patrz
dziennik
@Aldracor angular 5.2.1, nie działa. I nie rozumiem nawet, dlaczego powinno to wyglądać jak „warunek?”: Null ”, gdzie oba wyniki są w zasadzie fałszywe. Co powinno być zamiast „”? „prawda” też nie działa.
Arsenii Fomin
1
więc dla każdego, kto nie chce tworzyć elementu html, aby jego dyrektywa działała i używa ng-container, po prostu przekazałem [enabled] = "booleanVar"
Ben Taliadoros
7
Nie działa dla mnie w Angular 6. Próbka plunkera nie przechodzi przez ekran ładowania. Opierając się na moich odczytach, to podejście może działać w przypadku atrybutów HTML, ale nie będzie działać w przypadku dyrektyw Angular. Pierwotne pytanie dotyczyło dyrektyw Angular z biblioteki materiałów ng.
JeffryHouser
6
@kbpontius dzięki za komentarz, działa na atrybutach HTML, ale nie na dyrektywach kątowych (jako atrybut)
Reza
19

Jak już wspomniano, nie wydaje się to możliwe. Jedną z rzeczy, które można wykorzystać, aby przynajmniej zapobiec jakimś duplikacjom, jest ng-template. Pozwala to na wyodrębnienie zawartości elementu, na który ma wpływ ngIfrozgałęzienie.

Jeśli na przykład chcesz utworzyć hierarchiczny komponent menu przy użyciu materiału kątowego:

<!-- 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>

Tutaj jest stosowana warunkowo dyrektywa matMenuTriggerFor, która powinna być stosowana tylko do pozycji menu z dziećmi. Zawartość przycisku jest wstawiana w obu miejscach za pomocą ngTemplateOutlet.

HB
źródło
6
Jest to jedyna odpowiedź, która pozwala programiście używać dyrektyw warunkowych, a także możliwości ponownego wykorzystania kodu.
Ravinder Payal
16

Może to nastąpić późno, ale jest to realna i elegancka metoda warunkowego stosowania dyrektywy.

W klasie dyrektywy utwórz zmienną wejściową:

@Input('myDirective') options: any;

Stosując dyrektywę, ustaw właściwość apply zmiennej wejściowej:

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

W metodzie dyrektywy sprawdź zmienną this.options.apply i zastosuj logikę dyrektywy na podstawie warunku:

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

    // directive logic
}
Tiha
źródło
3
Dla mnie to nie działa, ponieważ dyrektywa nadal istnieje w komponencie, po prostu nie wykonuje żadnej logiki. Chciałbym, aby istnienie dyrektywy obowiązywało warunkowo, szczególnie dlatego, że istnieje CSS, który sprawdza tę dyrektywę.
Biegał z Lottem
Masz inny problem niż ten wymieniony tutaj (zastosuj dyrektywę warunkowo). Opublikuj swój problem, a ludzie ci pomogą. Pierwszym pomysłem byłoby umieszczenie dyrektywy w elemencie div i umieszczenie wokół niego kontenera ng z * ngIf, aby zastosować warunek. ng Jeśli usuwa węzeł DIV z DOM, więc może działać. Zgaduję, że musisz opublikować swój problem z przykładami kodu / opisem dla ppl, aby ci pomóc.
Tiha
To nie jest dobre rozwiązanie. Dyrektywa wciąż jest inicjowana.
Dino
8

Jak stwierdzili inni, directivesnie można go stosować dynamicznie.

Jeśli jednak chcesz po prostu zmienić md-buttonstyl z płaskiego na podniesiony , to

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

załatwi sprawę. Plunker

Ankit Singh
źródło
3

To też może być rozwiązanie:

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


Działa dla Angular 4, ionic 3 w ten sposób:

[color]="condition ? 'primary' : ''"gdzie conditionjest funkcją, która decyduje, czy jest to aktywna strona, czy nie. Cały kod wygląda następująco:

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

zalogowany
źródło
2

Obecnie istnieje NOsposób na warunkowe zastosowanie dyrektywy do komponentu, ale nie jest to obsługiwane. Utworzone komponenty można warunkowo dodawać lub usuwać.

Jest już utworzony problem dla tego samego z angular2, więc powinno być również w przypadku angular4.

Alternatywnie możesz wybrać opcję z ng-if

<button ngIf="!condition"></button>
<button ngIf="condition" md-raised-button></button> 
Sajeetharan
źródło
1
już uwzględnione w odpowiedzi LLL
Sumit Ramteke
2

Nie mogłem znaleźć fajnego istniejącego rozwiązania, więc zbudowałem własną dyrektywę, która to robi.

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);
  }
}

Następnie Twój html:

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

Cappi10
źródło
Możesz użyć po prostu @HostBinding('attr.dynamic-attr') @Input('dynamic-attr') attr: string;zamiast ngOnInit + ElementRef.
pinguinjkeke
2
To nie jest odpowiedź na pytanie, jak dynamicznie dodać dyrektywę , a nie atrybut.
Chris Haines
2

Może to komuś pomoże.

W poniższym przykładzie mam my-button.component.htmli chcę zastosować *appHasPermissiondyrektywę <button>tylko wtedy, gdy roleatrybut jest ustawiony.

<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>

W ten sposób nie duplikujesz <button>kodu.

MhagnumDw
źródło
0

tak to mozliwe.

strona html z dyrektywą 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>

dyrektywa

@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');
    }
  }

}
Chaitanya Nekkalapudi
źródło
2
Na marginesie, Renderer jest przestarzały, zamiast tego użyj Renderer2: alligator.io/angular/using-renderer2
tam.teixeira
0

Przejście nulldo dyrektywy usuwa ją!

<button md-raised-button="condition ? true : null"></button>
Yogesh Aggarwal
źródło
-1

Posługiwać się NgClass

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

przykład prawdziwego stanu:

this.element === 'Today'

lub funkcja boolowska

getTruth()

pełny przykład:

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

Jeśli chcesz mieć klasę domyślną:

  <button [ngClass]="{ 'mat-raised-button': trueCondition, 'default-class': !trueCondition }">TEXT</button>
Mosze
źródło
6
Nie o to prosiłem. Pokazujesz przykład dla klasy. Mówię o dyrektywie atrybutów.
user2899728
@ user2899728 Niestety nie ma innego sposobu, aby to zrobić. (Nie możesz ustawić md-raised-buttonatrybutu jako fałsz)
Edric
@ user2899728 Nie ma możliwości warunkowego zastosowania dyrektyw. Próbowałem dać Ci to, czego szukałeś (wynik końcowy), stosując inne podejście („środki”).
Moshe
Kiedy oferujesz kreatywną alternatywę, zwykle pomocne jest umieszczenie najpierw linii komentarzy, aby opisać, dokąd zmierzasz z odpowiedzią.
bvdb
1
@bvdb dziękuję za miłe słowa. Pisałem bez kierunku i to był błąd. Mam nadzieję, że w przyszłości zredaguję ten post, ponieważ mógłby pomóc nawet jednej osobie.
Moshe
-1

Mam inny pomysł na to, co możesz zrobić.

Możesz zapisać kod HTML, który chcesz zastąpić, w zmiennej jako ciąg, a następnie dodać / usunąć z niego dyrektywę, jak chcesz, używając bypassSecurityTrustHtmlmetody DomSanitizer .

Nie daje to czystego rozwiązania, ale przynajmniej nie musisz powtarzać kodu.

LLL
źródło
-3

Na dzień 18 stycznia 2019 r. W ten sposób warunkowo dodałem dyrektywę w Angular 5 i nowszych. Musiałem zmienić kolor <app-nav>komponentu na podstawie darkMode. Czy strona była w trybie ciemnym, czy nie.

To zadziałało dla mnie:

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

Mam nadzieję, że to komuś pomoże.

EDYTOWAĆ

Spowoduje to zmianę wartości atrybutu (koloru) na podstawie warunku. Po prostu zdarza się, że kolor jest definiowany za pomocą dyrektywy. Więc każdy, kto to czyta, nie daj się zmylić, to nie jest warunkowe stosowanie dyrektywy (tj. Co oznacza dodanie lub usunięcie dyrektywy do domeny na podstawie warunku)

Sandra Israel
źródło
3
Dyrektywę stosuje się w obu przypadkach tylko z różnymi opcjami (np. Pomarańczową lub zieloną). Pytanie dotyczy całkowitego zignorowania dyrektywy w oparciu o warunek.
Mojtaba,