目次
まえがき
最新版があります→https://mosapride.com/index.php/2017/07/06/post-392/
プロジェクトまるごとgithubにあげてあるので。→https://github.com/mosapride/angular-lean-dialog
標準のAngularでDialogを操作する資料が探しきれなかったのでAngular Materialを使用する。
プロジェクトの新規作成~ダイアログコンポーネントの作成~実行方法という手順で記述。
Materialのインストール方法とこれから作成するconfirm.components.ts、app.module.tsのコピペすれば他でも簡単に移行することができるように依存がないようにした。またcomponentはテンプレートをinner形式にしているので1ファイルに収めている。
環境とバージョン
- Angualr Material
- Angular 4
- Angular-cli
Angular(Angular-cli)がインストール済みと言う条件で新規プロジェクトから作成する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
ng -v _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ @angular/cli: 1.2.0 node: 6.11.0 os: win32 x64 @angular/animations: 4.2.5 @angular/common: 4.2.5 @angular/compiler: 4.2.5 @angular/core: 4.2.5 @angular/forms: 4.2.5 @angular/http: 4.2.5 @angular/material: 2.0.0-beta.7 @angular/platform-browser: 4.2.5 @angular/platform-browser-dynamic: 4.2.5 @angular/router: 4.2.5 @angular/cli: 1.2.0 @angular/compiler-cli: 4.2.5 @angular/language-service: 4.2.5 |
Dialogコンポーネントの作成
プロジェクト~npm install
新しいAngularプロジェクトの作成とMaterialを使用するための必要なパッケージをインストールする。
ng new コマンドを実行すると@angular/animationsがインストールされるが、Materialを実行するには最新の@angular/materialが必要なので明示的にnpm @angular/animationsをインストールする。これでバージョンが上がる。
Materialの機能をすべて使うにはhammerjsもインストールする必要があるが、ここでは省略する。
ちなみに、hammerjsはタッチジェスチャーを実装してくれるもので、Materialの機能にはmd-slide-toggle, md-slider, mdTooltipなどがあるためである。
1 2 3 4 5 6 |
ng new lean-angular-dialog cd lean-angular-dialog npm install --save @angular/material npm install --save @angular/animations |
Angular Materialの適用
FormModuleはinputを使用するため一緒に入れておく。
AngualrというよりシステムではForm系の操作が必須と言えるのでおまじないと思って入れてても良いはず。
1 2 3 |
import { FormsModule } from '@angular/forms'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MaterialModule } from '@angular/material'; |
DIする。依存性を注入のこと。説明できないぐらい理解もできていない。
1 2 3 4 5 6 |
imports: [ BrowserModule, FormsModule , BrowserAnimationsModule, MaterialModule ], |
index.htmlにMaterialのiconも入れておく。日々アイコンが増えているので後々役に立つかも。
1 |
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> |
index.htmlではなく.angular-cli.jsonにMaterialのスタイルシートを入れる。
index.htmlではnode_modulesファイルのパスが有効でないため、このように実装している。
indigo-pink.cssをコピペしてプロジェクト内に配置したり、style.cssに上書きする強引な手もあるかもしれない。
1 2 3 4 |
"styles": [ "../node_modules/@angular/material/prebuilt-themes/indigo-pink.css", "styles.css" ], |
ダイアログ(confirm)の作成
html、cssはインライン、specファイルは不要なのでオプションで作成しないようにする
1 |
ng g component dialog/confirm -it -is --spec false |
entryComponentsの追加。
ConfirmComponetはselectorを所持しない。たぶんentryComponentsはそういうときに書くもの。
ここらへんは勉強不足。
1 2 3 |
entryComponents: [ ConfirmComponent ], |
confirm.component.tsファイルを下記のようにする
いくつか注意する点として
上記でも記載しているがcomponentとして実装しているのにselectorが存在しない。
また、template内にあるボタンの配置は「cancel」、「ok」ボタンのことで標準では左よりに実装されている。
ダイアログの文字が多くなると不自然な気がして中央に実装している。
配置が左、中央、右のバージョンを作っているので好みに合わせてコメントイン&コメントアウトすればよい。
また、content(ダイアログの説明内容)は[innerHTML]で実装している。この理由としては使い方で説明する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import { Component, Optional, Inject, OnInit } from '@angular/core'; import { MdDialogRef, MD_DIALOG_DATA } from '@angular/material'; @Component({ template : ` <h1 md-dialog-title> <div style="display:flex; align-items :center"> <i class="material-icons" style="color : rgb(228,155,15)">help_outline</i>{{title}} </div> </h1> <md-dialog-content> <!-- https://angular.io/guide/template-syntax#!#property-binding-or-interpolation- --> <div [innerHTML]="content"></div> </md-dialog-content> <!-- ボタンの配置 --> <!-- <md-dialog-actions> --><!-- 左 left --> <md-dialog-actions style="justify-content:center"><!-- 中央 center --> <!-- <md-dialog-actions style="justify-content:flex-end"> --><!-- 右 right --> <button md-button [md-dialog-close]="'cancel'">cancel</button> <button md-button [md-dialog-close]="'ok'">OK</button> </md-dialog-actions> ` }) export class ConfirmComponent implements OnInit { public title: string; public content: string; constructor( @Inject(MD_DIALOG_DATA) public data: any, public dialogRef: MdDialogRef<ConfirmComponent> ) { } ngOnInit(): void { const config = this.data; this.title = config.title; this.content = config.content; } } |
使い方
サンプルプログラムの作成
使い方が分からなければ意味がないので、自動で作成されるapp.component.htmlとapp.component.tsをちょちょいと変更する。
といってもapp.component.htmlの中身を全部入れ替えればよいのさ
titleがダイアログのタイトル、contentがダイアログの内容。confirmReturnがダイアログのボタンの戻り値、あとボタンが3つ
button1はtitleとcontentを表示しダイアログの戻り値(押されたボタン)を素直に表示させる。
button2はtitleとcontentを表示しダイアログの戻り値(押されたボタン)を細工して表示させる。
button3はcontentにHTMLタグを使用したサンプル。title、contentは無視。
1 2 3 4 5 6 7 8 9 |
<p> title : <input [(ngModel)]='title' /><br> content : <input [(ngModel)]='content' /><br> <p> confirmReturn : {{confirmReturn}}<br> <button (click)='button1()'>button1</button> <button (click)='button2()'>button2</button> <button (click)='button3()'>PPAP</button> |
app.component.tsもすべて書き換える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import { ConfirmComponent } from './dialog/confirm/confirm.component'; import { Component, NgModule } from '@angular/core'; import { MdDialog, MdDialogConfig } from '@angular/material'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title: string; content: string; confirmReturn: string; constructor( private dialog: MdDialog ) { } button1() { const config = new MdDialogConfig(); config.data = { title: this.title, content: this.content } const ref = this.dialog.open(ConfirmComponent, config); ref.afterClosed().subscribe(rtn => this.confirmReturn = rtn); } button2() { const config = new MdDialogConfig(); config.data = { title: this.title, content: this.content } const ref = this.dialog.open(ConfirmComponent, config); ref.afterClosed().subscribe(rtn => { switch (rtn) { case 'ok': this.confirmReturn = '(*`・ω・)ゞOK '; break; case 'cancel': this.confirmReturn = '(´・ω・`) cance...'; break; default: this.confirmReturn = '(`ω´) undefined'; break; } }); } button3() { const config = new MdDialogConfig(); config.data = { title: 'PPAP', content: '<ul><li>i have a pen</li><li>i have an apple</li><li>ummm....</li><li><b>APPLE PEN!!!</b></li></ul>' } const ref = this.dialog.open(ConfirmComponent, config); ref.afterClosed().subscribe(rtn => this.confirmReturn = 'PPAP!!!!'); } } |
実行
angular-cliではおなじみのng serveで実行しlocalhost:4200にアクセス
1 |
ng serve |
titleとcontentに文字を入れbutton1を押すとDaialogが表示される。
cancelまたはokを押すとconfirmReturnが表示される。
「OK」を押すと、confirmReturnには「ok」が表示される。
これはただ単純にダイアログが閉じた時に発生する任意の戻り値を返しているだけであり、返す文字を変更するにはconfirm.componentsの[md-dialog-close]を変更すればよい。
そもそもconfirmが存在しないので戻り値がtrue、falseではない。
試してないけどobjectも返せるはず。
1 2 |
<button md-button [md-dialog-close]="'cancel'">cancel</button> <button md-button [md-dialog-close]="'ok'">OK</button> |
戻す値によって処理を変える必要があるのでbutton2ではswitchを使って処理を変更させている。
defaltはダイアログのボタン以外で閉じた場合に実行される(Escキー、ダイアログの外側をクリック)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
button2() { const config = new MdDialogConfig(); config.data = { title: this.title, content: this.content } const ref = this.dialog.open(ConfirmComponent, config); ref.afterClosed().subscribe(rtn => { switch (rtn) { case 'ok': this.confirmReturn = '(*`・ω・)ゞOK '; break; case 'cancel': this.confirmReturn = '(´・ω・`) cance...'; break; default: this.confirmReturn = '(`ω´) undefined'; break; } }); } |
ダイアログのコンテンツで改行やHTMLタグの使用を許可している。ただし使用できるタグはAngularの仕様となる。
詳しくはhttps://angular.io/guide/template-syntax#!#property-binding-or-interpolation-に記載されている。
scriptやXSS対策など行う必要はない。
PPAPボタンでHTMLタグを利用した例を用意している。
最後に
最初に記述したがAngular標準ではダイアログ機能は存在しないみたい。(たぶん)
component思考のためダイアログもcomponentの一つと考えられるので別で実装する必要性がないかもしれない。
作成したダイアログもcomponentだしね。
Angularを使っていて便利だなと実感できる場面が多いが、「これって使えないの?」という場面も多々ある。
jqueryも小細工しないと使えないみたいだし、その使い方にもクセがあるようだ(stackoverflowでみた)
過去の遺産は重宝するけど、ばっさり切り捨てる判断も必要かもしれない。