Jerry's Blog

Recording what I learned everyday

View on GitHub


20 June 2019

Angular (7) -- Directives

by Jerry Zhang

Day 16:

JavaScript setInterval

```javascript 1.8 onStart() { this.interval = setInterval(() => { this.timeNow = this.timeNow + 1; this.started.emit(this.timeNow); }, 1000); }


This anonymous function will be executed every one second. The `setInterval()` function is assigned to a reference 
`this.interval`. With this reference, later on, we can pause this interval using the code below.

```javascript 1.8
onPause() {
    clearInterval(this.interval);
}

Also notice that we used an ES6 syntax () => { }.

Create our own attribute directive

Create a new file called basic-highlight.directive.ts.

import {Directive, ElementRef, OnInit} from '@angular/core';

@Directive({
  selector: '[appBasicHighlight]'
})
export class BasicHighlightDirective implements OnInit{
  constructor(private elementRef: ElementRef) {
  }

  ngOnInit() {
    this.elementRef.nativeElement.style.backgroundColor = 'green';
  }
}

@Directive tells Angular this is a directive. The only mandatory attribute it needs is a selector, because this is the way we can use the new directive. Here, we defined it as [appBasicHighlight]. This must be unique.

Also remember that when we define a custom directive, we must notify Angular in the app.module.ts file by adding it to the declarations array.

import {BasicHighlightDirective} from './basic-highlight/basic-highlight.directive';
@NgModule({
  declarations: 
    BasicHighlightDirective
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Then we can use it in the html file.

<p appBasicHighlight>Style me with basic directive!</p>

A better way

import {Directive, ElementRef, OnInit, Renderer2} from '@angular/core';

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit(): void {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

}

If you want to listen to some events in the directive, you can use HostListener.

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {
  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit(): void {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseenter') mouseover(eventData: Event) {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseleave') mouseleave(eventData: Event) {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
  }

}

Or, we could simply use @HostBinding instead of the renderer.

export class BetterHighlightDirective implements OnInit {
  @HostBinding('style.backgroundColor') backgroundColor: string = 'transparent';

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit(): void {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseenter') mouseenter(eventData: Event) {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
    this.backgroundColor = 'blue';
  }

  @HostListener('mouseleave') mouseleave(eventData: Event) {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
    this.backgroundColor = 'transparent';
  }

}

Tip: mouseover, mouseenter, onmouseover

The mouseover event triggers when the mouse pointer enters the div element, and its child elements.

The mouseenter event is only triggered when the mouse pointer enters the div element.

The onmousemove event triggers every time the mouse pointer is moved over the div element.

Example

Binding to directive properties

Use custom property binding. Then, all the properties can be set dynamically at runtime.

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {
  @Input() defaultColor = 'transparent';
  @Input() highlightColor = 'blue';

  @HostBinding('style.backgroundColor') backgroundColor: string;

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit(): void {
    this.backgroundColor = this.defaultColor;
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseenter') mouseenter(eventData: Event) {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
    this.backgroundColor = this.highlightColor;
  }

  @HostListener('mouseleave') mouseleave(eventData: Event) {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
    this.backgroundColor = this.defaultColor;
  }

}

Change it from outside.

<p appBetterHighlight [defaultColor]="'yellow'" [highlightColor]="'red'">Style me with a better directive!</p>

Binding a main property for a directive

We can set an alias for a property in the directive, with the same name as its selector. Then, we put a square bracket around this directive, similar to [ngClass].

@Input('appBetterHighlight') highlightColor = 'blue';
<p [appBetterHighlight] = "'red'" [defaultColor]="'yellow'">Style me with a better directive!</p>

A shortcut when passing down a string

We can remove the quotation mark and the square brackets.

<p [appBetterHighlight] = "'red'" defaultColor="yellow">Style me with a better directive!</p>

Behind the star symbol of structural directives

Using

<ng-template [ngIf]="!onlyOdd">
          <div>
            <li
              class="list-group-item"
              [ngClass]="{odd: even % 2 !== 0}"
              *ngFor="let even of evenNumber">
              
            </li>
          </div>
        </ng-template>
tags: Angular