Angular

提供: MyMemoWiki
ナビゲーションに移動 検索に移動

目次

Angular

TypeScript | Google Cloud Platform | Bootstrap | Flask |

Angular CLI

準備

Quickスタート

  • ダウンロード
> git clone https://github.com/angular/quickstart.git quickstart
  • パッケージのインストール
> cd quickstart
> npm install
  • 実行
> npm start

Angular quickstart.png

要素

ルートモジュール
要素名 説明
コンポーネント UI部品
サービス ビジネスロジック
パイプ 表示値の加工、演算
ディレクティブ 文書ツリーの操作
  • モジュール
    • Angularにおけるモジュールの実態は、TypeScriptのクラス
    • 定義しただけではモジュールとみなされず、@NgModuleデコレータで宣言が必要

設定ファイル

設定ファイル 概要
package.json 利用するライブラリ情報
tsconfig.json TypeScriptコンパイラーの動作を
systemjs.config.js モジュールローダー(SystemJS)の設定

インストール

>npm install -g @angular/cli

アプリケーションの生成

> ng new myapp

アプリケーションの実行

> ng serve

Angular CLI の主なコマンド

概要 コマンド
appアプリを生成 ng new app
ひな形の生成 ng generate ...
ビルドして起動 ng serve
ビルド ng build
ユニットテスト ng test
E2Eテスト mg e2e
i118nメッセージを抽出 ng xi18n
指定されたキーワードで検索 ng doc keyword
TSLintによるコードチェック ng lint
現在の設定を取得 ng get key
指定されたキー/値を設定 ng set key=value
Angular CLIのバージョン ng version
ng generate サブコマンド
要素 コマンド
モジュール ng g moduole hoge
コンポーネント ng g component hoge
ディレクティブ ng g directive hoge
パイプ ng g pipe hoge
サービス ng g service hoge
ガード ng g guard hoge
クラス ng g class hoge
インターフェース ng g interface hoge
列挙 ng g enum hoge

ngx-bootstrap

Angular-CLIから利用

インストール
npm install ngx-bootstrap bootstrap --save
src/app/app.module.ts の編集
import { AlertModule } from 'ngx-bootstrap';
     :
@NgModule({
     :
   imports: [AlertModule.forRoot(), ... ],
     :
})
.angular-cli.json に以下を追加
"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.min.css",
  "styles.css"
],
src/app/app.component.html に以下を追加
<alert type="success">hello</alert>

0167 bootstrap alert.jpg

Angular Material

非同期通信

app.module.ts
import { HttpModule } from '@angular/http';
    :
@NgModule({
    :
  imports: [
     :
    HttpModule,
  ],
     :
})

データバインディング

構文

データ方向 種類 記法
コンポーネント -> ビュー 補間 {{...}}
コンポーネント -> ビュー プロパティ/属性バインディング [property]='value'
ビュー -> コンポーネント イベントバインディング (event)='handler'
コンポーネント <-> ビュー 双方向バインディング [(target)]='value'

テンプレート参照変数

    1. 変数名
  • (change)="0"は、イベントトリガーで値を更新するため必要
<input #txtHoge type="text" (change)="0"/>
<div>テンプレート:TxtHoge.value</div>

双方向バインディング

  • import と @NgModule の imports に FormModuleを追加
ルートモジュール(app.modules.ts)
import { FormsModule } from '@angular/forms';
   :
@NgModule({
   :
  imports: [
   BrowserModule,
   FormsModule,
     :
ビュー
  • input/textarea/selectなどフォーム要素をバインドするには、ngModel を利用する
  • このためには、name属性の指定が必須
  • ngModelを[(ngModel)]とする
<select name="selAcion" [(ngModel)]="selectedAction">
    <option *ngFor="let item of testActions" value="テンプレート:Item" >テンプレート:Item</option>
</select>
コンポーネント
export class AccountComponent implements OnInit {
  testActions: string[] = [,'login','logout','check'];
  selectedAction: string = ;

入力値の加工

  • 上記は、プロパティバインディング、イベントバインディングを組み合わせて、双方向を実現している。
  • データバインディング時に値を加工する場合、[(ngModel)] を [ngModel]と(ngModelChagen) に分解
  • $eventは入力値そのものを表す
<input name="hoge" type="text"
  [ngModel] = "hogeName"
  (ngModelChange) = "hogeName=$event.toUpperCase()" />

イベントバインディング

  • app.component.ts
import { Component } from '@angular/core';
import { componentFactoryName } from '@angular/compiler';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.sass']
})
export class AppComponent {
  title = 'Hot Dog Status';
  status = ;
  save(e: any) {
    this.status = "Save";
  }
  load(e: any) {
    this.status = "Load";
  }
}

.

  • appcomponent.html
<h1 id="hotDogStatus">テンプレート:Title:テンプレート:Status</h1>
<input type="textField" id="latestHotDogStatus" />
<button (click)="save($event)">Save</button>
<button (click)="load($event)">Load</button>

<router-outlet></router-outlet>

Angular event.png

ルーティング

適用

プロジェクト作成

> ng new app --routing
--routing オプションを付与せずにプロジェクトを作成した場合
  • /src/app/app-routing.module.ts を追加
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [];

@NgModule({
  imports: [
    RouterModule.forRoot(routes),
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • /src/app/app.module.ts
import { AppRoutingModule } from './app-routing.module';
   :
@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule, 
  ],
  providers: [],
  • /src/app/app.component.spec.ts
import { RouterTestingModule } from '@angular/router/testing';
   :
describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  }));

コンポーネント作成

> ng g component account --routing

ルーティング定義

  • app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AccountComponent } from './account/account.component'

