I have parent component and child component. Child component created as a modal component. So i have included child component selector inside parent component and i have set view encapsulation is none so that it will take parent component css and all and it's working also but parent component has #paper id applying some third party(rappidjs) libary css(for SVG diagramming). Same like child component has #dataMapper id. but here the thirdparty css is not taking because child component set to 'encapsulation: ViewEncapsulation.None'
. If i will remove encapsulation: ViewEncapsulation.None
it's working but modal is not working. all the modals loading instead of onclick. How to solve this issue please advice me someone.
Coding:
Parent Component TS
@Component({
selector: 'app-data-model',
templateUrl: './data-model.component.html',
styleUrls: ['./data-model.component.css']
})
export class DataModelComponent implements OnInit{
// Modal
openModal(id: string) {
this.modalApp = true;
this.modalService.open(id);
}
closeModal(id: string) {
this.modalService.close(id);
}
Parent Component HTML
<div id="toolbar">
<div class="tool-bar-section">
<button class="btn" (click)="openModal('custom-modal-1');"><i class="fa fa-file-excel-o" style="font-size: 24px"></i></button>
</div>
</div>
<div id="paper"> </div> ( this dom taking thirdparty css)
<app-modal id="custom-modal-1">
<h1 class="head-bar">Data Model - Import Excel <a href="#" class="close-icon" (click)="closeModal('custom-modal-1');"><i class="fa fa-times-circle-o" aria-hidden="true"></i></a></h1>
<div class="modal-content-section">
<ul>
<li><a href="#" (click)="closeModal('custom-modal-1');openModal('custom-modal-2');">Create New Schema</a></li>
<li><a href="#" (click)="closeModal('custom-modal-1');openModal('custom-modal-3');">Import Data to existing schema</a></li>
</ul>
</div>
</app-modal>
<app-modal id="custom-modal-2">
<h1 class="head-bar">Data Model - Import Excel <a href="#" class="close-icon" (click)="closeModal('custom-modal-2');"><i class="fa fa-times-circle-o" aria-hidden="true"></i></a></h1>
<div class="modal-content-section">
<div id="dataMapper"></div> ( this dom is not taking thirdparty css)
<p><a href="#" (click)="closeModal('custom-modal-2');openModal('custom-modal-4');">Data Mapping</a></p>
</div>
</app-modal>
Child Component HTML
<div class="app-modal">
<div class="app-modal-body">
<ng-content></ng-content>
</div>
</div>
<div class="app-modal-background"></div>
Child Component Ts
@Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css'],
encapsulation: ViewEncapsulation.None
})
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 {
// 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', el => {
if (el.target.className === 'app-modal') {
this.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 component is destroyed
ngOnDestroy(): void {
this.modalService.remove(this.id);
this.element.remove();
}
// open modal
open(): void {
this.element.style.display = 'block';
document.body.classList.add('app-modal-open');
}
// close modal
close(): void {
this.element.style.display = 'none';
document.body.classList.remove('app-modal-open');
}
}
Modal Service Code
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ModalService {
private modals: any[] = [];
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
const modal = this.modals.find(x => x.id === id);
modal.open();
}
close(id: string) {
// close modal specified by id
const modal = this.modals.find(x => x.id === id);
modal.close();
}
}
Please let me know if more details required.
ViewEncapsulation.Emulated. Angular modifies the component's CSS selectors so that they are only applied to the component's view and do not affect other elements in the application, emulating Shadow DOM behavior.
View Encapsulation in Angular defines how the styles defined in the template affect the other parts of the application. The angular uses three strategies while rendering the view ViewEncapsulation. Emulated , ViewEncapsulation. ShadowDOM and ViewEncapsulation.
Because of your modal. The modal is created on top of your app, (out of body tag if you look for the modal wrapper by inspecting it.)
It is the Modal cause the dom structure not in sync with ng component structure
So why the modal works with ng Encapsulation
? Because your modal service can handle it.
But the 3rd party CSS file is not a part of your angular compile config (i.e. only sass, scss works). So it does ignore any .css
even you import it properly.
To solve it, you can apply the .css globally. Or if you are afraid of that may overwriting other global styles, you can rename the css file to '_somefile.scss' (pay attention to the dash '_', it is important.)
Then under your project global style.scss file > create a selector matches your modal wrapper > under the selector: add a line that @import somefile (don't add extension)
style.scss
.modal-wrapper {
@import somepath/somefile
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With