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