Caixa de diálogo Angular 2.0 e Modal


128

Estou tentando encontrar alguns exemplos sobre como fazer uma caixa de diálogo modal de confirmação no Angular 2.0. Eu tenho usado a caixa de diálogo Bootstrap para Angular 1.0 e não consigo encontrar nenhum exemplo na Web para Angular 2.0. Eu também verifiquei documentos angulares 2.0 sem sorte.

Existe uma maneira de usar a caixa de diálogo Bootstrap com o Angular 2.0?


Eu encontrei este exemplo. Talvez ele vai ajudar você angularscript.com/angular2-modal-window-with-bootstrap-style
Puya Sarmidani

1
Estou usando este com RC3 e conteúdo muito com ele: valor-software.com/ng2-bootstrap/#/modals
Mentat

Graças a @ Sam, tive um bom começo. No entanto, notei que o componente de chamada não sabe em qual botão foi clicado. Após algumas pesquisas, pude usar o Observables em vez do EventEmitters para encontrar uma solução mais elegante .
Jon


Respostas:


199
  • Angular 2 e superior
  • CSS de inicialização (a animação é preservada)
  • NO JQuery
  • NO bootstrap.js
  • Oferece suporte a conteúdo modal personalizado (assim como a resposta aceita)
  • Recentemente adicionado suporte para vários modais uns sobre os outros .

