Appliquer une directive sous condition

110

J'utilise le matériau 2 pour ajouter md-raised-button. Je ne veux appliquer cette directive que si certaines conditions deviennent vraies.

Par exemple:

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

Autre exemple: j'ai créé une forme réactive dynamique de base dans plunker. J'utilise une formArrayNamedirective de forme réactive pour un tableau de contrôles. Je veux appliquer la formArrayNamedirective uniquement si une condition spécifique devient vraie, sinon n'ajoutez pas de formArrayNamedirective.

Voici un lien de plunker .

user2899728
la source
Oui md-raise-button c'est une directive d'attribut ( material.angular.io/components/component/button )
user2899728
L'application de conditions sur lesquelles les directives sont utilisées rendrait probablement AoT inutile car vous ne pourrez pas compiler les modèles à moins que l'application ne soit en cours d'exécution.
Reactgular

Réponses:

55

Je ne sais pas si vous pouvez appliquer des directives basées sur une condition, mais une solution de contournement consisterait à avoir 2 boutons et à les afficher en fonction d'une condition .

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

Edit: peut - être que ce sera utile.

JE VAIS
la source
13
Merci pour votre réponse. Mais j'ai déjà utilisé cette technique dans l'exemple de plunker que j'ai ajouté en détail de la question. C'est une bonne option mais pas une bonne idée si le code est complexe. Parce que parce que cette technique ruine le concept de réutilisation. Vous pouvez voir mon exemple dans plunker et remarquer comment mon code est dupliqué à cause de cette approche. C'est pourquoi je ne veux pas utiliser cette technique. Je veux une meilleure solution afin de pouvoir générer des éléments dynamiques avec.
user2899728
1
Je vois. Vous pouvez envelopper le code dupliqué dans le composant.
LLL
3
C'est une bonne idée mais malheureusement cela ne fonctionne pas dans le cas des formes réactives. Avec les formulaires réactifs, un autre problème apparaît. Si je mets une entrée dans un composant séparé, alors angular me demanderait d'ajouter [formGroup] = "form" dans ce composant enfant également. Mais si je le fais, ma liaison de tableau ne fonctionnerait pas.
user2899728
15
C'est une solution terriblement car c'est du code en double. Imaginez que ce n'est pas seulement un bouton mais un div avec beaucoup de code html à l'intérieur.
Shachar Har-Shuv
87

Si vous avez juste besoin d'ajouter un attribut pour déclencher des règles CSS, vous pouvez utiliser la méthode ci-dessous: (cela ne crée / détruit pas dynamiquement une directive)

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

Appliqué la même chose à votre plunker: fourchette

Mettre à jour:

Comment condition ? '' : nullfonctionne comme valeur:

Quand c'est la chaîne vide ( '') il devient attr.md-raised-button="", quand c'est nulll'attribut n'existera pas.

Mise à jour: mise à jour plunker: fork (problèmes de version corrigés, veuillez noter que la question était à l'origine basée sur angular 4)

Aldracor
la source
@Luke Oui, si vous entendez par "(maintenant)" comme: depuis le 06/01/2017, soit 5 mois avant que la question ne soit posée. voir le
journal des modifications
@Aldracor angular 5.2.1, ne fonctionne pas. Et je ne comprends pas pourquoi cela devrait ressembler à "condition? '': Null" où les deux résultats sont fondamentalement faux. Que devrait être au lieu de ''? «vrai» ne fonctionne pas non plus.
Arsenii Fomin
1
donc pour tous ceux qui ne veulent pas créer un élément html pour que leur directive fonctionne et qui utilisent ng-container, je suis juste allé en passant un [enabled] = "booleanVar"
Ben Taliadoros
7
Ne fonctionne pas pour moi dans Angular 6. L'échantillon plunker ne dépasse pas l'écran de chargement. D'après ma lecture, cette approche peut fonctionner pour les attributs HTML, mais ne fonctionnera pas pour les directives angulaires. La question initiale concernait les directives angulaires de la bibliothèque de matériaux ng.
JeffryHouser
6
@kbpontius merci pour le commentaire, cela fonctionne sur les attributs Html mais pas sur les directives angulaires (comme attribut)
Reza
19

Comme indiqué précédemment, cela ne semble pas possible. Une chose qui peut être utilisée pour au moins éviter une certaine duplication est ng-template. Cela vous permet d'extraire le contenu de l'élément affecté par le ngIfbranchement.

Si vous souhaitez par exemple créer un composant de menu hiérarchique à l'aide d'un matériau angulaire:

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

Ici, la directive appliquée conditionnellement est matMenuTriggerFor, qui ne doit être appliquée qu'aux éléments de menu avec enfants. Le contenu du bouton est inséré aux deux endroits via ngTemplateOutlet.

HB
la source
6
C'est la seule réponse qui permet à un développeur d'utiliser des directives conditionnelles ainsi que la réutilisation du code.
Ravinder Payal
16

Cela peut arriver tardivement, mais c'est une méthode viable et élégante pour appliquer une directive sous condition.

Dans la classe directive, créez la variable d'entrée:

@Input('myDirective') options: any;

Lors de l'application de la directive, définissez la propriété apply de la variable d'entrée:

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

Dans la méthode de la directive, vérifiez la variable this.options.apply et appliquez la logique directive basée sur la condition:

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

    // directive logic
}
Tiha
la source
3
Cela ne fonctionne pas pour moi, car la directive existe toujours dans le composant, elle n'effectue simplement aucune logique. Je voudrais que l’existence de la directive s’applique de manière conditionnelle, en particulier parce qu’il existe des CSS qui vérifient cette directive.
Ran Lottem
Vous rencontrez un problème différent de celui répertorié ici (appliquer la directive sous condition). Postez votre problème et les gens vous aideront. Comme première idée, vous pourriez mettre la directive sur un div et mettre un ng-container avec un * ngIf autour de lui pour appliquer votre condition. ngIf supprime le nœud div du DOM, donc cela pourrait fonctionner. Je ne fais que deviner, vous devez poster votre problème avec des exemples de code / description pour que ppl vous aide.
Tiha
Ce n'est pas une bonne solution. La directive est toujours initialisée.
Dino
8

