###### tags: `Angular`
# 🥔從認識 Component 開始
在開發專案的時候,大部分的程式邏輯我們都是寫在 Component 裡面 ,因此我想大家對於 Component 一定不陌生,但有些東西可能從來沒有注意過,或是不知道為什麼它是這個樣子。
所以我今天會從 Component 來開始,來帶大家認識 Angular 的一些基礎概念。
>[API參考手冊-Component](https://angular.tw/api/core/Component)。
## *@Component.* 裝飾器
- 宣告的類別掛上`@Component`裝飾器,就表示此類別為一個元件。Angular的元件類別負責暴露資料,並透過資料繫結機制來處理絕大多數檢視的顯示和使用者互動邏輯。
- `@Component()`裝飾器是擴充`@Directive()`裝飾器,增加了一些與範本(`template`)有關的特性。
## *@Component.* 資料配置
- `@Component`裝飾器內的配置,決定此元件會與哪個範本(`template`)建立關聯,與其他相關的程式,以下是`Component`基礎配置。
```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-first',
templateUrl: './first.component.html',
styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
```
## *@Input*
- 負責接收資料
>**Parent傳'Hello',Child接收並顯示**
>1. 建立一個child component並設計`@Input()`功能。
>2. 建立一個parent component使用child component,且使用child的`@Input()`。
*step1.* 建立Child component
==child.component.ts==
```typescript=
import { Component, Input, OnInit } from "@angular/core";
@Component({
selector: "app-child",
templateUrl: "./child.component.html",
styleUrls: ["./child.component.css"]
})
export class ChildComponent implements OnInit {
@Input() strShow: string;
constructor() {}
ngOnInit() {}
}
```
==child.component.html==
```htmlembedded=
<p>{{strShow}}</p>
```
*step2.* 建立Parent component
==parent.component.ts==
```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
strInput = 'Hello';
constructor() { }
ngOnInit() {
}
}
```
==parent.component.html==
- 要使用child內的`@Input()`要在HTML內使用,且要用[中括號]括起來後面再帶入參數。
```htmlembedded=
<app-child [strShow]="strInput"></app-child>
```
## *@Output*
- 負責發射資料
>**Parent接收點擊按鈕後,由Child送出的'World'**
>1. 建立一個child component並設計`@Output()`功能。
>2. 建立一個parent component使用child component,且使用child的`@Output()`。
*step1.* 建立Child component
==child.component.ts==
- Output一定要搭配使用EventEimmter,這是固定寫法。
- emit(),就是發射訊息的意思。
```typescript=
import { Component, EventEmitter, OnInit, Output } from "@angular/core";
@Component({
selector: "app-child",
templateUrl: "./child.component.html",
styleUrls: ["./child.component.css"]
})
export class ChildComponent implements OnInit {
@Output() strWord = new EventEmitter();
constructor() {}
ngOnInit() {}
onClick() {
this.strWord.emit('World');
}
}
```
==child.component.html==
```htmlembedded=
<button (click)="onClick()">Output</button>
```
*step2.* 建立Parent component
==parent.component.ts==
```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
constructor() { }
ngOnInit() {
}
showStrWord(strWord) {
console.log(strWord);
}
}
```
==parent.component.html==
- 要使用child內的`@Output()`要在HTML內使用,且要用(小括號)括起來後面再帶入參數。
- `showStrWord($event)`,這裡面的`$event`是emit的值,那$event也是固定寫法。
- 可以在devTools[F12] console 看到child傳送過來的值,確認是否正確。
```htmlembedded=
<app-child (strWord)="showStrWord($event)"></app-child>
```
## *其他傳值的方法*
[[T]Passing Parameters 參數傳遞](https://hackmd.io/@Ru/BkcCsfB2H#ViewChild)
- @ViewChild
==viewchild.component.html==
```htmlembedded=
<h2>@ViewChild()</h2>
<p>{{message}}</p>
```
==viewchild.component.ts==
```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-viewchild',
templateUrl: './viewchild.component.html',
styleUrls: ['./viewchild.component.scss']
})
export class ViewchildComponent implements OnInit {
message: string = '我是土豆';
constructor() { }
ngOnInit(): void {
}
setMessage(message: string) {
this.message = message;
}
}
```
==component.component.html==
```htmlembedded=
<app-viewchild #vc></app-viewchild>
<input [(ngModel)]="vcMsg" (change)="onChange()">
```
==component.component.ts==
```typescript=
import { ViewchildComponent } from './viewchild/viewchild.component';
import { Component, OnInit, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-component',
templateUrl: './component.component.html',
styleUrls: ['./component.component.scss']
})
export class ComponentComponent implements OnInit, AfterViewInit {
@ViewChild('vc') vc: ViewchildComponent;
vcMsg: string;
constructor(
private changeDetectorRef: ChangeDetectorRef
) { }
ngOnInit(): void {
}
ngAfterViewInit(): void {
this.vc.setMessage('土豆');
this.changeDetectorRef.detectChanges();
}
onChange() {
this.vc.setMessage(this.vcMsg)
}
}
```
> `ExpressionChangedAfterItHasBeenCheckedError`
> 使用 `@ViewChild` 的時候需要注意父元件的使用時機
- RouterState
==router-state.component.html==
```htmlembedded=
<h2>routerState</h2>
<button routerLink="/a4/component/input" [state]="{page: 'A'}">Page A</button>
<button (click)="onClickB()">Page B</button>
<button routerLink="/a4/component/viewchild">Page C</button>
<router-outlet></router-outlet>
```
==router.state.component.ts==
```typescript=
import { Router } from '@angular/router';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-router-state',
templateUrl: './router-state.component.html',
styleUrls: ['./router-state.component.scss']
})
export class RouterStateComponent implements OnInit {
constructor(
private router: Router
) { }
ngOnInit(): void {
}
onClickB() {
this.router.navigate(['/a4/component/output'], {state: {page: 'B'}})
}
}
```
==input / output component.ts==
```typescript=
ngOnInit(): void {
console.log('state', window.history.state);
}
```