Angular基礎メモ

Angularの基礎的なことを備忘録として残しておきます。

#環境
Angular: 9.1.2
Angular CLI: 9.1.12
Node: 12.18.3
OS: win32 x64

#参考
公式：Angular入門 チュートリアル
https://angular.jp/start

Angular入門 未経験から1ヶ月でサービス作れるようにする
https://qiita.com/seteen/items/43908e33e08a39612a07

Angular Tutorial - 21 - Fetch Data Using HTTP(httpClient.getの使い方）
https://www.youtube.com/watch?v=LmIsbzt-S_E&list=PLC3y8-rFHvwhBRAgFinJR8KHIrCdTkZcZ&index=21

#テンプレート構文
・HTML上で書ける基本のテンプレート構文
- *ngFor
- *ngIf
- 補間 {{ }} EL式みたいなの。
- プロパティバインディング [ ]　
- イベントバインディング ( )

##補間
補間構文 {{ }} は 
TypeScriptで宣言した変数の値をHTMLでテキスト表示する。 

```html:app.componet.html
<h1>{{ title }}</h1> // test-angularが表示される。
```

```typescript:app.componet.ts
export class AppComponent { 
  title = 'test-angular'; 
}
```


##プロパティバインディング
typescript　→　html方向のバインド
公式の説明：プロパティバインディングは、値をコンポーネントのプロパティから 対象の要素のプロパティへと、単方向に流します。
私の理解：[ ]で囲ったDOM要素に対してTypeScriptで定義した要素を入力する。 

[プロパティ名] = "変数名"

```html:app.component.html
<a [href]="url">Googleへ</a>
```

```typescript:app.componet.ts
export class AppComponent {
  url = 'https://www.google.com';
}
```
上記はHTMLのa要素のhrefプロパティにapp.componetのurlプロパティをバインドしている。


##ngFor
１、tsファイルで配列を定義。

```typescript:app.component.ts
import { Component } from '@angular/core'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent { 
  title = 'test-angular'; 
  url = 'https://www.google.com'; 
  i: number[] = [0,1,2]; 
}
```

2,htmlファイルでngFor

```html:app.component.html
<h1>{{ title }}</h1> 
<a [href]="url">Googleへ</a> 
<div *ngFor="let item of i"> 
  <p>{{item}}</p> 
</div> 
```
*ngFor="let aaa of bbb"はbbb配列の要素をaaaに1個ずつ入れて取り出す。
Javaの拡張for文のような感じ。

補足、添え字番号の取得など
`<li *ngFor="let item of i; let j = index; let f = first>`
jに添え字番号、fに最初の要素かどうかの boolean が入る。


##ngIf
１、tsファイルで配列を定義。

```typescript:app.component.ts
import { Component } from '@angular/core'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent { 
  i: number[] = [0,1,2,null]; //追加
}
```

２、htmlファイルでngIf

```html:app.component.html
//i[3]がnullならこのdivを表示。nullでないならi3を表示。
<div *ngIf="i[3] === null; else i3"> 
  i[3]はありません。 
</div> 

// nullでない時はこちらが表示される。ng-template要素。
<ng-template #i3> 
  {{i[3]}} 
</ng-template> 
```

##イベントバインディング
html　⇒　typescript方向のバインド。

１、 ボタンのclickイベントを、alertOn()メソッドに紐付けます。 
イベントバインディングは(click)のように、イベントを囲むカッコ ( ) を使用します。

```html:app.component.html
<button (click)="alertOn()">アラート</button>
```

２、alertOn()メソッドをtsファイルに追加。

```typescript:app.component.ts
import { Component } from '@angular/core'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent { 
 // alertOn()メソッドの追加。
  alertOn(): void { 
    alert('イベントバインディング'); 
  } 
}
```

〇主なイベント一覧
click　クリック
dbclick　ダブルクリック
mousedown　マウスボタンを押した時
mouseup　マウスボタンを離した時
mouseenter　マウスポインターが要素に入った時
mousemove　マウスポインターが要素内を移動した時
mouseleave　マウスポインターが要素から離れた時
focus　要素にフォーカスした時
blur　要素からフォーカスが外れた時
keydown　キーを押した時
keypress　キーを押し続けている時
keyup　キーを離した時
input　入力内容が変更された時
select　テキストが選択された時
reset　リセット時
submit　サブミット時


##双方向バインディング
外部（ブラウザ）からの入力と内部（スクリプト）からの入力の双方向で値を更新する仕組み。
ブラウザ⇔変数⇔TypeScript

１、HTMLで[(ngModel)]要素を作る。

```html:app.component.html
<input type="text" name="name" [(ngModel)]="message"> 
<div> 
  メッセージ：{{ message }} 
</div>
```

２、TypeScriptでmessage変数を定義。

```typescript:app.component.ts
import { Component } from '@angular/core'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent { 
  message: string;  //ここを追加。
}
```


#Component

一連のUI機能を再利用できる。
Android開発でいうところのレイアウトみたいなもの。（リニアレイアウトの中にテーブルレイアウトが入ってたりイメージビューが入ってたり）

以下、[Angular公式](https://angular.jp/guide/architecture-components)の引用。

>コンポーネントは3つの要素で構成されています。
>
> TypeScript：コンポーネントクラス では、データと機能を処理します。前のセクションでは、コンポーネントクラス内の製品データとshare()メソッドはそれぞれデータと機能を処理しました。
>
> HTML：HTMLテンプレート では、UIを決定します。 前のセクションでは、商品リストのHTMLテンプレートを変更して、各商品の名前、説明、および"Share"ボタンを表示しました。
>
>CSS：コンポーネント固有スタイル では、ルック・アンド・フィールを定義します。 商品リストにはスタイルは定義されていませんが、 ここにはコンポーネントCSSが存在します。


##コンポーネントの生成
angular CLIで

```
ng generate component hero-detail(コンポーネント名）
```

ng generate componentは4つのファイルを生成する。
CSS・HTML・TypeScript・テストファイル

#ルーティング
ルーティングとはURLに応じてコンテンツの部分を動的に表示させる仕組みです。
ページ遷移等。

##ルーティング基礎１
aaaComponentをルーティングで表示。
１、app-routing.module.tsでAaaComponentをインポート。
　　さらにpathを追加。

```typescript:app-routing.module.ts
import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 

import { AaaComponent } from './test/aaa/aaa.component'; // ここを追加

const routes: Routes = [ 

// ここを追加。http://localhost:4200/aaaに接続したら、AaaComponentが動作しますよということ。
  { path: 'aaa', component: AaaComponent }
]; 
@NgModule({ 
  imports: [RouterModule.forRoot(routes)], 
  exports: [RouterModule] 
}) 
export class AppRoutingModule { }
```

２、app.module.tsがapp-routing.module.tsを参照するように定義する。

```typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { AppRoutingModule } from './app-routing.module'; 
import { AppComponent } from './app.component';  //ここを追加。 
@NgModule({ 
  declarations: [ 
    AppComponent, 
    ProductListComponent, 
    ProductDetailComponent, 
    BbbComponent 
  ], 
  imports: [ 
    BrowserModule, 
    AppRoutingModule  // ここを追加。
  ], 
  providers: [], 
  bootstrap: [AppComponent] 
}) 
export class AppModule { }
```

３、app.component.htmlに下記を追加。
これでhttp://localhost:4200/aaaに接続するとaaa.component.htmlの中身が表示されるようになる。

```html:app.component.html
<router-outlet></router-outlet>
```

##ルーティング基礎２

・リダイレクト
１、app-routing.module.tsでpathを追加する。
ttp://localhost:4200/aaaにリダイレクトされる。

```typescript:app-routing.module.ts
import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
const routes: Routes = [ 
{ path: 'aaa', component: AaaComponent }, 
{ path: '', redirectTo: '/aaa', pathMatch: 'prefix' } //ここを追加するだけ。
]; 
@NgModule({ 
  imports: [RouterModule.forRoot(routes)], 
  exports: [RouterModule] 
}) 
export class AppRoutingModule { }
```
pathMatch: 'prefix'の意味
・prefix : URLが path の値で始まる場合 (今回の場合は、>http://localhost:4200/ で始まるすべてのURL。事前に定義されている /aaa を除く) にリダイレクトします。
・full: の場合はURLが path と完全に一致した場合（今回の場合 >http://localhost:4200/ ) にリダイレクトします。


##ルーティング基礎３
・ページ遷移
aaa.component.html ⇔bbb.component.htmlでの遷移

１、app-routing.module.tsでpathを追加する

```typescript:app-routing.module.ts
import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
import { AaaComponent } from './test/aaa/aaa.component'; 
import { BbbComponent } from './test/bbb/bbb.component';  //追加
const routes: Routes = [ 
  { path: 'aaa', component: AaaComponent }, 
  { path: 'bbb', component: BbbComponent },  // 追加
  { path: '', redirectTo: '/aaa', pathMatch: 'prefix' }, 
]; 
@NgModule({ 
  imports: [RouterModule.forRoot(routes)], 
  exports: [RouterModule] 
}) 
export class AppRoutingModule { }
```

２、app.module.tsにインポート。

```typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { AppRoutingModule } from './app-routing.module'; 
import { AppComponent } from './app.component'; 
import { AaaComponent } from './test/aaa/aaa.component'; 
import { BbbComponent } from './test/bbb/bbb.component';  //追加。多分自動で追加される。
@NgModule({ 
  declarations: [ 
    AppComponent, 
    AaaComponent, 
    BbbComponent //追加。多分自動で追加される。
  ], 
  imports: [ 
    BrowserModule, 
    AppRoutingModule 
  ], 
  providers: [], 
  bootstrap: [AppComponent] 
}) 
export class AppModule { }
```

3、aaa.component.html にリンクをはる。

```html:aaa.component.html
<p>aaa works!</p> 
//http://localhost:4200/bbbに遷移。
<button [routerLink]="['/bbb']"> 
  bbbへ 
</button>
```

4、bbb.component.html にリンクをはる。

```html:bbb.component.html
<p>bbb works!</p> 
//http://localhost:4200/aaaに遷移。
<button [routerLink]="['/aaa']"> 
  aaaへ 
</button>
```

#Service
[Angular公式](https://angular.jp/start/start-data)から引用。
>サービスはAngularアプリケーションの不可欠な部分です。 Angularでは、
>サービスはAngularの 依存性の注入システム を使用してアプリケーションの任意の部分で使用できるクラスのインスタンスです。
>サービスは、アプリケーションの各部分の間でデータを共有する場所です。 
>オンラインストアの場合、カートサービスはカートデータとメソッドを保存する場所です。
>逆にコンポーネントクラスは呼び出すだけ。


・なぜサービスが必要なのか？
[Angular公式](https://angular.jp/tutorial/toh-pt4)から引用。

>コンポーネント内では直接データの取得や保存を行うべきではありません。もちろん、故意に仮のデータを渡してもいけません。
>コンポーネントはデータの受け渡しに集中し、その他の処理はサービスクラスへ委譲するべきです。


・サービスの生成
`ng generate service hero（サービス名）`

・サービスの使用方法
参考：https://angular.jp/start/start-data

```typescript:cart.service.ts
import { Injectable } from '@angular/core'; 
@Injectable({ 
  providedIn: 'root' 
}) 
export class CartService { 
items = []; 
  addToCart(product) { 
    this.items.push(product); 
  }
}
```

サービスを使用したいtsファイルにインポート

```typescript:productdetails.component.ts
import { CartService } from '../cart.service';
```

サービスを使用したいtsファイルのコンストラクタに注入

```typescript:productdetails.component.ts
export class ProductDetailsComponent implements OnInit { 
  constructor( 
    private route: ActivatedRoute, 
    private cartService: CartService //依存性の注入
  ) { } 
}
```

サービスを使用したいtsファイルでメソッドを呼び出し。

```typescript:productdetails.component.ts
export class ProductDetailsComponent implements OnInit { 
    this.cartService.addToCart(product);
}
```

#GETリクエストの送り方
１、app.module.tsでインポート

```typescript:app.module.ts
import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { AppRoutingModule } from './app-routing.module'; 
import { AppComponent } from './app.component'; 
import { HttpClientModule } from '@angular/common/http'
import { HttpClientModule } from '@angular/common/http';// ここを追加。

@NgModule({
  declarations: [
    AppComponent
  ],
imports: [ 
    BrowserModule, 
    AppRoutingModule, 
    HttpClientModule // ここを追加。
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

１－２、jsonファイルを用意する 
/assets/data/employees.json

```json:employees.json
[
  {"id": 1, "name": "Andrew", "age": 30},
  {"id": 2, "name": "Brandon", "age": 25},
  {"id": 3, "name": "Christina", "age": 26},
  {"id": 4, "name": "Elena", "age": 28},
  {"id": 5, "name": "Felicia", "age": 25}
]
```

2、サービスクラスGETリクエストを送る。
http.getメソッドを呼ぶメソッドを作る。返り値型はObservable<?>

```typescript:Employee.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { IEmployee } from './employee.model';
@Injectable({
  providedIn: 'root'
})
export class EmployeeService {
  
  private url: string = '/assets/data/employees.json';

  constructor(private http: HttpClient) { }

  // getの後の<IEmployee[]>はキャストらしい。
  getEmployees(): Observable<IEmployee[]> {
    return this. http.get<IEmployee[]>(this.url);
  }
}
```

３、戻り値用のモデルクラスを作る

```typescript:employee.model.ts
export interface IEmployee {
  id: number,
  name: string,
  age: number
}
```

４、http.getメソッドを呼ぶメソッドを呼ぶメソッドを作るｗ

```typescript:app.component.ts
import { Component, OnInit } from '@angular/core'; 
import { EmployeeService } from './employee.service'; 
@Component({ 
  selector: 'app-root', 
  templateUrl: './app.component.html', 
  styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit{ 
  public employees = []; //返り値はここに入る 

  // 依存性の注入。EmployeeServiceの注入。 
  constructor(private employeeService: EmployeeService) {} 

  ngOnInit() { 
    // getEmployeesを呼び出し。返り値をemployees配列に代入。 
    this.employeeService.getEmployees() 
      .subscribe(data => this.employees = data); 
  } 
}
```

5、HTMLで表示

```html:app.component.html
<h2>Employee List</h2>
    <ul *ngFor="let employee of employees">
      <li>{{employee.name}}</li>
    </ul>
```