Boîte de dialogue angulaire 2.0 et modale


128

J'essaie de trouver des exemples sur la façon de faire une boîte de dialogue modale de confirmation dans Angular 2.0. J'utilise la boîte de dialogue Bootstrap pour Angular 1.0 et je ne trouve aucun exemple sur le Web pour Angular 2.0. J'ai également vérifié les documents angulaires 2.0 sans succès.

Existe-t-il un moyen d'utiliser la boîte de dialogue Bootstrap avec Angular 2.0?


J'ai trouvé cet exemple. Peut-être que cela vous aidera angularscript.com/angular2-modal-window-with-bootstrap-style
Puya Sarmidani

1
J'utilise celui-ci avec RC3 et je suis assez content avec: valor-software.com/ng2-bootstrap/#/modals
mentat

Grâce à @Sam, j'ai pris un bon départ. Cependant, j'ai remarqué que le composant appelant ne sait pas sur quel bouton on clique. Après quelques recherches, j'ai pu utiliser Observables au lieu d'EventEmitters pour proposer une solution plus élégante .
Jon


Réponses:


199
  • Angular 2 et plus
  • Bootstrap css (l'animation est préservée)
  • PAS DE JQuery
  • PAS de bootstrap.js
  • Prend en charge le contenu modal personnalisé (tout comme la réponse acceptée)
  • Prise en charge récemment ajoutée de plusieurs modaux les uns sur les autres .

»

@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();
    }
  }
}

Pour afficher la toile de fond , vous aurez besoin de quelque chose comme ce CSS:

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

L'exemple autorise désormais plusieurs modaux en même temps . (voir la onContainerClicked()méthode).

Pour les utilisateurs de Bootstrap 4 css , vous devez apporter une modification mineure (car un nom de classe css a été mis à jour à partir de Bootstrap 3). Cette ligne: [ngClass]="{'in': visibleAnimate}"doit être remplacée par: [ngClass]="{'show': visibleAnimate}"

Pour démontrer, voici un plunkr


Il y a un piège cependant. Parce que les boutons sont enveloppés dans un élément supplémentaire ici, le style bootstrap n'appliquera pas de marges aux boutons (au moins dans la v4). la suppression de l'emballage div.modal-footeret le changement .app-modal-footerde en .modal-footercorrige ce problème.
Axel Köhler

55

Voici un exemple assez décent de la façon dont vous pouvez utiliser le modal Bootstrap dans une application Angular2 sur GitHub .

L'essentiel est que vous pouvez envelopper l'initialisation bootstrap html et jquery dans un composant. J'ai créé un modalcomposant réutilisable qui vous permet de déclencher une ouverture à l'aide d'une variable de modèle.

<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>

Il vous suffit d'installer le package npm et d'enregistrer le module modal dans votre module d'application:

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

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

8
Bummer - s'appuie sur jquery comme dépendance :(
brando

52
Eh bien oui, bootstrap en dépend et je ne suis pas dans le métier de réécrire des bibliothèques.
Douglas Ludlow

2
Cela peut être fait sans jQuery. J'ai utilisé la réponse de Sam avec le tutoriel sur koscielniak.me/post/2016/03/angular2-confirm-dialog-component pour écrire un service et le composant modal associé.
BeetleJuice

Si vous n'utilisez pas bootstrap dans votre projet, n'oubliez pas d'ajouter un lien vers bootstrap.css. La page github oublie de mentionner cela.
Shekhar

46

C'est une approche simple qui ne dépend pas de jquery ou de toute autre bibliothèque sauf Angular 2. Le composant ci-dessous (errorMessage.ts) peut être utilisé comme vue enfant de tout autre composant. Il s'agit simplement d'un modal bootstrap qui est toujours ouvert ou affiché. Sa visibilité est régie par l'instruction ngIf.

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>

Ceci est un exemple de contrôle parent (certains codes non pertinents ont été omis par souci de concision):

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
nice - pourrait expliquerclass="modal fade show in danger"
bensiu

@bensiu Je suppose que le sélecteur de classe n'est pas utilisé - à moins qu'ils n'aient un sélecteur de style css pour tous ces mots, par exemple «in»
Drenai

Comment obtenez-vous l'effet de fondu entrant / sortant avec cela?
Big McLargeHuge

10

Maintenant disponible sous forme de package NPM

