Angular 2.0 und Modal Dialog


128

Ich versuche einige Beispiele zu finden, wie ein modaler Bestätigungsdialog in Angular 2.0 erstellt wird. Ich habe das Bootstrap-Dialogfeld für Angular 1.0 verwendet und konnte im Web keine Beispiele für Angular 2.0 finden. Ich habe auch eckige 2.0-Dokumente ohne Glück überprüft.

Gibt es eine Möglichkeit, den Bootstrap-Dialog mit Angular 2.0 zu verwenden?


Ich habe dieses Beispiel gefunden. Vielleicht hilft es Ihnen angularscript.com/angular2-modal-window-with-bootstrap-style
Puya Sarmidani

1
Ich benutze dieses mit RC3 und ziemlich zufrieden damit: valor-software.com/ng2-bootstrap/#/modals
mentat

Dank @Sam habe ich einen guten Start hingelegt. Ich habe jedoch festgestellt, dass die aufrufende Komponente nicht weiß, auf welche Schaltfläche geklickt wird. Nach einigen Recherchen konnte ich Observables anstelle von EventEmitters verwenden, um eine elegantere Lösung zu finden .
Jon


Antworten:


199
  • Winkel 2 und höher
  • Bootstrap CSS (Animation bleibt erhalten)
  • KEINE JQuery
  • KEINE bootstrap.js
  • Unterstützt benutzerdefinierte modale Inhalte (genau wie akzeptierte Antworten)
  • Kürzlich wurde die Unterstützung für mehrere übereinanderliegende Modalitäten hinzugefügt .