`

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

Para mostrar o pano de fundo , você precisará de algo como este CSS:

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

O exemplo agora permite vários modais ao mesmo tempo . (veja o onContainerClicked()método).

Para usuários do Bootstrap 4 css , é necessário fazer uma pequena alteração (porque um nome de classe css foi atualizado no Bootstrap 3). Esta linha: [ngClass]="{'in': visibleAnimate}"deve ser alterada para: [ngClass]="{'show': visibleAnimate}"

Para demonstrar, aqui está um plunkr


Há uma pegadinha embora. Como os botões estão dentro de um elemento extra aqui, o estilo de autoinicialização não aplicará margens aos botões (pelo menos na v4). remover o invólucro div.modal-footere alterar o .app-modal-footerpara .modal-footercorrigir isso.
Axel Köhler

55

Aqui está um exemplo bastante decente de como você pode usar o modal Bootstrap em um aplicativo Angular2 no GitHub .

O essencial é que você pode agrupar a inicialização html e jquery do bootstrap em um componente. Eu criei um modalcomponente reutilizável que permite ativar uma abertura usando uma variável de modelo.

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

Você só precisa instalar o pacote npm e registrar o módulo modal no seu módulo de aplicativo:

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

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

8
Bummer - confia no jquery como uma dependência :(
brando

52
Bem, sim, o bootstrap depende disso e eu não estou no negócio de reescrever bibliotecas.
Douglas Ludlow

2
Isso pode ser feito sem o jQuery. Usei a resposta de Sam junto com o tutorial em koscielniak.me/post/2016/03/angular2-confirm-dialog-component para escrever um serviço e o componente modal associado.
BeetleJuice

Se você não estiver usando o bootstrap em seu projeto, não se esqueça de adicionar um link ao bootstrap.css. A página do github esquece de mencionar isso.
Shekhar

46

Essa é uma abordagem simples que não depende do jquery ou de qualquer outra biblioteca, exceto a Angular 2. O componente abaixo (errorMessage.ts) pode ser usado como uma exibição filho de qualquer outro componente. É simplesmente um modal de autoinicialização sempre aberto ou exibido. Sua visibilidade é governada pela instrução 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>

Este é um exemplo de controle pai (algum código não relevante foi omitido por questões de brevidade):

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
bom - podia explicar #class="modal fade show in danger"
bensiu 14/07/2016

@bensiu Eu estou supondo que seletor de classe não é usada - a menos que tenham um estilo CSS seletores para todas aquelas palavras por exemplo 'em'
Drenai

Como você obtém o efeito fade in / out com isso?
Big McLargeHuge 24/10

10

Agora disponível como um pacote NPM

angular-custom-modal


@Stephen Paul continuação ...

  • CSS Bootstrap angular 2 e superior (a animação é preservada)
  • NO JQuery
  • NO bootstrap.js
  • Suporta conteúdo modal personalizado
  • Suporte para vários modais uns sobre os outros.
  • Moduralizado
  • Desativar rolagem quando modal estiver aberto
  • O modal é destruído ao navegar para longe.
  • Inicialização lenta de conteúdo, que é obtida ngOnDestroyquando o modal é encerrado.
  • Rolagem pai desativada quando modal estiver visível

Inicialização lenta de conteúdo

Por quê?

Em alguns casos, talvez você não deseje modal para manter seu status após ter sido fechado, mas restaurado para o estado inicial.

Edição modal original

Passar o conteúdo diretamente para a visualização na verdade gera inicializa-o antes mesmo que o modal o obtenha. O modal não tem como matar esse conteúdo, mesmo que esteja usando um *ngIfwrapper.

Solução

ng-template. ng-templatenão é processado até que seja solicitado.

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>

Referências

Devo dizer que não teria sido possível sem a excelente documentação oficial e da comunidade em torno da rede. Pode ajudar alguns de vocês demais para entender melhor como ng-template, *ngTemplateOutlete @ContentChildtrabalho.

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

Solução completa de copiar e colar

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

Eu uso o ngx-bootstrap para o meu projeto.

Você pode encontrar a demo aqui

O github é aqui

Como usar:

  1. Instale o ngx-bootstrap

  2. Importar para o seu módulo

// 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 estático simples
<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

Aqui está minha implementação completa do componente angular2 de auto-inicialização modal:

Suponho que no seu arquivo index.html principal (com <html>e <body>tags), na parte inferior da <body>tag, você tenha:

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

E exemplo de uso no componente Editor do cliente: 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>

Claro title, showClose, <mhead>e <mfoot>ar opcionais parâmetros / tags.


2
Em vez de bindModal(modal) {this._modal=modal;}, você pode usar do angular ViewChildanotação, assim: @ViewChild('editModal') _modal: Modal;. Ele lida com a ligação para você nos bastidores.
Douglas Ludlow


0

tente usar a ng-window, ele permitirá que o desenvolvedor abra e controle totalmente várias janelas em aplicativos de página única de maneira simples, sem jquery, sem bootstrap.

insira a descrição da imagem aqui

Configração Avilable

  • Janela Maxmize
  • Minimizar janela
  • Tamanho personalizado,
  • Posição personalizada
  • a janela é arrastável
  • Bloquear janela pai ou não
  • Centralize a janela ou não
  • Passar valores para a janela chield
  • Passar valores da janela chield para a janela pai
  • Ouvindo a janela de fechamento da janela principal na janela pai
  • Ouça o redimensionamento do evento com seu ouvinte personalizado
  • Aberto com tamanho máximo ou não
  • Ativar e desativar o redimensionamento de janelas
  • Ativar e desativar maximização
  • Ativar e desativar minimização

-1 Como isso é útil? Ele não atende a nenhum dos requisitos especificados pelo OP. Este é o quarto post. Vejo você trollando sua resposta!
quer

0

Angular 7 + NgBootstrap

Uma maneira simples de abrir o modal do componente principal e passar o resultado de volta para ele. é o que eu queria. Criei um tutorial passo a passo que inclui a criação de um novo projeto a partir do zero, a instalação do ngbootstrap e a criação do Modal. Você pode cloná-lo ou seguir o guia.

Espero que isso ajude de novo no Angular.!

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

Detalhes:

modelo modal-simples (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>

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

}

Demonstração (app.component.html) - maneira simples de lidar com o evento de retorno:

<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 é executado quando o modal é fechado:

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

Felicidades

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.