Project - Groupbuy App Part I

Project Introduction

This project is about designing a groupbuy app. The frontend is built based on Angular. In project todoList, we have already utilize Angular to build the frontend. In this prjoct we will go deeper in Angular and build a more fantasitic frontend.

Angular Components

1. Tab Bar

Prerequisite: Interface in TypeScript

In Java, interface is a blueprint of a class. It is used to achieve abstraction and multiple inheritance.
In TypeScript, it has another important function. That is it can be used to do typeAliase. Different with Java, in TypeScript the Interface can also have variable fields. So this enables typeAliase function for complex objects. For example,

interface Person {
  firstName: number,
  lastName: string,
  kids: number
}

var p: Person = {
  firstName: 'Garen',
  lastName: 'Demacia',
  kids: 0
}

TypeScript also supports the read-only and optional fields. E.g.g

kids?: number // optional
readonly kids: number // read-only

The Interface in TypeScript also can be used to define function. It uses syntax in ES6.

interface AddFunc {
  (x: number, y: number): number;
}

add: AddFunc = (x, y) => {
  return x + y;
}

The Interface in TypeScript supports indexing. E.g.

interface Dict {
  [a: string]: string;
}

dict: Dict = {
  a: '1',
  b: '2',
}

constructor () {
  console.log(this.dict['a']); // we can get 1 in the console Or we can write it as
  console.log(this.dict.a);
}

Tab Bar

CLICK TO SEE THE CODES
<ul>
  <li *ngFor="let menu of menus">
    <a href="#">  </a>
  </li>
</ul>
interface TopMenu {
  title: string,
  readonly link?: string
}

export class AppComponent {
  title = 'groupbuy';
  menus: TopMenu[] = [
    { title: 'HOT', link: '' },
    { title: 'WEAPON', link: '' },
    { title: 'Damage', link: '' },
    { title: 'Critical Strike', link: '' },
    { title: 'Attack Speed', link: '' },
    { title: 'Lift Steal', link: '' },
    { title: 'DEFENSE', link: '' },
    { title: 'Health', link: '' },
    { title: 'Magic Resist', link: '' },
    { title: 'Health Regen', link: '' },
    { title: 'Armor', link: '' },
    { title: 'MAGIC', link: '' },
    { title: 'Ability Power', link: '' },
    { title: 'Cooldown Reduction', link: '' },
    { title: 'Mana', link: '' },
    { title: 'Mana Regen', link: '' },
    { title: 'MISC', link: '' },
    { title: 'Movement', link: '' },
    { title: 'Consumables', link: '' }
  ]
}
ul {
  padding: 0;
  margin: 0;
  display: flex;
}

ul li {
  display: inline-block;
  margin: 0 5px;
  white-space: nowrap;
}

a {
  text-decoration: none
}

2. *ngFor

  • Syntax: let menu of menus
  • Get Index: let menu of menus; let i = index
  • Get First or Last Element: let menu of menus; let first = first; let last = last
  • Get Even or Odd Elements: let menu of menus; let odd = odd; let even = even
  • Imporve performance: let menu of menus; trackBy: trackElement
  • Data Binding: [], e.g. [class.active]="i === selectedIndex"
  • Event Binding: (), e.g. (click)="handleSelection(i)""

3. *ngIf

Syntax 1:

<div *ngIf="condition">View exposed when the condition is true.</div>

Syntax 2:

<div *ngIf="condition else elseContent" >Content exposed when the condition is true.</div>
<ng-template #elseContent>Content exposed when the condition is false.</ng-template>

Syntax 3:

<div *ngIf="condition; then thenTemplate; else elseContent"></div>
<ng-template #thenContent>Content exposed when the condition is true.</ng-template>
<ng-template #elseContent>Content exposed when the condition is false.</ng-template>

4. Component

How to generate a component?
ng generate component componentName(CamelCase) or ng g c name

Input and Output

Input Attribute Binding

For example, previous we have created a menu in ScrollableTabComponent, we want to reuse it somewhere. So, we add a decorator @Input before the menu, indicating the data of this menu field is set by father component. Now we refactor the codes as follows.

CLICK TO SEE THE CODES

In file scrollable-tab.component.ts:

export interface TopMenu {
  title: string;
  readonly link?: string;
}

