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 *ngIf
wrapper.
Solution
ng-template
. ng-template
ne 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
, *ngTemplateOutlet
et le @ContentChild
travail.
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 { }