Applicare una direttiva in modo condizionale


109

Sto usando il materiale 2 per aggiungere md-raised-button. Voglio applicare questa direttiva solo se una certa condizione diventa vera.

Per esempio:

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

Un altro esempio: ho creato una forma reattiva dinamica di base in plunker. Sto usando la formArrayNamedirettiva di forma reattiva per la serie di controlli. Voglio applicare la formArrayNamedirettiva solo se una condizione specifica diventa vera, altrimenti non aggiungere la formArrayNamedirettiva.

Ecco un link plunker .


Sì md-raise-button è la direttiva sugli attributi ( material.angular.io/components/component/button )
user2899728

L'applicazione delle condizioni in base alle quali vengono utilizzate le direttive renderebbe probabilmente AoT inutile poiché non sarebbe possibile compilare i modelli a meno che l'app non fosse in esecuzione.
Reactgular

Risposte:


54

Non so se puoi applicare le direttive in base a una condizione, ma una soluzione alternativa sarebbe avere 2 pulsanti e visualizzarli in base a una condizione .

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

Modifica: forse questo sarà utile.


13
Grazie per la vostra risposta. Ma ho già usato questa tecnica nell'esempio del plunker che ho aggiunto nei dettagli della domanda. Questa è una buona opzione ma non è una buona idea se il codice è complesso. Perché perché questa tecnica rovina il concetto di riutilizzo. Puoi vedere il mio esempio in plunker e notare come il mio codice viene duplicato a causa di questo approccio. Ecco perché non voglio usare questa tecnica. Voglio una soluzione migliore in modo da poter generare elementi dinamici con.
user2899728

1
Vedo. Puoi racchiudere il codice duplicato in component.
LLL

3
È una buona idea ma sfortunatamente non funziona nel caso di forme reattive. Con le forme reattive, appare un altro problema. Se inserisco l'input in un componente separato, allora angular richiederebbe di aggiungere [formGroup] = "form" anche all'interno di quel componente figlio. Ma se lo faccio, il mio binding di array non funzionerebbe.
user2899728

15
Questa è una soluzione terribile poiché è un codice duplicato. Immagina che non sia solo un pulsante ma un div con molto codice html al suo interno.
Shachar Har-Shuv,

87

Se devi solo aggiungere un attributo per attivare le regole CSS, puoi utilizzare il metodo seguente: (questo non crea / distrugge dinamicamente una direttiva)

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

Applicato lo stesso al tuo plunker: fork

Aggiornare:

Come condition ? '' : nullfunziona come valore:

Quando è la stringa vuota ( '') diventa attr.md-raised-button="", quando è nulll'attributo non esisterà.

Aggiornamento: aggiornamento plunker: forcella (problemi di versione risolti, si prega di notare che la domanda era originariamente basata su angolare 4)


@Luke Sì, se intendi con "(ora)" : dal 06/01/2017, 5 mesi prima che la domanda fosse posta. vedi changelog angolare 6 ° elemento
Aldracor

@ Aldracor angolare 5.2.1, non funziona. E non capisco perché dovrebbe apparire come "condition?": Null "dove entrambi i risultati sono fondamentalmente falsi. Cosa dovrebbe essere invece di ""? Anche "vero" non funziona.
Arsenii Fomin

1
quindi per chiunque non voglia creare un elemento html per far funzionare la propria direttiva e stia utilizzando ng-container, sono andato semplicemente passando un [enabled] = "booleanVar"
Ben Taliadoros

7
Non funziona per me in Angular 6. Il campione del plunker non supera la schermata di caricamento. Sulla base della mia lettura, questo approccio potrebbe funzionare per gli attributi HTML, ma non funzionerà per le direttive Angular. La domanda originale riguardava le direttive angolari della libreria dei materiali ng.
JeffryHouser

6
@kbpontius grazie per il commento, funziona su attributi Html ma non su direttive angolari (come attributo)
Reza

19

Come già notato, ciò non sembra essere possibile. Una cosa che può essere utilizzata almeno per prevenire alcuni duplicati è ng-template. Ciò consente di estrarre il contenuto dell'elemento interessato dalla ngIframificazione.

Se ad esempio desideri creare un componente di menu gerarchico utilizzando Materiale angolare:

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

Qui la direttiva applicata in modo condizionale è matMenuTriggerFor, che dovrebbe essere applicata solo alle voci di menu con figli. Il contenuto del pulsante viene inserito in entrambe le posizioni tramite ngTemplateOutlet.


6
Questa è l'unica risposta che consente a uno sviluppatore di utilizzare le direttive condizionali e la riutilizzabilità del codice.
Ravinder Payal

16

Questo può arrivare in ritardo, ma è un metodo praticabile ed elegante per applicare una direttiva in modo condizionale.

Nella classe direttiva creare la variabile di input:

@Input('myDirective') options: any;

Quando si applica la direttiva, impostare la proprietà apply della variabile di input:

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

Nel metodo della direttiva verificare la variabile this.options.apply e applicare la logica della direttiva in base alla condizione:

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

    // directive logic
}

