# Day08 【牙起來】 物件、陣列、ngFor、ngIf - 程式面介紹
再來換到**商店store**區塊
商店嘛,總是要販售一些**武器**和**防具**的
不然裸裝的冒險者早晚都死光了
## 程式內的物件 Object
於是在 `store.component.ts` 中加入 **weapon**物件
我要一把**小劍**,他的**攻擊力**是5 `{name: '小劍', atk: '5'}`
```typescript=
...
export class StoreComponent implements OnInit {
weapon = {name: '小劍', atk: '5'};
constructor() { }
ngOnInit(): void {
}
}
```
接下來你知道的,還要修改樣板 `store.component.html`
```html=
<h2>商店區塊</h2>
<div>武器: {{weapon}}</div>
```
來看一下吧

诶?奇怪
我的小劍跟攻擊力5去哪了?
為什麼是出現`[object Object]`呢?
我們分別使用 `alert` 與 `console.log` 印出來看看
```typescript=
...
export class StoreComponent implements OnInit {
weapon = {name: '小劍', atk: '5'};
constructor() { }
ngOnInit(): void {
alert(this.weapon);
console.log(this.weapon);
}
}
```
使用 `alert` 也一樣,印物件只會出現`Object`、而非物物件內部結構

> 這邊能用 `JSON.stringify()` 把物件以字串方式印出來看
使用 `console.log` 則可以看到物件內部結構

### 管線 pipe
要在Angular樣板上印出完整物件,可以使用**json pipe**
透過將物件轉換成json格式再印出來
修改 `store.component.html`
```html=
<h2>商店區塊</h2>
<div>武器: {{weapon | json}}</div>
```
在綁定的變數後方加上` | json` ,其中這一槓 `|` 代表的就是**管線 pipe**
> 關於pipe元件會在之後的章節再次提及
印出物件的畫面

### 取得物件底下的成員
分別印出武器物件底下的 **名稱 name** 跟 **攻擊力 atk**
透過以下兩種方式都可以取得物件底下的數值
* 物件的點點`.`來取得成員
* `['']` 來索引物件
```html=
<h2>商店區塊</h2>
<div>武器名稱: {{weapon.name}}</div>
<div>武器攻擊力: {{weapon['atk']}}</div>
```

> 什麼,你說現在商店只有一把武器 不夠看、太過窮酸?
>
> 看來... 我們只好導入陣列了
## 程式內的陣列 Array
武器變成多把,所以把變數名稱改成 `weapons` 複數
然後以**陣列**包起這個物件
修改 `store.component.ts`
```typescript=
export class StoreComponent implements OnInit {
weapons = [
{name: '小劍', atk: '5'},
{name: '彎刀', atk: '7'},
{name: '大魔劍', atk: '11'},
];
constructor() { }
ngOnInit(): void {
}
}
```
因為 `weapons` 變成陣列型態了,所以樣板也需要加入 `[0]` 來索引陣列
```html=
<h2>商店區塊</h2>
<div>武器名稱: {{weapons[0].name}}</div>
<div>武器攻擊力: {{weapons[0]['atk']}}</div>
```
---
## 樣板中的For迴圈 - `*ngFor`
有三樣武器,如果要透過HTML印出來
一樣一樣指定 `weapons[0]`、`weapons[1]`、`weapons[2]` 也太麻煩了
所以Angular在樣板中也有 **For 迴圈** ,叫作 **`*ngFor`**
修改 `store.component.html`
```html=
<h2>商店區塊</h2>
<div *ngFor="let weapon of weapons">
<div>武器名稱: {{weapon.name}}</div>
<div>武器攻擊力: {{weapon['atk']}}</div>
<br>
</div>
```
因為迴圈需要一層空間來**指定loop的範疇**,所以`ngFor`會放在要循環結構的外面
用法為`*ngFor = let ... of ...`

修改後結果

### 迴圈的索引值 index
若想將武器商品編號,需要For迴圈中的**索引值**時
可在 `ngFor` 的地方加上`let ... = index`
便可以引用索引編號,索引值index從`0`開始
修改 `store.component.html`
```html=
<h2>商店區塊</h2>
<div *ngFor="let weapon of weapons; let i = index">
<div>武器編號: {{i + 1}}</div>
<div>武器名稱: {{weapon.name}}</div>
<div>武器攻擊力: {{weapon['atk']}}</div>
<br>
</div>
```
> 什麼,你覺得這波操作挺稀鬆平常?
>
> 拜託,這裡可是HTML樣板啊,原本可都是只寫標籤元素的地方
> 能在這裡寫code難道不驚訝嗎?
>
> 這都是Angular框架的功勞啊
---
接下來替遊戲增加一點樂趣興
因為遊戲商店中,總會有一些玩樂性質的**垃圾武器**出現
譬如說接下來要登場的這一把 `只是名稱長了一點但沒有任何攻擊力` 的武器
修改 `store.component.ts`
```typescript=
export class StoreComponent implements OnInit {
weapons = [
{name: '小劍', atk: '5'},
{name: '彎刀', atk: '7'},
{name: '大魔劍', atk: '11'},
{name: '只是名稱長了一點但沒有任何攻擊力'},
];
constructor() { }
ngOnInit(): void {
}
}
```
結果畫面

## 樣板中的if判斷 - `*ngIf`
因為 `只是名稱長了一點但沒有任何攻擊力` 這把武器真的沒有攻擊力的屬性
我想將他的 **武器攻擊力** 這一行隱藏掉,不然顯示在那也頗怪、挺佔位置的
這時候可以用**if 判斷式** `*ngIf`
修改 `store.component.html`
```html=
<h2>商店區塊</h2>
<div *ngFor="let weapon of weapons; let i = index">
<div>武器編號: {{i + 1}}</div>
<div>武器名稱: {{weapon.name}}</div>
<div *ngIf="weapon.atk">武器攻擊力: {{weapon['atk']}}</div>
<br>
</div>
```
當 `weapon` 底下有 `atk` 這個屬性時,才會顯示**武器攻擊力**這一行
完成畫面

`*ngIf` 也可以有其他篩選條件
譬如**過濾武器**,只顯示**攻擊力為11**的武器
```html=
<h2>商店區塊</h2>
<div *ngFor="let weapon of weapons; let i = index">
<div *ngIf="weapon.atk == '11'">
<div>武器編號: {{i + 1}}</div>
<div>武器名稱: {{weapon.name}}</div>
<div *ngIf="weapon.atk">武器攻擊力: {{weapon['atk']}}</div>
<br>
</div>
</div>
```
這邊的`'11'`因為是**字串**而非數字,所以用單引號`''`括起來
最終完成畫面

---
> 恭喜到這一步已經完成 61% 的Angular
>
> 至於ngFor、ngIf為什麼要有那個星號`*`?
> 因為星號表示[**循環結構的語法糖**](https://stackoverflow.com/questions/35498498/what-is-the-meaning-of-in-ngfor-in-angular2)
>
> 另外,[**ngIf跟ngFor沒辦法綁在同一個標籤上**](https://stackoverflow.com/questions/34657821/ngif-and-ngfor-on-same-element-causing-error)