Angular 2.0 e finestra di dialogo modale


128

Sto cercando di trovare alcuni esempi su come eseguire una finestra di dialogo modale di conferma in Angular 2.0. Ho usato la finestra di dialogo Bootstrap per Angular 1.0 e non sono riuscito a trovare alcun esempio nel web per Angular 2.0. Ho anche controllato i documenti angolari 2.0 senza fortuna.

C'è un modo per utilizzare la finestra di dialogo Bootstrap con Angular 2.0?


Ho trovato questo esempio. Forse vi aiuterà a angularscript.com/angular2-modal-window-with-bootstrap-style
Puya Sarmidani

1
Sto usando questo con RC3 e abbastanza contenuti con esso: valor-software.com/ng2-bootstrap/#/modals
mentat

Grazie a @Sam, ho iniziato bene. Tuttavia, ho notato che il componente chiamante non sa quale pulsante viene cliccato. Dopo alcune ricerche, sono stato in grado di utilizzare Observables anziché EventEmitters per trovare una soluzione più elegante .
Jon,


Risposte:


199
  • Angolare 2 e fino
  • Bootstrap css (l'animazione è preservata)
  • NO JQuery
  • NO bootstrap.js
  • Supporta contenuti modali personalizzati (proprio come la risposta accettata)
  • Aggiunto di recente il supporto per più modali uno sopra l'altro .

`

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

Per mostrare lo sfondo , avrai bisogno di qualcosa come questo CSS:

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

L'esempio ora consente più modali contemporaneamente . (vedi il onContainerClicked()metodo).

Per gli utenti di Bootstrap 4 css , è necessario apportare 1 modifica minore (poiché un nome di classe css è stato aggiornato da Bootstrap 3). Questa riga: [ngClass]="{'in': visibleAnimate}"deve essere modificata in: [ngClass]="{'show': visibleAnimate}"

Per dimostrare, ecco un plunkr


C'è un gotcha però. Poiché i pulsanti sono racchiusi in un elemento aggiuntivo qui, lo stile bootstrap non applicherà margini ai pulsanti (almeno in v4). rimuovendo il wrapping div.modal-footere cambiando in .app-modal-footerper .modal-footerrisolvere questo problema.
Axel Köhler,

55

Ecco un esempio abbastanza decente di come utilizzare Bootstrap modale all'interno di un'app Angular2 su GitHub .

L'essenza è che puoi avvolgere il bootstrap html e l'inizializzazione jquery in un componente. Ho creato un modalcomponente riutilizzabile che ti consente di attivare un'apertura utilizzando una variabile modello.

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

Devi solo installare il pacchetto npm e registrare il modulo modale nel modulo dell'app:

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

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

8
Peccato - fa affidamento su jquery come dipendenza :(
brando

52
Bene sì, bootstrap si basa su di esso e non mi occupo di riscrivere le librerie.
Douglas Ludlow,

2
Questo può essere fatto senza jQuery. Ho usato la risposta di Sam insieme al tutorial su koscielniak.me/post/2016/03/angular2-confirm-dialog-component per scrivere un servizio e il componente modale associato.
BeetleJuice,

Se non si utilizza bootstrap nel progetto, non dimenticare di aggiungere il collegamento a bootstrap.css. La pagina di github dimentica di menzionarlo.
Shekhar,

46

Questo è un approccio semplice che non dipende da jquery o da qualsiasi altra libreria tranne Angular 2. Il componente in basso (errorMessage.ts) può essere usato come vista figlio di qualsiasi altro componente. È semplicemente un bootstrap modale che è sempre aperto o mostrato. La visibilità è regolata dall'istruzione 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>

Questo è un esempio di controllo parent (alcuni codici non rilevanti sono stati omessi per brevità):

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
bello - potrebbe spiegareclass="modal fade show in danger"
bensiu

@bensiu Immagino che il selettore di classe non sia usato - a meno che non abbiano un selettore di stile CSS per tutte quelle parole, ad esempio "in"
Drenai,

Come si ottiene l'effetto dissolvenza in / out con questo?
Big McLarge: enorme

10

Ora disponibile come pacchetto NPM

angolare-custom-modale


@Stephen Paul continuation ...

  • Angular 2 e versioni successive Bootstrap css (l'animazione è preservata)
  • NO JQuery
  • NO bootstrap.js
  • Supporta contenuti modali personalizzati
  • Supporto per più modali uno sopra l'altro.
  • Moduralized
  • Disabilita lo scorrimento quando modale è aperto
  • Modale viene distrutto durante la navigazione.
  • Inizializzazione del contenuto pigro, che ottiene ngOnDestroy (modificata) all'uscita dal modale.
  • Lo scorrimento dei genitori è disabilitato quando è visibile modale

Inizializzazione del contenuto pigro

Perché?

In alcuni casi potresti non voler modale per conservare il suo stato dopo essere stato chiuso, ma piuttosto ripristinato allo stato iniziale.

Problema modale originale

Passare il contenuto direttamente nella vista in realtà genera inizializzarlo anche prima che il modale lo ottenga. Il modale non ha modo di uccidere tali contenuti anche se si utilizza a*ngIf wrapper.

Soluzione

ng-template. ng-templatenon esegue il rendering fino a quando non viene ordinato di farlo.

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>

Riferimenti

Devo dire che non sarebbe stato possibile senza l'eccellente documentazione ufficiale e comunitaria in rete. Potrebbe aiutare anche alcuni di voi a capire meglio come ng-template, *ngTemplateOutlete@ContentChild il lavoro.

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

Soluzione completa per copia e incolla

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

Uso ngx-bootstrap per il mio progetto.

Puoi trovare la demo qui

Il github è qui

Come usare:

  1. Installa ngx-bootstrap

  2. Importa nel tuo modulo

// 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. Modale statico semplice
<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

Ecco la mia completa implementazione del componente angolare2 modale bootstrap:

Presumo che nel tuo file index.html principale (con <html>e <body>tag) nella parte inferiore del <body>tag hai:

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

Ed esempio di utilizzo nel componente Editor 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>

Naturalmente title, showClose, <mhead>e <mfoot>ar opzionali parametri / tags.


2
Invece di bindModal(modal) {this._modal=modal;}, puoi usare gli angolariViewChild annotazione, in questo modo: @ViewChild('editModal') _modal: Modal;. Gestisce la rilegatura per te dietro le quinte.
Douglas Ludlow,


0

prova a usare ng-window, consente allo sviluppatore di aprire e controllare completamente più finestre in applicazioni a pagina singola in modo semplice, No Jquery, No Bootstrap.

inserisci qui la descrizione dell'immagine

Configrazione disponibile

  • Finestra Maxmize
  • Riduci a icona la finestra
  • Formato personalizzato,
  • Posizione personalizzata
  • la finestra è trascinabile
  • Blocca la finestra padre o meno
  • Centra la finestra o no
  • Passa i valori alla finestra di chield
  • Passa i valori dalla finestra chield alla finestra parent
  • Ascoltare la chiusura della finestra chield nella finestra principale
  • Ascolta il ridimensionamento dell'evento con il tuo listener personalizzato
  • Apri con dimensioni massime o meno
  • Abilita e disabilita il ridimensionamento delle finestre
  • Abilita e disabilita la massimizzazione
  • Abilita e disabilita la minimizzazione

-1 Come è utile? Non soddisfa nessuno dei requisiti specificati dall'OP. Questo è il quarto post che ti vedo trollare la tua risposta!
dal

0

Angular 7 + NgBootstrap

Un modo semplice per aprire modale dal componente principale e restituire il risultato ad esso. è quello che volevo. Ho creato un tutorial passo-passo che include la creazione da zero di un nuovo progetto, l'installazione di ngbootstrap e la creazione di Modal. Puoi clonarlo o seguire la guida.

Spero che questo aiuti di nuovo ad Angular.!

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

Dettagli:

modello modale-semplice (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>

Il 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 di esso (app.component.html) - modo semplice di gestire l'evento di ritorno:

<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 viene eseguito una volta chiuso modale:

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

Saluti

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.