Reputation: 105
I am using angular 9. I have a home page which has four buttons. I want to open separate modal on each button's click at a time. I did research a lot, here is my trial and effort. Thanks in advance :)
parent component
@Component({
selector: 'app-link-budget-view',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
@ViewChild('childOne') callChild_OneFn: ChildOneComponent;
@ViewChild('childTwo') callChild_TwoFn: ChildTwoComponent;
...
ngOnInit(): void {
}
openModalOne() {
this.callChild_OneFn.OpenModalFunction();
}
openModalOne() {
this.callChild_TwoFn.OpenModalFunction();
...
}
}
Home Html
<button class="btn btn-primary mb-2 mr-2" (click)="openModalOne()">Modal 1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModalTwo()">Modal 2</button>
...
<app-child-one #childOne></app-child-one>
<app-child-two #childTwo></app-child-two>
...
childOne Component
@Component({
selector: 'app-link-budget-view',
templateUrl: './child-one.component.html',
styleUrls: ['./chile-one.component.scss']
})
export class ChildOneComponent implements OnInit {
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
OpenModalFunction() {
console.log("component One function running...")
this.modalService.open('#ModalOneId', { size: 'xl' });
}
...
}
similarly there is a function in component two
OpenModalFunction() {
console.log("component Two function running...")
this.modalService.open('#ModalTwoId', { size: 'xl' });
}
Component One Html
<ng-template #ModalOneId let-modal>
<div class="modal-header">
<h4 class="modal-title">This is modal one</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">
<div class="card">
<div class=" card-body">
<div id="table" class="table-editable">
...
...
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="modal.close('Close click')">Close</button>
</div>
</ng-template>
similarly ng-templete is used in component two html
Upvotes: 2
Views: 6142
Reputation: 105
Finally I fixed it here is the code to help others
Parent ts
export class ParentComponent implements OnInit {
constructor(private modalService: CustomModalServiceService) { }
ngOnInit(): void {
}
openModal(modalName: string) {
this.modalService.openModalFunction(modalName);
}
}
Parent html
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('childOne')">Modal_1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('childTwo')">Modal_2</button>
child one or two ts code accordingly for one or two
export class ChildOneComponent implements OnInit {
constructor(private modalRef: NgbActiveModal) { }
ngOnInit(): void {
}
hideModalFunction() {
this.modalRef.close();
}
}
child one or two html for modal
<div class="modal-header">
<h4 class="modal-title">This is modal one</h4>
<button type="button" class="close" aria-label="Close" (click)="hideModalFunction()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="card">
<div class=" card-body">
<div id="table" class="table-editable">
...
...
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="hideModalFunction()">Close</button>
</div>
and you need a custom modal service
Custom modal service
export class CustomModalService {
...
private modalRef: NgbModalRef;
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
openModalFunction(modalName: string) {
switch(modalName) {
case 'one':
console.log("component One function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildOneComponent, { size: 'xl' });
this.modalRef.componentInstance.testData = 'test';
break;
case 'two':
console.log("component Two function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildTwoComponent, { size: 'xl' });
break;
case default:
// do nothing
}
}
}
Upvotes: 1
Reputation: 1870
you didn't mention if what you wrote is working or not, or what errors you are getting. it looks like it should work to me. Although if you just want to open a modal, you can handle it completely in your html:
<button (click)="childOne.OpenModalFunction()">Modal 1</button>
<button (click)="childTwo.OpenModalFunction()">Modal 2</button>
<app-child-one #childOne></app-child-one>
<app-child-two #childTwo></app-child-two>
that should be the only thing you need in the parent. no code needed in the parent .ts file. if this is not working, there's something wrong with the code in your child class.
Upvotes: 1
Reputation: 56
You are repeating too much code here. You could make it more re-usable and less repetitive. Try to extract most of the business logic to a service. Leave the component as dumb(no business logic) as possible for better re-usability.
Parent component
@Component({
selector: 'app-link-budget-view',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
...
constructor(private myModalService: MyModalService)
ngOnInit(): void {
}
openModal(modelName: string) {
this.myModalService.openModalFunction(modalName);
}
}
Home Html
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('one')">Modal 1</button>
<button class="btn btn-primary mb-2 mr-2" (click)="openModal('two')">Modal 2</button>
...
MyModal Service
@Injectable({
providedIn: 'root'
})
export class MyModalService {
...
private modalRef: NgbModalRef;
constructor( private modalService: NgbModal) { }
ngOnInit(): void {
}
openModalFunction(modalName: string) {
switch(modalName) {
case 'one':
console.log("component One function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildOneComponent, { size: 'xl' });
this.modalRef.componentInstance.testData = 'test';
break;
case 'two':
console.log("component Two function running...");
// do any execution before opening child component
this.modalRef = this.modalService.open(ChildTwoComponent, { size: 'xl' });
case default:
// do nothing
}
}
hideModalFunction() {
//do something before closing the modal
this.modalRef.close();
}
}
Now no OpenModalFunction() required inside the child components as you have extracted the modal opening logic into the MyModalService. This will also adhere to the Single Functionality principle means every component has only single functionality to be fulfilled. Furthermore, you have now full control via MyModalService to handle popups. If you want to execute a common code before/after opening/closing the windows like notifying another service, you could do that.
Now this could be further optimized as all software codes do. Like extracting common code from Child Components to a single interface/abstract class. But it totally depends upon your requirements.
Upvotes: 0