const routes: Routes = [
  {
    path: 'account', component: AccountComponent
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes),
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

利用

<a routerLink="/account">Account</a>
<router-outlet></router-outlet>

コンポーネント

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

@Component({
  selector: 'my-app',
  template: `<h1>Hello テンプレート:Name&kt;/h1>`,
})
export class AppComponent  { name = 'Angular'; }
パラメータ名 概要
selector コンポーネントを適用すべき要素を表す
template コンポーネントに適用するビュー

ライフサイクル

ライフサイクル 内容
コンポーネント生成
コンストラクター
ngOnChanges @Input経由で入力値が設定/再設定された
ngOnInit 入力値(@Inputp)が処理された後、コンポーネントの初期化時(最初のngOnChangesメソッドの後で一度だけ)
ngDoCheck 状態の変更を検出したとき
ngAfterContentInit 外部コンテンツを初期化した時(最初のngDoCheckメソッドの後で一度だけ)
ngAfterContentChecked 外部コンテンツの変更をチェックした時
ngAfterViewInit 現在のコンポーネントと子コンポーネントのビューを生成した時(最初のngAfterContentCheckedメソッドの後で一度だけ)
ngAfterViewChecked 現在のコンポーネントと子コンポーネントのビューが変更された時
ngOnDestroyed コンポーネントが破棄される時
コンポーネント破棄

サービス

  • サービスクラスであることの条件は、@Injectable デコレータを付与することのみ。
  • @Injectable デコレータは、コンポーネントに対してサービスを引き渡せることを意味する。

登録

  • モジュールにサービスを登録する。
  • コンポーネントにも登録できる。この場合コンポーネントと子コンポーネントのみで利用できる。
import { HogeService } from './hoge.service';

@NgModule({
   :
  providers: [HogeService],
   :
})

依存性注入

  • 方法を宣言するのは、@NgModule/@Component デコレータの providersパラメータ
  • サービスを提供するためのProviderオブジェクトを登録する
Providerであることの条件は以下のプロパティを持つこと
プロパティ 内容
provide サービスを注入する際に利用するDIトークン
useXxxxx サービスの生成方法 例 userClass: XXXX と指定するとクラス XXXX を常にnew でインスタンス化する
multi 同一のDIトークンに対して複数のProviderを追加するか

useXxxx

プロパティ 内容
useClass 指定されたクラスを注入のたびにインスタンス化
useValue 指定されたオブジェクトを常に引き渡す(同じ値になる)
useExisting 指定されたトークンのエイリアスを生成
useFactory 指定されたファクトリー関数で注入の際にオブジェクトを生成
useClass
  • 常に新たなインスタンスを生成する
providers: [
  { provide: HogeService, useClass: HogeService } 
]
useValue
  • 常に同じオブジェクトを注入する
  • クラスのインスタンスを渡す
providers: [
  { provide: HogeService, useVlaue: new HogeService() } 
]
useExisting
  • トークンのエイリアスを生成
providers: [
  { provide: HogeService, useClass: HogeService }、
  { provide: HogeAliasService, useExisting: HogeService }、
]

<blockquote>互換性維持など、別のトークンから同一インスタンスを取得したい場合などに利用</blockquote>

useFactory
  • ファクトリー関数経由でインスタンスを生成
providers: [
  { provide: HogeService, useFactory: () => {
      let service = new HogeService();
      service.foo = "bar";
      return service;
    } 
   } 
]

Modules

Http

RxJs

リアクティブプログラミングは、データストリームと変更の伝播に関する非同期プログラミングのパラダイムです。 RxJS (Reactive Extensions for JavaScript) は、非同期またはコールバックベースのコード (RxJS Docs) の作成を容易にする observables を使用したリアクティブプログラミング用のライブラリ

  • 非同期処理の既存のコードを observables に変換する
  • ストリーム内の値を反復処理する
  • 異なる型への値のマッピング
  • ストリームのフィルタリング
  • 複数のストリームの作成

Observable 作成関数

ベント、タイマー、promise などから observables を作成するプロセスを簡素化

promise から observable を作成

import { from } from 'rxjs';

// promise から Observable を作成
const data = from(fetch('/api/endpoint'));
// 非同期の結果の購読を開始
data.subscribe({
  next(response) { console.log(response); },
  error(err) { console.error('Error: ' + err); },
  complete() { console.log('Completed'); }
});

カウンターから observable を作成する

import { interval } from 'rxjs';

// 一定間隔でで値を発行するObservable を作成
const secondsCounter = interval(1000);
// 発行される値の購読を開始
secondsCounter.subscribe(n =>
  console.log(`It's been ${n} seconds since subscribing!`));

イベントから observable を作成する

import { fromEvent } from 'rxjs';

const el = document.getElementById('my-element');

// マウスの移動を発行する Observable の作成
const mouseMoves = fromEvent(el, 'mousemove');

// マウス移動イベントを購読開始 
const subscription = mouseMoves.subscribe((evt: MouseEvent) => {
  console.log(`Coords: ${evt.clientX} X ${evt.clientY}`);

  // スクリーンの左端をマウスが越えたら購読中止
  if (evt.clientX < 40 && evt.clientY < 40) {
    subscription.unsubscribe();
  }
});

AJAX リクエストから observable を作成

import { ajax } from 'rxjs/ajax';

// AJAXリクエストを生成する Observable の作成
const apiData = ajax('/api/data');
// リクエストの生成を購読
apiData.subscribe(res => console.log(res.status, res.response));

オペレーター

オペレーターは、コレクションの高度な操作を可能にするために、observables 基盤上に構築される関数です。たとえば RxJS は map()、filter()、concat()、flatMap() のようなオペレーターを定義

オペレーターは設定オプションをとり、ソースとなる observable を受け取る関数を返します。この返された関数を実行するとき、オペレーターは observable が出力する値を観測、変換し、変換された値の新しい observable を返します

Map operator

import { map } from 'rxjs/operators';

const nums = of(1, 2, 3);

const squareValues = map((val: number) => val * val);
const squaredNums = squareValues(nums);

squaredNums.subscribe(x => console.log(x));

// Logs
// 1
// 4
// 9

パイプ

パイプを使用するとオペレーターをリンクすることができます。パイプを使用すると、複数の機能を1つの機能にまとめることができます。pipe() 関数は、結合する関数を引数としてとり、実行時に順次関数を実行する新しい関数を返します。

observable に適用される�オペレーターのセットは、レシピ、つまり関心のある値を生成するための一連の命令です。それだけではレシピは何もしません。レシピを通して結果を出すには subscribe() を呼び出す必要があります。

単独利用

import { filter, map } from 'rxjs/operators';

const nums = of(1, 2, 3, 4, 5);

// Observable を受け入れる関数の生成
const squareOddVals = pipe(
  filter((n: number) => n % 2 !== 0),
  map(n => n * n)
);

// filter と map 関数を実行する Observable を生成
const squareOdd = squareOddVals(nums);

// 結合された関数の実行を購読
squareOdd.subscribe(x => console.log(x));

Observable.pip

pipe() 関数は RxJS Observable のメソッドでもあるため、短く書き換え

import { filter, map } from 'rxjs/operators';

const squareOdd = of(1, 2, 3, 4, 5)
  .pipe(
    filter(n => n % 2 !== 0),
    map(n => n * n)
  );

squareOdd.subscribe(x => console.log(x));

コンポーネントからサービスのデータを購読する

Service
import { Subject } from 'rxjs/subject';
import { User } from './user';
 
@Injectable()
export class AccountService {
  private userChangeAnnouncedSource = new Subject<User>();
  userChangeAnnounced$ = this.userChangeAnnouncedSource.asObservable();
    :
  announceUserChange(user: User) {
    this.userChangeAnnouncedSource.next(user);
  }
    :
Component
import { Subscription } from 'rxjs/Subscription';
  
export class AccountComponent implements OnInit, OnDestroy {
    user: User;
    subscription: Subscription

  ngOnInit() {
    this.subscription = this.accountService.userChangeAnnounced$.subscribe((user:User) => {
      this.user = user;
    });  
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
       :

UI

Angular Material

レスポンシブレイアウト

テスト

ユニットテスト

Karma

Firebase

Firestoreの利用

Tips

機能

Chrome拡張機能

augury 0168 chrome extension.jpg

Facebook SDK

Hello.js 認証をまとめるJavaScriptライブラリ

文法

Javascriptのグローバルオブジェクトを利用

declare const hoge;

コード

コードからルーティング

import { Router } from '@angular/router';
   :
constructor(private router: Router) {}
   :
this.router.navigate(['/hoge']) 

CSRF

参照

Firebase