ウェブサイト検索

typescript - Angular 4 に対応したモーダルポップアップを作成する方法


ラジオボタンが選択されたときに、特定の自分のAngular 4コンポーネントを読み込むポップアップウィンドウを作成できるようにしたいです。

この質問への回答に挙げられている方法は、Angular 2としか互換性がないようです。

どこから始めればいいかわからず、どんな助けでもありがたいです!

回答 #1

承認された回答は、ハエをたたくために大きな依存関係を追加します。モーダル(およびモードレス)ダイアログは、主に1つか2つのCSSクラスの結果です。この「名前を変更...」の例を試してみてください:

1) 子モーダルがモーダルではなく、単に *ngIf が付いたインラインフォームであるかのように、親と子のモーダルを書きなさい。

<my-modal> 子を使用する親HTML:

<div>
    A div for {{name}}.
    <button type="button" (click)="showModal()">Rename</button>
    <my-modal *ngIf="showIt" [oldname]="name" (close)="closeModal($event)"></my-modal>
</div>

親クラス。@Component デコレーターは簡略化のため省略しています。(name プロパティは親クラスに属しており、フォームがそれを変更するものでなくても存在します。)

export class AppComponent {
    name = "old name";

    showIt = false;
    showModal() {
        this.showIt = true;
    }
    closeModal(newName: string) {
        this.showIt = false;
        if (newName) this.name = newName;
    }

}

子コンポーネント(モーダル用)。@Component デコレーターとインポートは再度省略されています。

export class MyModalComponent {
    @Input() oldname = "";
    @Output() close = new EventEmitter<string>();
    newname = "";

    ngOnInit() {
        // copy all inputs to avoid polluting them
        this.newname = this.oldname; 
    }

    ok() {
        this.close.emit(this.newname);
    }

    cancel() {
        this.close.emit(null);
    }
}

モーダル化する前の子HTML。

<div>
    Rename {{oldname}}
    <input type="text" (change)="newname = $event.target.value;" />
    <button type="button" (click)="ok()">OK</button>
    <button type="button" (click)="cancel()">Cancel</button>
</div>

2) こちらは child 用の CSS ですが、アプリ全体で再利用するためにグローバルなスタイルシートに配置することもできます。単一のクラス modal で、<div> 要素向けに作られています。

.modal {
    /* detach from rest of the document */
    position: fixed;

    /* center */
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);

    /* ensure in front of rest of page -- increase as needed */
    z-index: 1001;

    /* visual illusion of being in front -- alter to taste */
    box-shadow: rgba(0,0,0,0.4) 10px 10px 4px;

    /* visual illusion of being a solid object -- alter to taste */
    background-color: lightblue;
    border: 5px solid darkblue;

    /* visual preference of don't crowd the contents -- alter to taste */
    padding: 10px;
}

しかし、modal CSSクラスは、その下のページとのやり取りを防ぐことはできません。(つまり、技術的にはモードレスダイアログを作成することになります。)そのため、マウス操作を吸収して無視するために、モーダルの下にoverlayを置きます。overlayも<div>要素を意図しています。

.overlay {
    /* detach from document */
    position: fixed;

    /* ensure in front of rest of page except modal */
    z-index: 1000;

    /* fill screen to catch mice */
    top: 0;
    left: 0;
    width: 9999px;
    height: 9999px;

    /* dim screen 20% -- alter to taste */
    opacity: 0.2;
    background-color: black;
}

3) 子のHTMLでmodalとoverlayを使用します。

<div class="modal">
    Rename {{oldname}}
    <input type="text" (change)="newname = $event.target.value;" />
    <button type="button" (click)="ok()">OK</button>
    <button type="button" (click)="cancel()">Cancel</button>
</div>
<div class="overlay"></div>

以上です。基本的には2つのCSSクラスだけで、どんなコンポーネントでもモーダルにすることができます。実際、コンポーネントをインラインで表示するかモーダルとして表示するかは、ngClass や [class.modal]="showAsModalBoolean" を使ってCSSクラスの有無を変更するだけで実行時に切り替えることができます。

これを変更して、子コンポーネントが表示/非表示のロジックを制御できるようにすることができます。*ngIf、showIt、および show() 関数を子コンポーネントに移動します。親コンポーネントでは@ViewChild(MyModalComponent) renameModal: MyModalComponent;を追加し、その後親は命令的にthis.renameModal.show(this.name);を呼び出して、必要に応じて初期化や含まれるdivの再接続を行うことができます。

子モーダルは、上記のように親の関数に情報を返すこともできますし、子のshow()メソッドが代わりにコールバックを受け取ったり、好みに応じてPromiseを返したりすることもできます。

知っておくべきことが二つあります:

`this.renameModal.show(..);` は、`<my-modal>` に *ngIf がある場合は動作しません。なぜなら、そもそも関数を公開するためのコンポーネントが存在しないからです。*ngIf はコンポーネント全体(show() 関数も含む)を削除するため、もし何らかの理由でこれが必要な場合は代わりに `[hidden]` を使用してください。

モーダル同士はすべて同じ z-index を共有するため、z-index の問題が発生します。これは [style.z-index]="calculatedValue" のような方法で解決できます。

回答 #2

Angular Materialのダイアログを確認してください。こちらがPlunkerです

import {Component} from '@angular/core';
import {MdDialog, MdDialogRef} from '@angular/material';


@Component({
  selector: 'dialog-result-example',
  templateUrl: './dialog-result-example.html',
})
export class DialogResultExample {
  selectedOption: string;

  constructor(public dialog: MdDialog) {}

  openDialog() {
    let dialogRef = this.dialog.open(DialogResultExampleDialog);
    dialogRef.afterClosed().subscribe(result => {
      this.selectedOption = result;
    });
  }
}


@Component({
  selector: 'dialog-result-example-dialog',
  templateUrl: './dialog-result-example-dialog.html',
})
export class DialogResultExampleDialog {
  constructor(public dialogRef: MdDialogRef<DialogResultExampleDialog>) {}
}

関連記事