Project - Groupbuy App Part III

prev

Angular Basics II - Decorator & Directive

1. Decorator(Annotation)

Annotation or Decorator is esssentially a function, which also returns a function. Next we will create a decorator step by step.

Practice 1: @Emoji

@Emoji can add a Laugh Emoji at both sides of the string.

@Emoji() result = 'Hello';

Codeing the decorator:

export function Emoji() {
  return (target: object, key: string) => {
    let val = target[key];
    const getter = () => {
      return val;
    }
    const setter = (value: string) => {
      val = `😂 ${value} 😂`
    }

    Object.defineProperty(target, key, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true
    })
  }
}

Through debugging we can see the target is the component, and the key is string result.

Practice 2: @Confirmable(‘…’)

We add it above handleClick(). When clicking the button, we want to pop up a window to warn our user. This decorator has param.

@Confirmable('Are you sure to do something?')
handleClick() {
  console.log('handle click works');
}

Codeing the decorator:

export function Confirmable(message: string) {
  return (target: object, key: string, descriptor: PropertyDescriptor) => {
    const original = descriptor.value;
    descriptor.value = function(...args: any) {
      const allow = window.confirm (message)
      if (allow) {
        const result = original.apply(args);
        return result;
      }
      return null;
    };
    return descriptor;
  }
}

2. Directive

There are two types of directives in Angular. They are,

  • structural directives: ngIf, ngFor, ngSwitch
  • attribute directives: ngClass, ngStyle, ngModel

Next, we will create some directives.

Create Directives:

Create a file gird-item.directive.ts, in this file use a shortcut ng-directive to gernerate a directive. Then a template can be generated as below.

import { Directive } from '@angular/core';

@Directive({
  selector: 'app-Name',
})
export class NameDirective { }

It has some mistakes. To let it work, we need to make some modifications.

  • use [] to surround the app-Name.
    import { Directive } from '@angular/core';
    
    @Directive({
      selector: '[appGridItem]',
    })
    export class GridItemDirective { }
  • add its decleration in shared.component.ts and also export it
    @NgModule({
      declarations: [
        ScrollableTabComponent,
        ImageSliderComponent,
        HorizontalGridComponent,
        GridItemDirective
      ],
      ...
      exports: [
        CommonModule,
        FormsModule,
        ScrollableTabComponent,
        ImageSliderComponent,
        HorizontalGridComponent,
        GridItemDirective
      ]
    })

Now let’s code this directive.

import { Directive } from '@angular/core';

@Directive({
selector: '[appGridItem]',
})
export class GridItemDirective {
  constructor (
    private elr: ElementRef,
    private rd2: Renderer2
  ) {
    this.rd2.setStyle(this.elr.nativeElement, 'display', 'grid');
    this.rd2.setStyle(this.elr.nativeElement, 'grid-template', `'image' 'title'`);
    this.rd2.setStyle(this.elr.nativeElement, 'place-itmes', 'center');
    this.rd2.setStyle(this.elr.nativeElement, 'width', '4rem');
  }
}

It’s not good to set styles in the constructor. We can do this job in ngOnInit(), so let directives implement OnInit and realize ngOnInit().

import { Directive } from '@angular/core';

@Directive({
selector: '[appGridItem]',
})
export class GridItemDirective {
  constructor (
    private elr: ElementRef,
    private rd2: Renderer2
  ) {}
  ngOnInit() {
    this.rd2.setStyle(this.elr.nativeElement, 'display', 'grid');
    this.rd2.setStyle(this.elr.nativeElement, 'grid-template-areas', `'image' 'title'`);
    this.rd2.setStyle(this.elr.nativeElement, 'place-items', 'center');
    this.rd2.setStyle(this.elr.nativeElement, 'width', '4rem');
  }
}

Then create GridItemImageDirective and GridItemTitleDirective following same procedures.

Use Created Directives:

Directives are like properties. Now we can use these directives in the template of HorizontalGridComponent.

<div appGridItem *ngFor="let item of channels">
  <img [src]="item.imgUrl" alt="" appGridItemImage>
  <span appGridItemTitle></span>
</div>

We need to defind channels in horizontal-grid.component.ts. First define interface Channel, then define the Channel[].

export interface Channel {
  id: number;
  icon: string;
  title: string;
  link: string;
}

In summary:

  • Components like tags in HTML.
  • Directives like properties, which can be applied to HTML tags.

3. Style / Event Binding in Directive

Since there is no template in directive. Directive needs a host(an element). In Angular, @HostBinding can be used to bind attributes and styles to host, @HostListener can be used to bind evnets to host.

@HostBinding

Previously, we use rd2 to set styles of host, now we can use @HostBinding to realize the same function.

export class GridItemDirective { 
  @HostBinding('style.display') display = 'grid';
  @HostBinding('style.grid-template-areas') template = `'image' 'title'`;
  @HostBinding('style.place-items') align = 'center';
  @HostBinding('style.width') width = '4rem';
}

@HostListener

It accepts two params, one is event name, another is event data.

@HostListener('click', ['$event.target'])
handleClick(ev) {
  console.log(ev);
}

We don’t need to add additional event binding in template like we previously did. The code in template is,

<div appGridItem *ngFor="let item of channels">
  <img [src]="item.icon" alt="" 
       [appGridItemImage]="'4rem'" 
       [fitMode]="'cover'">
  <span appGridItemTitle="0.6rem" class="title"></span>
</div>

Host Concept in Component

:host is used to design component styles in .component.css. It is a pseudo-classes selector. For example,

:host {
    display: flex;
    justify-content: center;
}

The pattern defined by :host is applied to the component itself.

next

   Reprint policy


《Project - Groupbuy App Part III》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
 Previous
Clumsy Factorial Clumsy Factorial
LeetCode Q 1006 - Clumsy FactorialNormally, the factorial of a positive integer n is the product of all positive intege
2019-06-26 Tong Shi
Next 
Proxy Design Pattern Proxy Design Pattern
1. What is proxy?Definition in Wikipedia is: A proxy is a class functioning as an interface to something else. The prox
2019-06-25 Tong Shi
  TOC