Comme d'autres l'ont également indiqué, directivesne peut pas être appliqué dynamiquement.

Cependant, si vous voulez simplement faire basculer md-buttonle style de plat à surélevé , alors ce

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

ferait l'affaire. Plunker

Ankit Singh
la source
3

Cela pourrait aussi être une solution:

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


Cela fonctionne pour angulaire 4, ionique 3 comme ceci:

[color]="condition ? 'primary' : ''"conditionest une fonction qui décide s'il s'agit d'une page active ou non. L'ensemble du code ressemble à ceci:

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

zalog
la source
2

Actuellement, il existe un NOmoyen d'appliquer conditionnellement une directive à un composant.Cela n'est pas pris en charge.Les composants que vous avez créés peuvent être ajoutés ou supprimés de manière conditionnelle.

Il y a déjà un problème créé pour le même avec angular2, donc cela devrait être le cas avec angular4 également.

Vous pouvez également opter pour l'option avec ng-if

<button ngIf="!condition"></button>
<button ngIf="condition" md-raised-button></button> 
Sajeetharan
la source
1
déjà couvert dans la réponse de LLL
Sumit Ramteke
2

Je n'ai pas pu trouver une bonne solution existante, alors j'ai construit ma propre directive qui fait cela.

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

Puis votre html:

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

Cappi10
la source
Vous pouvez utiliser simplement a @HostBinding('attr.dynamic-attr') @Input('dynamic-attr') attr: string;au lieu de ngOnInit + ElementRef.
pinguinjkeke
2
Ce n'est pas une réponse à la question qui était de savoir comment ajouter une directive dynamiquement, pas un attribut.
Chris Haines
2

Peut-être que cela aidera quelqu'un.

Dans l'exemple ci-dessous, j'ai le my-button.component.htmlet je veux appliquer la *appHasPermissiondirective au <button>uniquement si l' roleattribut est défini.

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

De cette façon, vous ne dupliquez pas le <button>code.

MhagnumDw
la source
0

Oui c'est possible.

page html avec la directive 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>

directif

@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
la source
2
En remarque, le Renderer est obsolète, utilisez plutôt Renderer2: alligator.io/angular/using-renderer2
tam.teixeira
0

Passer nullà la directive le supprime!

<button md-raised-button="condition ? true : null"></button>
Yogesh Aggarwal
la source
-1

Utilisation NgClass

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

exemple de condition vraie:

this.element === 'Today'

ou une fonction booléenne

getTruth()

exemple complet:

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

Si vous voulez une classe par défaut:

  <button [ngClass]="{ 'mat-raised-button': trueCondition, 'default-class': !trueCondition }">TEXT</button>
Moshe
la source
6
Ce n'est pas ce que j'ai demandé. Vous montrez un exemple pour la classe. Je parle d'attribut-directive.
user2899728
@ user2899728 Malheureusement, il n'y a pas d'autre moyen de le faire. (Vous ne pouvez pas définir l' md-raised-buttonattribut comme faux)
Edric
@ user2899728 Il n'existe aucun moyen d'appliquer des directives de manière conditionnelle. J'ai essayé de vous donner ce que vous recherchiez (résultat final) avec une approche différente (les «moyens»).
Moshe
Lorsque vous proposez une alternative créative, il est généralement utile de mettre d'abord une ligne de commentaires pour décrire où vous allez avec votre réponse.
bvdb
1
@bvdb merci pour vos aimables paroles. J'écrivais sans direction, et c'était une erreur. À l'avenir, j'espère éditer ce message, car cela pourrait aider même une personne.
Moshe
-1

J'ai une autre idée de ce que vous pourriez faire.

Vous pouvez stocker le html que vous souhaitez remplacer dans une variable sous forme de chaîne, puis y ajouter / supprimer la directive comme vous le souhaitez, en utilisant la bypassSecurityTrustHtmlméthode du DomSanitizer .

Je n'ai pas pour résultat une solution propre mais au moins vous n'avez pas besoin de répéter le code.

JE VAIS
la source
-3

Au 18 janvier 2019, c'est ainsi que j'ai ajouté une directive conditionnelle dans Angular 5 et au-dessus. J'avais besoin de changer la couleur du <app-nav>composant en fonction dedarkMode . Si la page était en mode sombre ou non.

Cela a fonctionné pour moi:

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

J'espère que ça aidera quelqu'un.

ÉDITER

Cela modifie la valeur d'un attribut (couleur) en fonction d'une condition. Il arrive juste que la couleur soit définie à l'aide d'une directive. Donc, si vous lisez ceci, ne soyez pas confus, il ne s'agit pas d'appliquer une directive de manière conditionnelle (c'est-à-dire d'ajouter ou de supprimer une directive au dom en fonction d'une condition)

Sandra Israël
la source
3
Vous appliquez la directive dans les deux cas uniquement avec des options différentes (c'est-à-dire orange ou vert). La question demande d'ignorer du tout la directive sur la base d'une condition.
Mojtaba