9

The following directive should hide an element.

import {Directive, ElementRef, Input, Renderer2} from '@angular/core';
import {el} from "@angular/platform-browser/testing/src/browser_util";

// Directive decorator
@Directive({ selector: '[hide-me]' })
// Directive class
export class MyHiddenDirective {
//  @Input() hideme:boolean;
  constructor(public el: ElementRef, public  renderer: Renderer2) {
    // Use renderer to render the element with styles
        renderer.setStyle(el.nativeElement, 'display', 'none');

  }
}

I am using it as follows:

<div>Name: <input hide-me #myint  type="text" name="name" [(ngModel)]="this.name" />  You entered {{this.name}} {{myint.hasAttribute('required')}}</div>

Why does selector: '[hide-me]' work but selector: 'hide-me' doesn't? I do not use square brackes when I use the Directive <input hide-me... and not <input [hide-me].... In Components, we generally specify selector without square brackets. Why do I need to specify square brackets in Directives?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Manu Chadha
  • 15,555
  • 19
  • 91
  • 184

1 Answers1

18

Because the selector is a CSS selector. The same kind of selector you use in a CSS file to specify which elements are concerned by a CSS rule:

  • foo means elements with name foo
  • [foo] means elements with an attribute named foo
  • .foo means elements with a CSS class named foo
  • foo[bar] means elements named foo with an attribute named bar, etc.

As a complement
The directive's selector can be used as an input which is especially useful when that input carries something other than a boolean (as the directive instance suffices to tell it is active), use the @Input decorator's "bindingPropertyName" argument to use distinct tokens between the template attribute and the Directive class property:

@Directive({ selector: '[enhanced-me]' })
export class NodeEnhancementDirective {
  @Input('enhanced-me') options: {foo: true, bar: true} ;
}
Stphane
  • 3,368
  • 5
  • 32
  • 47
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks. regarding `foo[bar]`, my selector in directive is `[hide-me]` and I have an attribute in class `@Input() hideme:boolean`. But I am unable to use it as ` – Manu Chadha Jun 29 '17 at 08:32
  • Use `[hideme]` as selector, and `` – JB Nizet Jun 29 '17 at 10:54
  • got error = `Angular: Can't bind to 'hideme' since it isn't a known property of 'input'.` – Manu Chadha Jun 29 '17 at 11:11
  • You probably forgot to declare your directive. See http://plnkr.co/edit/O77pgTgWvb0eZBfif0h7?p=preview: it works fine. – JB Nizet Jun 29 '17 at 11:16
  • The declaration was already there. Things got working when I changed the selector from `[hide-me]` to `[hideme]`. This seems strange! – Manu Chadha Jun 29 '17 at 11:22
  • So, things started working when doing what I precisely told you to do: *Use [hideme] as selector*. Why do you expect [hideme]="true" to select your directive if its selector is [hide-me]? – JB Nizet Jun 29 '17 at 11:23
  • my bad, didn't read that one properly. But things didn't work when my selector was `[hide-me]` and the property was `hideme`. If my selector is `S` and I have properties `P1` and `P2`, how to do assign values to these properties? – Manu Chadha Jun 29 '17 at 11:52
  • `
    `. P1 and P2 mustbe inputs, not just properties.
    – JB Nizet Jun 29 '17 at 12:48
  • ah! found the issue. I didn't keep a space earlier. `hide-me [hideme]` works, `hide-me[hideme]` doesn't. you might want to change your answer above and add space between foo and [bar] – Manu Chadha Jun 29 '17 at 12:54
  • For anyone that may get wrong directions here: the error wasn't because of the space between elements. It was just because of the wrong use of the directive trigger itself. If the directive was declared with the selector "[hide-me]", the element where it will be triggered MUST HAVE an ATTRIBUTE "hide-me". Following your last comment, @ManuChadha: you didn't needed the "[hideme]" sentence at all, because all the work was done by the "hide-me" one. – Luan Feb 15 '18 at 16:53