angulaire-personnalisé-modal


@Stephen Paul suite ...

  • Angular 2 et plus Bootstrap css (l'animation est préservée)
  • PAS DE JQuery
  • PAS de bootstrap.js
  • Prend en charge le contenu modal personnalisé
  • Prise en charge de plusieurs modaux les uns sur les autres.
  • Moduralisé
  • Désactiver le défilement lorsque modal est ouvert
  • Le modal est détruit lors de la navigation.
  • Initialisation du contenu paresseux, qui est ngOnDestroy(ed) lorsque le modal est quitté.
  • Défilement parent désactivé lorsque modal est visible

Initialisation du contenu paresseux

Pourquoi?

Dans certains cas, il se peut que vous ne souhaitiez pas que le mode modal conserve son état après avoir été fermé, mais plutôt restauré à l'état initial.

Problème modal d'origine

Passer le contenu directement dans la vue génère en fait l'initialisation avant même que le modal ne l'obtienne. Le modal n'a pas de moyen de tuer un tel contenu même en utilisant un *ngIfwrapper.

Solution

ng-template. ng-templatene rend pas jusqu'à ce qu'on lui ordonne de le faire.

mon-composant.module.ts

...
imports: [
  ...
  ModalModule
]

mon-composant.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>

Références

Je dois dire que cela n'aurait pas été possible sans l'excellente documentation officielle et communautaire sur le net. Il pourrait aider certains d' entre vous aussi de mieux comprendre comment ng-template, *ngTemplateOutletet le @ContentChildtravail.

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 -angulaire-896b0c689f6e

Solution complète de copier-coller

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

J'utilise ngx-bootstrap pour mon projet.

Vous pouvez trouver la démo ici

Le github est

Comment utiliser:

  1. Installez ngx-bootstrap

  2. Importez dans votre module

// 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. Modal statique simple
<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

Voici mon implémentation complète du composant modal bootstrap angular2:

Je suppose que dans votre fichier principal index.html (avec les balises <html>et <body>) au bas de la <body>balise, vous avez:

  <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>

Et exemple d'utilisation dans le composant de l'éditeur client: 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>

Ofcourse title, showClose, <mhead>et <mfoot>ar paramètres optionnels / tags.


2
Au lieu de bindModal(modal) {this._modal=modal;}, vous pouvez utiliser de angulaire ViewChildde l' annotation, comme suit: @ViewChild('editModal') _modal: Modal;. Il gère la reliure pour vous dans les coulisses.
Douglas Ludlow


0

essayez d'utiliser ng-window, cela permet au développeur d'ouvrir et de contrôler complètement plusieurs fenêtres dans des applications à une seule page de manière simple, sans Jquery, sans Bootstrap.

entrez la description de l'image ici

Configration disponible

  • Agrandir la fenêtre
  • Minimiser la fenêtre
  • Format personnalisé,
  • Position personnalisée
  • la fenêtre est déplaçable
  • Bloquer la fenêtre parent ou non
  • Centrer la fenêtre ou non
  • Passer les valeurs à la fenêtre de contrôle
  • Passer les valeurs de la fenêtre de champ à la fenêtre parente
  • Écouter la fermeture de la fenêtre chield dans la fenêtre parent
  • Écoutez pour redimensionner l'événement avec votre auditeur personnalisé
  • Ouvert avec une taille maximale ou non
  • Activer et désactiver le redimensionnement de la fenêtre
  • Activer et désactiver la maximisation
  • Activer et désactiver la minimisation

-1 En quoi est-ce utile du tout? Il ne répond à aucune des exigences spécifiées par le PO. C'est le 4e message que je vous vois troller votre réponse!
avn

0

Angulaire 7 + NgBootstrap

Un moyen simple d'ouvrir le modal du composant principal et de lui renvoyer le résultat. c'est ce que je voulais. J'ai créé un tutoriel étape par étape qui comprend la création d'un nouveau projet à partir de zéro, l'installation de ngbootstrap et la création de Modal. Vous pouvez soit le cloner, soit suivre le guide.

J'espère que cela aide nouveau à Angular.!

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

Détails:

modèle modal-simple (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>

Le 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() {
  }

}

Démo de celui-ci (app.component.html) - moyen simple de gérer l'événement de retour:

<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 est exécuté une fois le modal fermé:

@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;
  }    
}

À votre santé

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.