Aplicar uma diretiva condicionalmente


109

Estou usando o Material 2 para adicionar md-raised-button. Desejo aplicar esta diretiva apenas se certa condição se tornar verdadeira.

Por exemplo:

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

Outro exemplo: criei uma forma reativa dinâmica básica no plunker. Estou usando uma formArrayNamediretiva de forma reativa para uma série de controles. Quero aplicar a formArrayNamediretiva apenas se uma condição específica se tornar verdadeira, caso contrário, não adicione a formArrayNamediretiva.

Aqui está um link de êmbolo .


Sim, o botão em relevo md é uma diretiva de atributo ( material.angular.io/components/component/button )
— user2899728

Aplicar as condições nas quais as diretivas são usadas provavelmente tornaria o AoT inútil, pois você não seria capaz de compilar os modelos a menos que o aplicativo estivesse em execução.
— Reagular de

Respostas:


54

Não sei se você pode aplicar diretivas com base em uma condição, mas uma solução alternativa seria ter 2 botões e exibi-los com base em uma condição .

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

Editar: talvez isso seja útil.


13
Obrigado pela sua resposta. Mas já usei essa técnica no exemplo do êmbolo que adicionei nos detalhes da pergunta. Esta é uma boa opção, mas não é uma boa ideia se o código for complexo. Pois porque essa técnica estraga o conceito de reaproveitamento. Você pode ver meu exemplo no plunker e perceber como meu código é duplicado por causa dessa abordagem. É por isso que não quero usar essa técnica. Eu quero alguma solução melhor para que possa gerar elementos dinâmicos com.
— user2899728

1
Entendo. Você pode envolver o código que está duplicado no componente.
— LLL de

3
É uma boa ideia, mas infelizmente não funciona no caso de formas reativas. Com as formas reativas, outro problema aparece. Se eu colocar a entrada em um componente separado, o angular exigirá que eu adicione [formGroup] = "formulário" dentro desse componente filho também. Mas se eu fizer isso, minha associação de array não funcionará.
— user2899728

15
Essa é uma solução terrível, pois é código duplicado. Imagine que não é apenas um botão, mas um div com muito código html dentro dele.
— Shachar Har-Shuv

87

Se você só precisa adicionar um atributo para acionar as regras CSS, pode usar o método a seguir: (isso não cria / destrói dinamicamente uma diretiva)

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

Aplicado o mesmo ao seu êmbolo: garfo

Atualizar:

Como condition ? '' : nullfunciona como o valor:

Quando é a string vazia ( ''), torna-se attr.md-raised-button="", quando é nullo atributo não existirá.

Atualização: atualização do plunker: fork (problemas de versão corrigidos, observe que a questão foi originalmente baseada no angular 4)


@Luke Sim, se você quer dizer "(agora)" como: desde 06/01/2017, que foi 5 meses antes da pergunta ser feita. ver item 6 do changelog angular
— Aldracor

@Aldracor angular 5.2.1, não funciona. E eu nem mesmo entendo por que deveria ser parecido com "condição? '': Null" onde ambos os resultados são basicamente falsos. O que deve ser em vez de ''? 'true' também não funciona.
— Arsenii Fomin

1
então, para quem não deseja criar um elemento html para que sua diretiva funcione e está usando o ng-container, apenas passei um [enabled] = "booleanVar"
— Ben Taliadoros

7
Não funciona para mim no Angular 6. A amostra do êmbolo não passa da tela de carregamento. Com base na minha leitura, essa abordagem pode funcionar para atributos HTML, mas não funcionará para diretivas Angular. A pergunta original era sobre as diretivas angulares da biblioteca de materiais ng.
— JeffryHouser

6
@kbpontius obrigado pelo comentário, funciona com atributos Html, mas não com diretivas angulares (como atributo)
— Reza

19

Como já foi observado, isso não parece ser possível. Uma coisa que pode ser usada para evitar pelo menos alguma duplicação é ng-template. Isso permite que você extraia o conteúdo do elemento afetado pela ngIframificação.

Se você, por exemplo, deseja criar um componente de menu hierárquico usando 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>

Aqui, a diretiva aplicada condicionalmente é matMenuTriggerFor, que só deve ser aplicada a itens de menu com filhos. O conteúdo do botão é inserido em ambos os lugares via ngTemplateOutlet.


6
Esta é a única resposta que permite ao desenvolvedor usar diretivas condicionais, bem como reutilização de código.
— Ravinder Payal

16

Isso pode chegar tarde, mas é um método viável e elegante para aplicar uma diretiva condicionalmente.

Na classe de diretiva, crie a variável de entrada:

@Input('myDirective') options: any;

Ao aplicar a diretiva, defina a propriedade apply da variável de entrada:

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

No método da diretiva, verifique a variável this.options.apply e aplique a lógica da diretiva com base na condição:

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

    // directive logic
}