3
Questo non funziona per me, poiché la direttiva esiste ancora nel componente, semplicemente non esegue alcuna logica. Vorrei che l'esistenza della direttiva si applicasse in modo condizionale, in particolare perché c'è CSS che controlla questa direttiva.
Ran Lottem

Hai un problema diverso da quello elencato qui (applica la direttiva in modo condizionale). Pubblica il tuo problema e le persone ti aiuteranno. Come prima idea, potresti mettere la direttiva su un div e mettere un ng-container con un * ngIf intorno per applicare la tua condizione. ngIf rimuove il nodo div dal DOM, quindi potrebbe funzionare. Sto solo indovinando, devi inviare il tuo problema con esempi di codice / descrizione per ppl per aiutarti.
Tiha

Questa non è una buona soluzione. La direttiva viene ancora inizializzata.
Dino

8

Come altri hanno anche affermato, directivesnon può essere applicato dinamicamente.

Tuttavia, se vuoi solo cambiare lo md-buttonstile di da piatto a rialzato , allora questo

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

farebbe il trucco. Plunker


3

Anche questa potrebbe essere una soluzione:

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


Funziona per angolare 4, ionico 3 in questo modo:

[color]="condition ? 'primary' : ''"dove conditionè una funzione che decide se questa è una pagina attiva o meno. L'intero codice assomiglia a questo:

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


2

Attualmente esiste un NOmodo per applicare una direttiva a un componente in modo condizionale, ma non è supportato. I componenti che hai creato possono essere aggiunti o rimossi in modo condizionale.

C'è già un problema creato per lo stesso con angular2, quindi dovrebbe essere il caso anche con angular4.

In alternativa puoi scegliere l'opzione con ng-if

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

1
già coperto nella risposta di LLL
Sumit Ramteke

2

Non sono riuscito a trovare una bella soluzione esistente, quindi ho creato la mia direttiva che lo fa.

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

Quindi il tuo html:

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


Puoi usare solo un @HostBinding('attr.dynamic-attr') @Input('dynamic-attr') attr: string;invece di ngOnInit + ElementRef.
pinguinjkeke

2
Questa non è una risposta alla domanda su come aggiungere una direttiva dinamicamente, non un attributo.
Chris Haines,

2

Forse aiuterà qualcuno.

Nell'esempio seguente ho il my-button.component.htmle voglio applicare la *appHasPermissiondirettiva al <button>solo se l' roleattributo è impostato.

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

In questo modo non duplicherai il <button>codice.


0

sì, è possibile.

pagina html con direttiva 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>

direttiva

@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
Come nota a
margine

0

Passare nullalla direttiva lo rimuove!

<button md-raised-button="condition ? true : null"></button>

-1

Uso NgClass

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

esempio di vera condizione:

this.element === 'Today'

o una funzione booleana

getTruth()

esempio completo:

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

Se vuoi una classe predefinita:

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

6
Questo non è quello che ho chiesto. Stai mostrando un esempio per la lezione. Sto parlando della direttiva sugli attributi.
user2899728

@ user2899728 Sfortunatamente non c'è altro modo per farlo. (Non è possibile impostare l' md-raised-buttonattributo come falso)
Edric

@ user2899728 Non è possibile applicare le direttive in modo condizionale. Ho tentato di darti quello che stavi cercando (risultato finale) con un approccio diverso (i "mezzi").
Moshe

Quando offri un'alternativa creativa, di solito è utile inserire prima una riga di commenti per descrivere dove stai andando con la tua risposta.
bvdb

1
@ bvdb grazie per le tue gentili parole. Stavo scrivendo senza direzione ed è stato un errore. In futuro, spero di modificare questo post, in quanto potrebbe aiutare anche una sola persona.
Moshe

-1

Ho un'altra idea su cosa potresti fare.

È possibile memorizzare l'html che si desidera sostituire in una variabile come stringa e quindi aggiungere / rimuovere la direttiva come si desidera, utilizzando il bypassSecurityTrustHtmlmetodo di DomSanitizer .

Non risulta una soluzione pulita ma almeno non è necessario ripetere il codice.


-3

Al 18 gennaio 2019, è così che ho aggiunto una direttiva in modo condizionale in Angular 5 e versioni successive. Avevo bisogno di cambiare il colore del <app-nav>componente in base a darkMode. Se la pagina era in modalità oscura o meno.

Questo ha funzionato per me:

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

Spero che questo aiuti qualcuno.

MODIFICARE

Questo cambia il valore di un attributo (colore) in base a una condizione. Succede solo che il colore sia definito usando una direttiva. Quindi chiunque stia leggendo questo articolo per favore non confondersi, non si tratta di applicare una direttiva in modo condizionale (ad esempio, il che significa aggiungere o rimuovere una direttiva dal dominio in base a una condizione)


3
Si applica la direttiva in entrambi i casi solo con diverse opzioni (ad esempio, arancione o verde). La domanda chiede di ignorare del tutto la direttiva sulla base di una condizione.
Mojtaba
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.