メモ的な何か

技術的な私のメモになる予定です。

自作アプリ「BookSelf」のAngular部分の解説

前記事に書いたBookSelfのAngular部分の解説となります。

Angular部分はangular CLIを使用して作成しました。
言語はTypeScriptになります。

AngularCLIの使い方

npm install -g @angular/cli
ng new BookSelfApp

※参考
https://cli.angular.io/

起動

cd BookSelfApp
ng serve

構成

ソースの構成は以下のような形です。

src
│  app.module.ts
│
├─component
│      home.component.css
│      home.component.html
│      home.component.ts
│      router.component.ts
│
├─model
│      bookInfo.ts
│      bookItem.ts
│
├─profile
│      profile.ts
│
└─service
    │  bookapi.service.ts
    │  bookself.database.service.ts
    │
    └─common
            http.service.ts

以下のような方針でディレクトリは分けています。
component
画面(component単位)を格納するディレクト
画面に対してロジック(TypeScript)、HTML、CSSを分けて格納するディレクト

model
データオブジェクト(言い方が難しい。JavaではJOJO?)を格納するディレクト

profile
環境情報を格納するディレクト

service
APIを呼ぶ機能を格納するディレクト

UI

UIデザインにはbootstrapを使用しています。

npm install --save bootstrap

angular-cli.json

"apps" : [
 ...
 "styles" : [
   "../node_modules/bootstrap/dist/css/bootstrap.min.css",
   "styles.css"
 ],

※ng-bootstrapもインストールしてますがこちらはまだ使用していないです。

今回はいったんこんな感じの構成で作成しました。
いろいろ考えましたが、経験が増えていくうちにこれから変わってくかもしれません。

わかりずらく、いろいろ調べたところ

自分の記録用と同じことで迷った人の参考までに
■app.module.tsへの記載
AngularCLIを使用している場合はapp.module.tsになるがその指定はmain.tsとなります。
さらにはangular-cli.jsonで起動もとをmain.tsに決めています。(あとindex.htmlとかも)
・Componentを追加や削除の場合
 ngModuleのdeclarationsに記載をする

・ライブラリの機能を追加したい場合
 モジュールのimportを記載し、ngModuleのimportにも記載する

・constructorでインスタンス化する場合(DI)
 ngModuleのproviderに記載をする
 ※HttpとかはHttpModuleの内部でproviderの宣言がされているのでHttpModuleをImportすることで解決している

・最初の起動画面
 ngModuleのbootstrapに記載

インクリメンタルサーチ
検索フォームはインクリメンタルサーチを作っています。(必要だろうか。。。)

f: FormGroup;

public constructor(private fb: FormBuilder, ....) {...}

fというフォームグループの宣言とFormBuilderのDIをします。

this.f = this.fb.group({
	'searchWord': ['', Validators.required]
});
this.f.valueChanges.debounceTime(500).subscribe(value => {
	this.searchWord = value['searchWord'];
	this.bookapiService.search(this.searchWord).subscribe(value => {
		this.bookItems = value[0];
		this.totalItems = value[1];
		this.initPaginationList(this.page);
	});
});

これをngOnInit(最初に動く)で実装しています。
searchWordフォームコントロールをFormBuilderに設定します。
Validators.requiredは指定フィールドが必須という意味らしい。今回はあまり意識しないです。
値に変更がかかってから次の変更を検知するまで500ミリ秒待ちを入れてます。無駄に反応しすぎるのをさけるためです。
変更を受けて検索処理が入るようになり、インクリメンタルサーチ的な動きをつくっています。

<form class="form-search" [formGroup]="f">
	<div class="form-group">
		<input type="text" value="utf8" formControlName="searchWord" class="form-control" placeholder="Please enter keywords">
	</div>
</form>

フォームは以下のような形で上記のフォームグループfの紐づけとsearchWordの紐づけをします。
※参考
qiita.com
qiita.com


APIの結果を受けて(この結果も使用する)、さらにAPIを投げる場合
参考(動作未確認、ソースではbookapi.service.tsで実装例あり)

//結果をObservable型でComponentのsubcribeに返すことですべての結果を非同期でわたせるっぽい
return http.request(最初のAPI)
.map(res => {
	let result = res.json();
	return result;
})
.map(result => {
        firstApiResult = result;

	let reses = [];//複数のAPI結果の格納先
    for(var i in result){
        let res = http.request(次のAPI, i)
                .map(res => {
                	let result = res.json();
                	return result;
                });
        reses.push(res);
    }
    return reses;
})
.flatMap(reses => Observable.forkJoin(reses))//flatMapとObservable.forkJoinを使用することで最初のAPI結果を待って、次のAPIも非同期で処理できる
.map(secondApiResults => {
	return [firstApiResult, secondApiResults];//secondApiResultsは配列
});

※参考
Angular2でObservableを使ってHTTPリクエストを複数送信 | VPSサーバーでWebサイト公開 備忘録 ~Linux、MySQLからAJAXまで


アプリ作成前にWeb以外では以下の本を参考にさせてもらっています。
Webアプリケーション作りの基本的なところは押さえられると思います。


今回のAngularのソースはGitHubにコミットしてます。
github.com
自作のWebAPI部分(DBも)がないと動きません。
その部分に関しての詳細は次の記事に記載します。