Angular (with Angular Material)を触って学んだことをメモメモ
来年は、「Vive Focus」などスタンドアロン型のVRヘッドセットが続々と投入される年になりそうで、今からワクワクが止まらない kouraku です。おはこんばんちわ。
さて、今回は、最近案件上触れることになったAngularについて、色々と挫折しかかって学んだことを忘れないようにメモしたいと思います。
ちなみに、コーダーな自分は、Angularに触れるのは初めてで、「TypeScript?なにそれ、おいしいの?」レベルな感じですので、生暖かい目で見てやっていただければと思います。
尚、Angular の導入につきましては、fujihara がとてもわかり易い記事を書いていますので、以下をご参照ください。
「手っ取り早く Angularするなら Angular CLI (Angular Material も添えて)」
尚、今回使用している環境は、ざっくりと以下のとおりです。
- Angular CLI : 1.4.9
- Node : 6.9.1
- Angular Material のコンポーネントを使用
起動時にブラウザ開いてくれないかなー
gulpでBrowsersyncを使っていると、コマンド叩いたらブラウザが勝手に開いてくれる・・・なんて当たり前ですよね。Angular CLIでも無いかなー・・・なんて思ってぐぐったら、すぐ見つかりました。
ng serve --open
あぁ、なるほど、「--open」をつければ良いのか。
でも、「--open」とか毎回つけるの面倒だな・・・
そんなときは、package.jsonを開いて・・・
"scripts": {
"ng": "ng",
"start": "ng serve --open", ←ここに「--open」を追加
といった感じで修正すれば、
npm start
で「ng serve --open」を実行してくれるので、これで少し手間が省けますね。
「それくらい入力しろ!」ってことは無しで・・・
え?スタイルが当たらない!?
fujihara が導入していた Angular Material を使っているときに起こったのですが、例えば メニューコンポーネント(MatMenuModule)を使用して、そのスタイルをちょっと調整してみよう・・・と思ったら、書いたスタイルが当たらない・・・。
何故だろう?と思い開発者ツールで調べてみると・・・、読み込まれているスタイルが以下の形で展開されていました。
<style>.hoge[_ngcontent-c3] .mat-button[_ngcontent-c3] {
color: #00f; }</style>
なるほど、.hoge と .mat-button の属性として「_ngcontent-c3」が付いている時のみ、「color: #00f;」が適用されるようになっていますね・・・。しかし、調整しようとしているメニューには何故かそんな属性は付いていない・・・。
何故こんなことが起こるのか・・・といったことは自分には分からないので、良い解決方法がないかを調べてみたところ・・・ありました!カッコイイ外国の方がサラッと答えている記事を見つけることができました。
「お前ら、『::ng-deep』を付けて定義してみな!」
(kouraku 訳)
つまり、以下の様にしてみろ、ということですね。
::ng-deep .hoge .mat-button {
color: #00f;
}
するとどうでしょう。開発者ツールを開いて、展開されているスタイルを覗いてみると・・・
<style>.hoge .mat-button {
color: #00f; }</style>
おぉ!思っていた通りの形で展開されるようになりました。これで無事解決できました。
メニューを閉じたときにイベントを起こしたいけど、どうすれば良いのか分からないよ!!
Angular 素人の kouraku には、こんなことも分かりません。
例えば、Angular Material のメニューコンポーネントですが、メニューを開いた後、画面のどこかをクリックすると、開いていたメニューが閉じます。
メニューの開閉状況によって、メニューアイコンの形を変えていた場合、メニューボタンを押して閉じるというのは、クリックイベントで取れるから良いのですが、画面のどこかをクリックして閉じる状態はどうやって認識させればよいのか・・・。そこで、Angular Material のサイトを見てみると・・・
@Output()
close
new EventEmitter<void | 'click' | 'keydown'>()
Event emitted when the menu is closed.
閉じた状態を取得する方法がありました!
・・・あとはこれをどうやって使えば良いのか。素人は、これを見ても使い方が分かりません。
グーグル先生の出番です。教えて!カッコイイ外国の方!
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu" (close)="closeMenu()"> ← こんな感じで close の時のイベントを入れる
<button mat-menu-item>
<mat-icon>dialpad</mat-icon>
<span>Redial</span>
</button>
<button mat-menu-item disabled>
<mat-icon>voicemail</mat-icon>
<span>Check voicemail</span>
</button>
<button mat-menu-item>
<mat-icon>notifications_off</mat-icon>
<span>Disable alerts</span>
</button>
</mat-menu>
なるほどなるほど、こういう書き方をすれば良いんですね。英語は弱い方なので、マニュアルを読んでも分かりませんでしたが、こうしてサンプルコードがあると良く分かりますね。ありがたや、ありがたや。
コンポーネント切替時にアニメーションを入れたいけど、どうすれば良いのか分からないよ!
例えば、ログインボタンを押したら、しばらくアニメーションする時間を待って、時間が経ったらコンポーネントを切り替える・・・こんな感じの動作をさせたいわけです。
これを実現するために考えたのが、
①コンポーネント切り替えは ts の処理で行う
② ngClass を使用して、ts 内のフラグの状況をみてクラスを付け替える
③時間管理は「Promese」を使う
といった方法を用いることでした。
部分的な感じでコードを書くと、以下のとおりです。
<!-- html -->
<div class="loginArea" [ngClass]="setClass()">
:
<form name="form" (ngSubmit)="login()">
:
<button mat-button mat-raised-button color="primary" [disabled]="flgLoading || flgCheck">ログイン</button>
:
</form>
:
</div>
// typescript
private flgLoading = false;
private flgCheck = false;
:
login() {
var that = this;
that.flgLoading = true;
Promise.resolve()
.then( () => {
setTimeout(function () {
that.flgCheck = true;
that.flgLoading = false;
}, 2000);
})
.then( () => {
setTimeout(function () {
that.router.navigate(['hoge']);
}, 3000);
});
}
setClass() {
let classes = {
loading: this.flgLoading,
active: this.flgCheck,
}
return classes;
}
2秒ローディングし、2〜3秒の間に何かしらアニメーションをさせて、3秒経過で画面が切り替わる、といったイメージです。
That.flgLoading = true;
にするタイミングを変えれば、ログインチェックが終わるまでローディング状態が続く・・・などもできます。
上記のやり方が良いかは分かりませんが、これでやりたいことができるようになりました。
まとめ
今回初めて Angular を触ってみましたが、なるほど・・・自分のような素人でも、複雑なことをやろうとしなければ、SPA(シングルページアプリケーション)なんかはサクッと作れちゃう気がします。ngClass が本当に使い勝手が良いと思いました。あとは、ngIf なんかでフラグの状態でコードを出し分けたりとか、手軽にできてしまうのが本当に便利だなーと思いました。
面白いと思ったついでに色々と調べていたら、WordPressをDB代わりに使って遊ぶ・・・とかもできるっぽいじゃないですか!ちょっと楽しそうなので、今度その辺りを見てみたいですね!