export class ScrollableTabComponent implements OnInit {
@Input() menus: TopMenu[] = [];
...
}

In file app.component.ts:

menus: TopMenu[] = [
  { title: 'HOT', link: '' },
  { title: 'WEAPON', link: '' },
  { title: 'Damage', link: '' },
  { title: 'Critical Strike', link: '' },
  { title: 'Attack Speed', link: '' },
  { title: 'Lift Steal', link: '' },
  { title: 'DEFENSE', link: '' },
  { title: 'Health', link: '' },
  { title: 'Magic Resist', link: '' },
  { title: 'Health Regen', link: '' },
  { title: 'Armor', link: '' },
  { title: 'MAGIC', link: '' },
  { title: 'Ability Power', link: '' },
  { title: 'Cooldown Reduction', link: '' },
  { title: 'Mana', link: '' },
  { title: 'Mana Regen', link: '' },
  { title: 'MISC', link: '' },
  { title: 'Movement', link: '' },
  { title: 'Consumables', link: '' }
]

How to transfer data from parent component (app.component), to child component (scrollable-tab.component) ?

In app.component.html:

<app-scrollable-tab [menus]="menus"></app-scrollable-tab>

Output - Event Binding

For example, we bind an event on the tab we clicked.

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

export class ScrollableTabComponent implements OnInit {
  // codes
  @Output() tabSelected = new EventEmitter();
  // codes
  handleSelection(index: number) {
    this.selectedIndex = index;
    this.tabSelected.emit(this.menus[this.selectedIndex]);
  }
}

In app.component.html and app.component.ts

<app-scrollable-tab [menus]="menus" (tabSelected)="handleTabSeletced($event)"></app-scrollable-tab>
handleTabSelected (tabMenu: TopMenu) {
  console.log(tabMenu); 
}

5. Template Binding

More about *Binding* in Angular

Several ways to realize Template Binding

  • <div [class.className]="condition">...</div>
  • <div [ngClass]="{'One': true, 'Two': true, 'Three': false}>...</div>
  • <div [ngStyle]="{'color':someColor, 'font-size':fontSize}">...</div>

For example, we want to set background color, font color, font weight from upper component, then we can code like this.

In scollable-tab.componnet.html, we add [ngStyle]="{ 'background-color': backgroundColor } in tag <ul> to set the background color of the list. And backgroundColor is the input variable from father component.

<ul [ngStyle]="{ 'background-color': backgroundColor }">
  <li *ngFor="let menu of menus; let i = index; let even = even; let odd = odd"
      [ngClass]="{ 'even': even, 'odd': odd}">
    <a href="#" 
       [ngStyle]="{ color: i === selectedIndex ? titleActiveColor : titleColor }"
       (click)="handleSelection(i)">
    </a>
    <span class="indicator" 
          [ngStyle]="{ 'background-color': indicatorColor }"
          *ngIf="i === selectedIndex; else elseTemplate"></span>
  </li>
  <<ng-template #elseTemplate>Hello</ng-template>
</ul>

In scollable-tab.componnet.css:

.even {
    font-weight: 900;
}
.odd {
    font-weight: 100;
}

In scollable-tab.componnet.ts we add decorator @Input before variables we want to set from father component.

@Input() menus: TopMenu[] = [];
@Input() backgroundColor = '#fff';
@Input() titleActiveColor = 'yellow';
@Input() titleColor = 'blue';
@Input() indicatorColor = 'brown';

Then in the father component we can pass data into these variables.

<app-scrollable-tab 
  [menus]="menus" 
  [backgroundColor]="'red'"
  titleColor="#fff"
  titleActiveColor="yellow"
  indicatorColor="yellow"
  (tabSelected)="handleTabSelected($event)">
</app-scrollable-tab>

Then the tab is shown as follows.

next

   Reprint policy


《Project - Groupbuy App Part I》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
 Previous
Add Binary Add Binary
LeetCode Q 67 - Add BinaryGiven two binary strings, return their sum (also a binary string). The input strings are both
2019-06-19 Tong Shi
Next 
Arithmetic Slices Arithmetic Slices
LeetCode Q 413 - Arithmetic SlicesA sequence of number is called arithmetic if it consists of at least three elements an
2019-06-18 Tong Shi
  TOC