3
Isso não funciona para mim, como a diretiva ainda existe no componente, ela simplesmente não executa nenhuma lógica. Eu gostaria que a existência da diretiva fosse aplicada condicionalmente, especificamente porque há css que verifica essa diretiva.
— Ran Lottem

Você tem um problema diferente do listado aqui (aplique a diretiva condicionalmente). Publique o seu problema e as pessoas irão ajudá-lo. Como uma primeira idéia, você poderia colocar a diretiva em um div e colocar um ng-container com um * ngIf ao redor para aplicar sua condição. ngIf remove o nó div do DOM, então pode funcionar. Estou apenas supondo, você precisa postar seu problema com exemplos de código / descrição para ppl para ajudá-lo.
— Tiha

Esta não é uma boa solução. A diretiva ainda foi inicializada.
— Dino,

8

Como outros também afirmaram, directivesnão pode ser aplicado dinamicamente.

No entanto, se você quiser apenas alternar md-buttono estilo de plano para elevado , então

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

faria o truque. Plunker


3

Esta também pode ser uma solução:

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


Está funcionando para angular 4, iônico 3 assim:

[color]="condition ? 'primary' : ''"onde conditioné uma função que decide se esta é uma página ativa ou não. Todo o código se parece com isto:

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


2

Atualmente, existe uma NOmaneira de aplicar condicionalmente uma diretiva a um componente. Isso não é suportado. Os componentes que você criou podem ser adicionados ou removidos condicionalmente.

Já existe um problema criado para o mesmo com angular2, então deve ser o caso com angular4 também.

Alternativamente, você pode escolher a opção com ng-if

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

1
já abordado na resposta da LLL
— Sumit Ramteke

2

Não consegui encontrar uma boa solução existente, então criei minha própria diretiva que faz isso.

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

Então seu html:

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


Você pode usar apenas um em @HostBinding('attr.dynamic-attr') @Input('dynamic-attr') attr: string;vez de ngOnInit + ElementRef.
— pinguinjkeke

2
Esta não é uma resposta à questão de como adicionar uma diretiva dinamicamente, não um atributo.
— Chris Haines

2

Talvez ajude alguém.

No exemplo abaixo, tenho o my-button.component.htmle desejo aplicar a *appHasPermissiondiretiva ao <button>somente se o roleatributo estiver definido.

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

Dessa forma, você não duplica o <button>código.


0

Sim, é possível.

página html com diretiva 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>

diretriz

@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
Como uma observação lateral, o Renderer está obsoleto, em vez disso use Renderer2: alligator.io/angular/using-renderer2
— tam.teixeira

0

Passar nullpara a diretiva remove isso!

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

-1

Usar NgClass

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

exemplo de condição verdadeira:

this.element === 'Today'

ou uma função booleana

getTruth()

exemplo completo:

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

Se você quiser uma classe padrão:

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

6
Não foi isso que perguntei. Você está dando exemplo para a aula. Estou falando sobre diretiva de atributo.
— user2899728

@ user2899728 Infelizmente não há outra maneira de fazer isso. (Você não pode definir o md-raised-buttonatributo como falso)
— Edric

@ user2899728 Não há como aplicar diretivas condicionalmente. Tentei dar a você o que você estava procurando (resultado final) com uma abordagem diferente (os "meios").
— Moshe

Quando você oferece uma alternativa criativa, geralmente ajuda colocar uma linha de comentários primeiro para descrever aonde você quer chegar com sua resposta.
— bvdb

1
@bvdb obrigado por suas amáveis ​​palavras. Eu estava escrevendo sem direção e isso foi um erro. No futuro, espero editar este post, pois pode ajudar até mesmo uma pessoa.
— Moshe de

-1

Tive outra ideia sobre o que você poderia fazer.

Você pode armazenar o html que deseja substituir em uma variável como uma string e, em seguida, adicionar / remover a diretiva como desejar, usando o bypassSecurityTrustHtmlmétodo do DomSanitizer .

I não resulta em uma solução limpa, mas pelo menos você não precisa repetir o código.


-3

Em 18 de janeiro de 2019, foi assim que adicionei uma diretiva condicionalmente no Angular 5 e acima. Eu precisava mudar a cor do <app-nav>componente com base em darkMode. Se a página estava no modo escuro ou não.

Isso funcionou para mim:

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

Espero que isso ajude alguém.

EDITAR

Isso altera o valor de um atributo (cor) com base em uma condição. Acontece que a cor é definida por meio de uma diretiva. Portanto, quem estiver lendo isso, não se confunda, isso não é aplicar uma diretiva condicionalmente (ou seja, o que significa adicionar ou remover uma diretiva ao dom com base em uma condição)


3
Você aplica a diretiva em ambos os casos apenas com opções diferentes (ou seja, laranja ou verde). A questão pede para ignorar a diretiva em tudo com base em uma condição.
— Mojtaba,
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.