如何使Modal在Angular 2中可重用? [英] How to make a Modal reusable in Angular 2?
问题描述
可重用性在编程时非常重要,我们为减少代码重复所做的一切都将为我们提供帮助.
Reusability is very important when programming, and anything we can do to reduce duplication of code is going to help us out.
在Angular 2项目中的许多地方,我必须使用Modal弹出窗口向用户显示信息.我正在使用 ng-bootstrap ,并且所有这些模式具有相同的页眉和页脚但是身体在很多情况下都会改变.有时,主体只是想替换单个占位符,而在其他时候,准备动态内容会有些复杂.这些是由不同的组件触发或管理的.
I have to use Modal popups to display information to users in many places in my Angular 2 project. I am using ng-bootstrap and all of these Modals have the same Header and Footer but body changes in many cases. Sometimes the body just wanted to replace a single place holder, at other times it has some complexity to prepare the dynamic content. And these are triggered or managed by different components.
ng-bootstrap 允许我们以两种方式将内容传递给Modal
ng-bootstrap allow us to pass content into a Modal in two ways.
- 作为模板.这里将整个Modal html包装在
<ng-template></ng-template>
中
- 作为组件
采用第一种方法时,我必须针对每个模式重复编写页眉,正文和页脚.
With the first approach, I have to write the header, body and footer repeatedly per modal.
使用第二种方法,我可以将HTML包装在组件内,但是需要放置占位符以使其动态.这样我就可以按以下方式传递值了
With the second approach, I can wrap the HTML inside a component but need to put placeholders to make it dynamic. so then I can pass values as follows
open() {
const modalRef = this.modalService.open(NgbdModalContent);
modalRef.componentInstance.name = 'World';
}
但是灵活性仍然有限.
But the flexibility is still limited.
因此,在我的公共模态中,身体看起来如下.我将<ng-content></ng-content>
放置为Modal身体的插槽.
So, in my Common Modal's body looks as below. I placed <ng-content></ng-content>
as a slot for the Modal's body.
@Component({
selector: 'common-modal',
template: `
<!-- Modal -->
<div class="modal fade" id="common-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">{{title}}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ng-content></ng-content>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
`,
现在我希望可以将其用作波纹管.
Now I wish I could use it as bellow.
<common-modal title="First Modal">
<span>Welcome Jasnan!</span>
</common-modal>
在其他地方
<common-modal title="Second Modal">
//......
<tr *ngFor="let student of pagedStudents">
<td>
{{student.name}}
</td>
<td>
{{student.grade}}
</td>
</tr>
//......
</common-modal>
我该怎么做?是否可以在 ng-bootstrap 中做到这一点?感谢您帮助我解决这个问题.
How can I make this? Is there a way to do this in ng-bootstrap? Thanks for helping me to figure this out.
推荐答案
到目前为止,最好的解决方案是在共享模块(组件和服务已导出的地方)中创建自定义可重用的modal component
和modal service
,因此它可以在导入共享模块的任何其他模块中使用
The best solution so far is to create a custom reusable modal component
and modal service
in a shared module (where the component and service is exported), so that it can be used in any other module where shared module is imported
shared.module.ts
@NgModule({
imports: [
CommonModule
],
declarations: [
ModalComponent,
],
providers:[
ModalService
],
exports:[
ModalComponent
]
})
modal.component.html
<div class="custom-modal">
<div class="model-close-btn">
<img class="close-image" src="assets/icon/png/close.png" alt="">
</div>
<ng-content></ng-content>
</div>
modal.component.ts
import { Component, OnInit, OnDestroy, ElementRef, Input } from '@angular/core';
import { ModalService } from '../services/modal.service';
import { element } from '@angular/core/src/render3';
@Component({
selector: 'custom-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.scss']
})
export class ModalComponent implements OnInit, OnDestroy {
@Input() id: string;
private element: any;
constructor(private modalService: ModalService, private el: ElementRef) {
this.element = el.nativeElement;
}
ngOnInit(): void {
let modal = this;
// ensure id attribute exists
if (!this.id) {
console.error('modal must have an id');
return;
}
// move element to bottom of page (just before </body>) so it can be displayed above everything else
document.body.appendChild(this.element);
// close modal on background click
this.element.addEventListener('click', function (e: any) {
if (e.target.className === 'modal__overlay modal__overlay--toggle') {
modal.close();
}
});
this.element.addEventListener('click', function (e: any) {
if (e.target.className === 'model-close-btn' || e.target.className === 'close-image' ) {
modal.close();
}
});
// add self (this modal instance) to the modal service so it's accessible from controllers
this.modalService.add(this);
}
// remove self from modal service when directive is destroyed
ngOnDestroy(): void {
this.modalService.remove(this.id);
this.element.remove();
}
// open modal
open(): void {
//console.log(this.element);
this.element.style.display = 'block';
}
// close modal
close(): void {
this.element.style.display = 'none';
}
}
modal.component.scss
/* MODAL STYLES
-------------------------------*/
:host(custom-modal) {
/* modals are hidden by default */
display: none;
}
.custom-modal-open {
/* body overflow is hidden to hide main scrollbar when modal window is open */
display: block !important;
}
.model-close-btn {
position: fixed;
width: 18px;
height: 18px;
right: 50px;
top: 50px;
z-index: 9999;
background-color: #fff;
border-radius: 50px;
padding: 10px;
cursor: pointer;
img {
width: 18px;
}
}
modal.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ModalService {
private modals: any[] = [];
constructor() { }
add(modal: any) {
// add modal to array of active modals
this.modals.push(modal);
}
remove(id: string) {
// remove modal from array of active modals
this.modals = this.modals.filter(x => x.id !== id);
}
open(id: string) {
// open modal specified by id
let modal: any = this.modals.filter(x => x.id === id)[0];
modal.open();
}
close(id: string) {
// close modal specified by id
let modal: any = this.modals.filter(x => x.id === id)[0];
modal.close();
}
}
现在,如果要在另一个模块的示例组件中使用此组件,请执行以下操作:
Now if you want to use this component in a sample component in another module , do the following:
步骤1:将共享模块导入到要使用custom-modal
Step 1: Import the shared module to the sample module where you want to use the custom-modal
sample.module.ts
@NgModule({
declarations: [
SampleComponent,
],
imports: [
SharedModule
],
})
第2步:
sample.component.ts
import { ModalService } from 'src/shared/services/modal.service';
constructor(private modalService: ModalService){}
// call this function to open modal by passing modal id
openModal(id: string) {
this.modalService.open(id);
}
// just call this function to close modal by passing modal id
closeModal(id: string) {
this.modalService.close(id);
}
sample.component.html
<!-- modal popup started -->
<custom-modal id="custom-modal-one">
// add your any custom modal template code here and logic in sample.component.ts
</custom-modal>
<!-- modalp popup ends -->
这篇关于如何使Modal在Angular 2中可重用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!