modal-dialog - create - modales angular 2
Angular 2.0 y diálogo modal (9)
Ahora disponible como paquete NPM
@Stephen Paul continuation ...
- Angular 2 y más Bootstrap css (se conserva la animación)
- NO JQuery
- NO bootstrap.js
- Admite contenido modal personalizado
- Soporte para múltiples modales uno encima del otro.
- Moduralizado
- Deshabilitar desplazamiento cuando modal está abierto
- El modal se destruye cuando se aleja.
-
Inicialización de contenido
ngOnDestroy
, que obtienengOnDestroy
(ed) cuando sengOnDestroy
del modal. - Desplazamiento principal deshabilitado cuando modal es visible
Inicialización de contenido diferido
¿Por qué?
En algunos casos, es posible que no desee modal para retener su estado después de haber sido cerrado, sino más bien restaurado al estado inicial.
Problema modal original
Pasar el contenido directamente a la vista en realidad genera lo inicializa incluso antes de que el modal lo obtenga.
El modal no tiene una forma de eliminar dicho contenido incluso si se usa un contenedor
*ngIf
.
Solución
ng-template
.
ng-template
no se procesa hasta que se le ordena hacerlo.
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>
Referencias
Tengo que decir que no hubiera sido posible sin la excelente documentación oficial y comunitaria de la red.
También podría ayudar a algunos de ustedes comprender mejor cómo funcionan
ng-template
,
*ngTemplateOutlet
y
@ContentChild
.
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
Solución completa de copiar y pegar
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 { }
Estoy tratando de encontrar algunos ejemplos sobre cómo hacer un diálogo modal de Confirmación en Angular 2.0. He estado usando el diálogo Bootstrap para Angular 1.0 y no pude encontrar ningún ejemplo en la web para Angular 2.0. También revisé los documentos angulares 2.0 sin suerte.
¿Hay alguna manera de usar el diálogo Bootstrap con Angular 2.0?
Aquí está mi implementación completa del componente modal2 bootstrap angular2:
Supongo que en su archivo index.html principal (con las etiquetas
<html>
y
<body>
) en la parte inferior de la etiqueta
<body>
tiene:
<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">×</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>
Y ejemplo de uso en el componente Editor del 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>
Por supuesto, el
title
,
showClose
,
<mhead>
y
<mfoot>
son parámetros / etiquetas opcionales.
Aquí hay un ejemplo bastante decente de cómo puede usar el modo Bootstrap dentro de una aplicación Angular2 en GitHub .
La esencia de esto es que puede envolver la inicialización html y jquery de bootstrap en un componente.
He creado un componente
modal
reutilizable que le permite activar una apertura utilizando una variable de plantilla.
<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>
Solo necesita instalar el paquete npm y registrar el módulo modal en el módulo de su aplicación:
import { Ng2Bs3ModalModule } from ''ng2-bs3-modal/ng2-bs3-modal'';
@NgModule({
imports: [Ng2Bs3ModalModule]
})
export class MyAppModule {}
Este es un enfoque simple que no depende de jquery ni de ninguna otra biblioteca, excepto Angular 2. El componente a continuación (errorMessage.ts) se puede usar como una vista secundaria de cualquier otro componente. Es simplemente un modo de arranque que siempre está abierto o se muestra. Su visibilidad se rige por la declaración 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">×</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 es un ejemplo de control principal (se ha omitido un código no relevante por brevedad):
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...
Verifique el cuadro de diálogo ASUI que crea en tiempo de ejecución. No hay necesidad de esconder y mostrar lógica. Simplemente el servicio creará un componente en tiempo de ejecución usando AOT ASUI NPM
Yo uso ngx-bootstrap para mi proyecto.
Puedes encontrar la demo ngx-bootstrap
El github está here
Cómo utilizar:
-
Instalar ngx-bootstrap
-
Importar a su 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(){}
- Modal estático 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">×</span> </button> </div> <div class="modal-body"> This is static modal, backdrop click will not close it. Click <b>×</b> to close modal. </div> </div> </div> </div>
intente usar ng-window, permite al desarrollador abrir y controlar por completo múltiples ventanas en aplicaciones de una sola página de manera simple, sin Jquery, sin Bootstrap.
Configuración disponible
- Ventana de Maxmize
- Minimizar ventana
- Tamaño personalizado,
- Posicion personalizada
- la ventana es dragable
- Bloquear ventana principal o no
- Centrar la ventana o no
- Pasar valores a la ventana chield
- Pase valores de la ventana de campo a la ventana principal
- Escuchando el cierre de la ventana chield en la ventana padre
- Escuche cambiar el tamaño del evento con su oyente personalizado
- Abierto con tamaño máximo o no
- Habilitar y deshabilitar el cambio de tamaño de la ventana
- Habilitar y deshabilitar la maximización
- Habilitar y deshabilitar la minimización
Angular 7 + NgBootstrap
Una forma simple de abrir modal desde el componente principal y pasarle el resultado nuevamente. Es lo que quería. Creé un tutorial paso a paso que incluye la creación de un nuevo proyecto desde cero, la instalación de ngbootstrap y la creación de Modal. Puede clonarlo o seguir la guía.
Espero que esto ayude a nuevo en Angular.
https://github.com/wkaczurba/modal-demo
Detalles:
plantilla 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">×</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>
El 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() {
}
}
Demostración de la misma (app.component.html): forma sencilla de tratar el evento de devolución:
<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 se ejecuta una vez que modal se cierra:
@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;
}
}
Salud
- Angular 2 y hasta
- Bootstrap css (se conserva la animación)
- NO JQuery
- NO bootstrap.js
- Admite contenido modal personalizado (al igual que la respuesta aceptada)
- Soporte agregado recientemente para múltiples modales uno encima del otro .
``
@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 el fondo , necesitará algo como este CSS:
.modal {
background: rgba(0,0,0,0.6);
}
El ejemplo ahora permite múltiples modales al mismo tiempo
.
(vea el método
onContainerClicked()
).
Para los usuarios de Bootstrap 4 css
, debe realizar 1 cambio menor (porque se actualizó un nombre de clase css desde Bootstrap 3).
Esta línea:
[ngClass]="{''in'': visibleAnimate}"
debe cambiarse a:
[ngClass]="{''show'': visibleAnimate}"
Para demostrar, aquí hay un plunkr