¿Cómo resolver el problema de View Encapsulation en Angular8?

8

Tengo componente principal y componente secundario. Componente hijo creado como componente modal. Así que he incluido el selector de componentes secundarios dentro del componente principal y he establecido que la encapsulación de la vista sea nula, por lo que tomará el componente principal css y todo, y también funciona, pero el componente primario tiene #paper id aplicando alguna biblioteca de terceros (rappidjs) libary css (para Diagramación SVG). Igual que el componente hijo tiene #dataMapper id. pero aquí el css de terceros no está tomando porque el componente hijo está establecido en 'encapsulation: ViewEncapsulation.None'. Si voy a eliminar encapsulation: ViewEncapsulation.None, está funcionando pero modal no está funcionando. todos los modales se cargan en lugar de onclick. Cómo resolver este problema, por favor avísame a alguien.

Codificación:

Componente principal 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);
}

HTML de componente principal

<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>

HTML de componente hijo

<div class="app-modal">
    <div class="app-modal-body">
        <ng-content></ng-content>
    </div>
</div>
<div class="app-modal-background"></div>

Componente secundario 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');
  }

}

Código de servicio modal

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();
  }
}

Avíseme si se requieren más detalles.

Bagya
fuente
3
Intente agregar un ejemplo de stackblitz en lugar de publicar un montón de código.
Akhil Aravind
@AkhilAravind: agregar stackblitiz puede llevar más tiempo. porque es una aplicación grande y he colocado el código solo donde está el problema.
bagya
No necesitamos todo el bloque de código, solo una muestra mínima para reproducir el problema.
Akhil Aravind
2
¿Puedes publicar algunos ejemplos del CSS que se supone que se aplicará y los selectores? No está claro qué está pasando aquí. Si este CSS de terceros se basa en los ID, es muy problemático si estos ID aparecen varias veces en la página, como si estos componentes se reutilizaran en cualquier lugar. solo la primera instancia de una identificación tomará los estilos
bryan60
1
Sería útil para todos nosotros resolver su problema si puede crear un problema reproducible mínimo en stackblitz. No incluya todo su proyecto, solo la parte en la que se encuentra con este problema.
PrinceIsNinja

Respuestas:

1

Por tu modal. El modal se crea en la parte superior de su aplicación (fuera de la etiqueta del cuerpo si busca el contenedor modal al inspeccionarlo).

Es el modo modal porque la estructura dom no está sincronizada con la estructura del componente ng

Entonces, ¿por qué el modal funciona con ng Encapsulation? Porque su servicio modal puede manejarlo.

Pero el archivo CSS de terceros no es parte de su configuración de compilación angular (es decir, solo sass, scss funciona). Por lo tanto, ignora cualquiera, .cssincluso si lo importa correctamente.

Para resolverlo, puede aplicar el .css a nivel mundial. O si tiene miedo de que eso pueda sobrescribir otros estilos globales, puede cambiar el nombre del archivo css a '_somefile.scss' (preste atención al guión '_', es importante).

Luego, en el archivo global style.scss de su proyecto> cree un selector que coincida con su contenedor modal> debajo del selector: agregue una línea que @ importe algún archivo (no agregue extensión)

style.scss

.modal-wrapper {
    @import somepath/somefile
}
Vincent-cm
fuente
0

Según lo descrito por usted en el problema, desea heredar el CSS del componente primario dentro del componente secundario. Por lo tanto, supongo que tiene los mismos elementos HTML en los componentes primarios y secundarios y no desea duplicar su CSS.

Como no podemos replicar su problema y no ha creado ninguna instancia de stackblitz. Sugeriría una mejor alternativa que funcionará. Por favor encuéntrelo a continuación:

Podemos especificar múltiples URL CSS dentro de la styleUrlspropiedad del @Componentobjeto de metadatos del decorador. Por lo tanto, le sugiero que pase también la URL del archivo de estilo principal.

He creado un stackblitz básico que muestra dónde estoy accediendo al CSS del componente principal: https://stackblitz.com/edit/angular-jhewzy

Archivo css del componente primario (app.component.css): estoy especificando que el color de fondo de la petiqueta dentro del primario debe ser amarillo. Quiero heredar esto en el componente hijo.

p {
  background-color: yellow;
}

A continuación se muestra el componente CSS secundario (hello.component.css)

p {
  font-style: italic;
}

Como desea utilizar el componente primario dentro del componente secundario, simplemente use la ruta de URL de estilo en la propiedad styleUrls

import { Component, Input } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<p>I am child</p>`,
  styleUrls: [`./hello.component.css`, './app.component.css'],
})


export class HelloComponent  {
  @Input() name: string;
}

Espero que te ayude.

PrinceIsNinja
fuente