`

@Component({
  selector: 'app-component',
  template: `
  <button type="button" (click)="modal.show()">test</button>
  <app-modal #modal>
    <div class="app-modal-header">
      header
    </div>
    <div class="app-modal-body">
      Whatever content you like, form fields, anything
    </div>
    <div class="app-modal-footer">
      <button type="button" class="btn btn-default" (click)="modal.hide()">Close</button>
      <button type="button" class="btn btn-primary">Save changes</button>
    </div>
  </app-modal>
  `
})
export class AppComponent {
}

@Component({
  selector: 'app-modal',
  template: `
  <div (click)="onContainerClicked($event)" class="modal fade" tabindex="-1" [ngClass]="{'in': visibleAnimate}"
       [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <ng-content select=".app-modal-header"></ng-content>
        </div>
        <div class="modal-body">
          <ng-content select=".app-modal-body"></ng-content>
        </div>
        <div class="modal-footer">
          <ng-content select=".app-modal-footer"></ng-content>
        </div>
      </div>
    </div>
  </div>
  `
})
export class ModalComponent {

  public visible = false;
  public visibleAnimate = false;

  public show(): void {
    this.visible = true;
    setTimeout(() => this.visibleAnimate = true, 100);
  }

  public hide(): void {
    this.visibleAnimate = false;
    setTimeout(() => this.visible = false, 300);
  }

  public onContainerClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('modal')) {
      this.hide();
    }
  }
}

Um den Hintergrund zu zeigen , benötigen Sie so etwas wie dieses CSS:

.modal {
  background: rgba(0,0,0,0.6);
}

Das Beispiel erlaubt jetzt mehrere Modalitäten gleichzeitig . (siehe die onContainerClicked()Methode).

Für Bootstrap 4-CSS-Benutzer müssen Sie eine geringfügige Änderung vornehmen (da ein CSS-Klassenname von Bootstrap 3 aktualisiert wurde). Diese Zeile: [ngClass]="{'in': visibleAnimate}"sollte geändert werden in: [ngClass]="{'show': visibleAnimate}"

Um zu demonstrieren, hier ist ein Plunkr


Es gibt aber eine Gotcha. Da die Schaltflächen hier in ein zusätzliches Element eingeschlossen sind, werden beim Bootstrap-Stil keine Ränder auf die Schaltflächen angewendet (zumindest in Version 4). Entfernen Sie die Verpackung div.modal-footerund ändern Sie die, .app-modal-footerum .modal-footerdies zu beheben.
Axel Köhler

55

Hier ist ein ziemlich anständiges Beispiel dafür, wie Sie das Bootstrap-Modal in einer Angular2-App auf GitHub verwenden können .

Das Wesentliche dabei ist, dass Sie die Bootstrap-HTML- und JQuery-Initialisierung in eine Komponente einbinden können. Ich habe eine wiederverwendbare modalKomponente erstellt, mit der Sie mithilfe einer Vorlagenvariablen ein Öffnen auslösen können.

<button type="button" class="btn btn-default" (click)="modal.open()">Open me!</button>

<modal #modal>
    <modal-header [show-close]="true">
        <h4 class="modal-title">I'm a modal!</h4>
    </modal-header>
    <modal-body>
        Hello World!
    </modal-body>
    <modal-footer [show-default-buttons]="true"></modal-footer>
</modal>

Sie müssen nur das npm-Paket installieren und das Modalmodul in Ihrem App-Modul registrieren:

import { Ng2Bs3ModalModule } from 'ng2-bs3-modal/ng2-bs3-modal';

@NgModule({
    imports: [Ng2Bs3ModalModule]
})
export class MyAppModule {}

8
Schade - verlässt sich auf jquery als Abhängigkeit :(
brando

52
Nun ja, Bootstrap verlässt sich darauf und ich bin nicht im Geschäft, Bibliotheken neu zu schreiben.
Douglas Ludlow

2
Dies kann ohne jQuery erfolgen. Ich habe Sams Antwort zusammen mit dem Tutorial unter koscielniak.me/post/2016/03/angular2-confirm-dialog-component verwendet , um einen Dienst und die zugehörige modale Komponente zu schreiben.
BeetleJuice

Wenn Sie in Ihrem Projekt kein Bootstrap verwenden, vergessen Sie nicht, einen Link zu bootstrap.css hinzuzufügen. Die Github-Seite vergisst, dies zu erwähnen.
Shekhar

46

Dies ist ein einfacher Ansatz, der nicht von jquery oder einer anderen Bibliothek außer Angular 2 abhängt. Die folgende Komponente (errorMessage.ts) kann als untergeordnete Ansicht einer anderen Komponente verwendet werden. Es ist einfach ein Bootstrap-Modal, das immer geöffnet oder angezeigt wird. Die Sichtbarkeit wird durch die ngIf-Anweisung bestimmt.

errorMessage.ts

import { Component } from '@angular/core';
@Component({
    selector: 'app-error-message',
    templateUrl: './app/common/errorMessage.html',
})
export class ErrorMessage
{
    private ErrorMsg: string;
    public ErrorMessageIsVisible: boolean;

    showErrorMessage(msg: string)
    {
        this.ErrorMsg = msg;
        this.ErrorMessageIsVisible = true;
    }

    hideErrorMsg()
    {
        this.ErrorMessageIsVisible = false;
    }
}

errorMessage.html

<div *ngIf="ErrorMessageIsVisible" class="modal fade show in danger" id="myModal" role="dialog">
    <div class="modal-dialog">

        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                <h4 class="modal-title">Error</h4>
            </div>
            <div class="modal-body">
                <p>{{ErrorMsg}}</p>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" (click)="hideErrorMsg()">Close</button>
            </div>
        </div>
    </div>
</div>

Dies ist ein Beispiel für ein übergeordnetes Steuerelement (einige nicht relevante Codes wurden der Kürze halber weggelassen):

parent.ts

import { Component, ViewChild } from '@angular/core';
import { NgForm } from '@angular/common';
import {Router, RouteSegment, OnActivate, ROUTER_DIRECTIVES } from '@angular/router';
import { OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';


@Component({
    selector: 'app-application-detail',
    templateUrl: './app/permissions/applicationDetail.html',
    directives: [ROUTER_DIRECTIVES, ErrorMessage]  // Note ErrorMessage is a directive
})
export class ApplicationDetail implements OnActivate
{
    @ViewChild(ErrorMessage) errorMsg: ErrorMessage;  // ErrorMessage is a ViewChild



    // yada yada


    onSubmit()
    {
        let result = this.permissionsService.SaveApplication(this.Application).subscribe(x =>
        {
            x.Error = true;
            x.Message = "This is a dummy error message";

            if (x.Error) {
                this.errorMsg.showErrorMessage(x.Message);
            }
            else {
                this.router.navigate(['/applicationsIndex']);
            }
        });
    }

}

parent.html

<app-error-message></app-error-message>
// your html...

3
schön - könnte erklärenclass="modal fade show in danger"
Bensiu

@bensiu Ich vermute, dass die Klassenauswahl nicht verwendet wird - es sei denn, sie haben einen CSS-Stil-Selektor für all diese Wörter, zB 'in'
Drenai

Wie kommt man damit zum Ein- / Ausblenden?
Big McLargeHuge

10

Jetzt als NPM-Paket erhältlich

eckig-kundenspezifisch-modal


@ Stephen Paul Fortsetzung ...

  • Angular 2 und höher Bootstrap CSS (Animation bleibt erhalten)
  • KEINE JQuery
  • KEINE bootstrap.js
  • Unterstützt benutzerdefinierte modale Inhalte
  • Unterstützung für mehrere übereinanderliegende Modalitäten.
  • Modalisiert
  • Deaktivieren Sie den Bildlauf, wenn Modal geöffnet ist
  • Modal wird beim Wegnavigieren zerstört.
  • Lazy Content Initialisierung, die ngOnDestroybeim Beenden des Modals (ed) wird.
  • Übergeordnetes Scrollen deaktiviert, wenn Modal sichtbar ist

Lazy Content Initialisierung

Warum?

In einigen Fällen möchten Sie möglicherweise nicht modal arbeiten, um den Status nach dem Schließen beizubehalten, sondern den ursprünglichen Zustand wiederherstellen.

Ursprüngliche modale Ausgabe

Wenn Sie den Inhalt direkt in die Ansicht übergeben, wird er tatsächlich initialisiert, noch bevor das Modal ihn erhält. Das Modal hat keine Möglichkeit, solche Inhalte zu töten, selbst wenn ein *ngIfWrapper verwendet wird.

Lösung

ng-template. ng-templatewird erst gerendert, wenn Sie dazu aufgefordert werden.

my-component.module.ts

...
imports: [
  ...
  ModalModule
]

my-component.ts

<button (click)="reuseModal.open()">Open</button>
<app-modal #reuseModal>
  <ng-template #header></ng-template>
  <ng-template #body>
    <app-my-body-component>
      <!-- This component will be created only when modal is visible and will be destroyed when it's not. -->
    </app-my-body-content>
    <ng-template #footer></ng-template>
</app-modal>

modal.component.ts

export class ModalComponent ... {
  @ContentChild('header') header: TemplateRef<any>;
  @ContentChild('body') body: TemplateRef<any>;
  @ContentChild('footer') footer: TemplateRef<any>;
 ...
}

modal.component.html

<div ... *ngIf="visible">
  ...
  <div class="modal-body">
    ng-container *ngTemplateOutlet="body"></ng-container>
  </div>

Verweise

Ich muss sagen, dass es ohne die exzellente offizielle und Community-Dokumentation im Internet nicht möglich gewesen wäre. Es könnte einige von euch helfen zu verstehen besser , wie ng-template, *ngTemplateOutletund @ContentChildArbeit.

https://angular.io/api/common/NgTemplateOutlet
https://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet/
https://medium.com/claritydesignsystem/ng-content -the-hidden-docs-96a29d70d11b
https://netbasal.com/understanding-viewchildren-contentchildren-and-querylist-in-angular-896b0c689f6e
https://netbasal.com/understanding-viewchildren-contentchildren-and-querylist-in -angular-896b0c689f6e

Vollständige Copy-Paste-Lösung

modal.component.html

<div
  (click)="onContainerClicked($event)"
  class="modal fade"
  tabindex="-1"
  [ngClass]="{'in': visibleAnimate}"
  [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}"
  *ngIf="visible">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <ng-container *ngTemplateOutlet="header"></ng-container>
        <button class="close" data-dismiss="modal" type="button" aria-label="Close" (click)="close()">×</button>
      </div>
      <div class="modal-body">
        <ng-container *ngTemplateOutlet="body"></ng-container>
      </div>
      <div class="modal-footer">
        <ng-container *ngTemplateOutlet="footer"></ng-container>
      </div>
    </div>
  </div>
</div>

modal.component.ts

/**
 * @Stephen Paul https://stackoverflow.com/a/40144809/2013580
 * @zurfyx https://stackoverflow.com/a/46949848/2013580
 */
import { Component, OnDestroy, ContentChild, TemplateRef } from '@angular/core';

@Component({
  selector: 'app-modal',
  templateUrl: 'modal.component.html',
  styleUrls: ['modal.component.scss'],
})
export class ModalComponent implements OnDestroy {
  @ContentChild('header') header: TemplateRef<any>;
  @ContentChild('body') body: TemplateRef<any>;
  @ContentChild('footer') footer: TemplateRef<any>;

  public visible = false;
  public visibleAnimate = false;

  ngOnDestroy() {
    // Prevent modal from not executing its closing actions if the user navigated away (for example,
    // through a link).
    this.close();
  }

  open(): void {
    document.body.style.overflow = 'hidden';

    this.visible = true;
    setTimeout(() => this.visibleAnimate = true, 200);
  }

  close(): void {
    document.body.style.overflow = 'auto';

    this.visibleAnimate = false;
    setTimeout(() => this.visible = false, 100);
  }

  onContainerClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('modal')) {
      this.close();
    }
  }
}

modal.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { ModalComponent } from './modal.component';

@NgModule({
  imports: [
    CommonModule,
  ],
  exports: [ModalComponent],
  declarations: [ModalComponent],
  providers: [],
})
export class ModalModule { }

7

Ich benutze ngx-bootstrap für mein Projekt.

Die Demo finden Sie hier

Der Github ist hier

Wie benutzt man:

  1. Installieren Sie ngx-bootstrap

  2. In Ihr Modul importieren

// RECOMMENDED (doesn't work with system.js)
import { ModalModule } from 'ngx-bootstrap/modal';
// or
import { ModalModule } from 'ngx-bootstrap';

@NgModule({
  imports: [ModalModule.forRoot(),...]
})
export class AppModule(){}
  1. Einfaches statisches Modal
<button type="button" class="btn btn-primary" (click)="staticModal.show()">Static modal</button>
<div class="modal fade" bsModal #staticModal="bs-modal" [config]="{backdrop: 'static'}"
tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
   <div class="modal-content">
      <div class="modal-header">
         <h4 class="modal-title pull-left">Static modal</h4>
         <button type="button" class="close pull-right" aria-label="Close" (click)="staticModal.hide()">
         <span aria-hidden="true">&times;</span>
         </button>
      </div>
      <div class="modal-body">
         This is static modal, backdrop click will not close it.
         Click <b>&times;</b> to close modal.
      </div>
   </div>
</div>
</div>

4

Hier ist meine vollständige Implementierung der modalen Bootstrap Angular2-Komponente:

Ich gehe davon aus, dass Sie in Ihrer index.html-Hauptdatei (mit <html>und <body>Tags) am Ende des <body>Tags Folgendes haben:

  <script src="assets/js/jquery-2.1.1.js"></script>
  <script src="assets/js/bootstrap.min.js"></script>

modal.component.ts:

import { Component, Input, Output, ElementRef, EventEmitter, AfterViewInit } from '@angular/core';

declare var $: any;// this is very importnant (to work this line: this.modalEl.modal('show')) - don't do this (becouse this owerride jQuery which was changed by bootstrap, included in main html-body template): let $ = require('../../../../../node_modules/jquery/dist/jquery.min.js');

@Component({
  selector: 'modal',
  templateUrl: './modal.html',
})
export class Modal implements AfterViewInit {

    @Input() title:string;
    @Input() showClose:boolean = true;
    @Output() onClose: EventEmitter<any> = new EventEmitter();

    modalEl = null;
    id: string = uniqueId('modal_');

    constructor(private _rootNode: ElementRef) {}

    open() {
        this.modalEl.modal('show');
    }

    close() {
        this.modalEl.modal('hide');
    }

    closeInternal() { // close modal when click on times button in up-right corner
        this.onClose.next(null); // emit event
        this.close();
    }

    ngAfterViewInit() {
        this.modalEl = $(this._rootNode.nativeElement).find('div.modal');
    }

    has(selector) {
        return $(this._rootNode.nativeElement).find(selector).length;
    }
}

let modal_id: number = 0;
export function uniqueId(prefix: string): string {
    return prefix + ++modal_id;
}

modal.html:

<div class="modal inmodal fade" id="{{modal_id}}" tabindex="-1" role="dialog"  aria-hidden="true" #thisModal>
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header" [ngClass]="{'hide': !(has('mhead') || title) }">
                <button *ngIf="showClose" type="button" class="close" (click)="closeInternal()"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                <ng-content select="mhead"></ng-content>
                <h4 *ngIf='title' class="modal-title">{{ title }}</h4>
            </div>
            <div class="modal-body">
                <ng-content></ng-content>
            </div>

            <div class="modal-footer" [ngClass]="{'hide': !has('mfoot') }" >
                <ng-content select="mfoot"></ng-content>
            </div>
        </div>
    </div>
</div>

Ein Beispiel für die Verwendung in der Client-Editor-Komponente: client-edit-component.ts:

import { Component } from '@angular/core';
import { ClientService } from './client.service';
import { Modal } from '../common';

@Component({
  selector: 'client-edit',
  directives: [ Modal ],
  templateUrl: './client-edit.html',
  providers: [ ClientService ]
})
export class ClientEdit {

    _modal = null;

    constructor(private _ClientService: ClientService) {}

    bindModal(modal) {this._modal=modal;}

    open(client) {
        this._modal.open();
        console.log({client});
    }

    close() {
        this._modal.close();
    }

}

client-edit.html:

<modal [title]='"Some standard title"' [showClose]='true' (onClose)="close()" #editModal>{{ bindModal(editModal) }}
    <mhead>Som non-standart title</mhead>
    Some contents
    <mfoot><button calss='btn' (click)="close()">Close</button></mfoot>
</modal>

Natuerlich title, showClose, <mhead>und <mfoot>ar optionale Parameter / Tags.


2
Stattdessen bindModal(modal) {this._modal=modal;}können Sie die ViewChildAnnotation von Angular wie folgt verwenden : @ViewChild('editModal') _modal: Modal;. Es übernimmt die Bindung für Sie hinter den Kulissen.
Douglas Ludlow


0

Wenn Sie versuchen, ng-window zu verwenden, können Entwickler auf einfache Weise mehrere Fenster in Anwendungen mit nur einer Seite öffnen und vollständig steuern. No Jquery, No Bootstrap.

Geben Sie hier die Bildbeschreibung ein

Verfügbare Konfigration

  • Fenster maximieren
  • Fenster minimieren
  • Benutzerdefiniertes Format,
  • Benutzerdefinierte Position
  • Das Fenster ist ziehbar
  • Übergeordnetes Fenster blockieren oder nicht
  • Fenster zentrieren oder nicht
  • Übergeben Sie Werte an das Chield-Fenster
  • Übergeben Sie Werte vom Chield-Fenster an das übergeordnete Fenster
  • Hören Sie sich das Schließen des Chield-Fensters im übergeordneten Fenster an
  • Hören Sie zu, um die Größe des Ereignisses mit Ihrem benutzerdefinierten Listener zu ändern
  • Mit maximaler Größe öffnen oder nicht
  • Aktivieren und Deaktivieren der Fenstergrößenänderung
  • Aktivieren und deaktivieren Sie die Maximierung
  • Aktivieren und deaktivieren Sie die Minimierung

-1 Wie ist das überhaupt nützlich? Es werden keine der vom OP festgelegten Anforderungen erfüllt. Dies ist der 4. Beitrag, in dem du deine Antwort trollst!
Avn

0

Winkel 7 + NgBootstrap

Eine einfache Möglichkeit, das Modal von der Hauptkomponente zu öffnen und das Ergebnis an diese zurückzugeben. ist was ich wollte. Ich habe eine Schritt-für-Schritt-Anleitung erstellt, die das Erstellen eines neuen Projekts von Grund auf, das Installieren von ngbootstrap und das Erstellen von Modal umfasst. Sie können es entweder klonen oder der Anleitung folgen.

Hoffe das hilft neu bei Angular.!

https://github.com/wkaczurba/modal-demo

Einzelheiten:

modal-simple-Vorlage (modal-simple.component.html):

<ng-template #content let-modal>
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Are you sure?</h4>
    <button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <p>You have not finished reading my code. Are you sure you want to close?</p>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('yes')">Yes</button>
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('no')">No</button>
  </div>
</ng-template>

Die modal-simple.component.ts:

import { Component, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-modal-simple',
  templateUrl: './modal-simple.component.html',
  styleUrls: ['./modal-simple.component.css']
})
export class ModalSimpleComponent implements OnInit {
  @ViewChild('content') content;
  @Output() result : EventEmitter<string> = new EventEmitter();

  constructor(private modalService : NgbModal) { }

  open() {
    this.modalService.open(this.content, {ariaLabelledBy: 'modal-simple-title'})
      .result.then((result) => { console.log(result as string); this.result.emit(result) }, 
        (reason) => { console.log(reason as string); this.result.emit(reason) })
  }

  ngOnInit() {
  }

}

Demo davon (app.component.html) - einfache Möglichkeit, mit Rückgabeereignissen umzugehen:

<app-modal-simple #mymodal (result)="onModalClose($event)"></app-modal-simple>
<button (click)="mymodal.open()">Open modal</button>

<p>
Result is {{ modalCloseResult }}
</p>

app.component.ts - onModalClosed wird ausgeführt, sobald modal geschlossen wird:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  modalCloseResult : string;
  title = 'modal-demo';

  onModalClose(reason : string) {
    this.modalCloseResult = reason;
  }    
}

Prost

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.