Wie kann das View Encapsulation-Problem in Angular8 gelöst werden?

8

Ich habe übergeordnete Komponente und untergeordnete Komponente. Untergeordnete Komponente, die als modale Komponente erstellt wurde. Also habe ich den Selektor für untergeordnete Komponenten in die übergeordnete Komponente aufgenommen und die Ansichtskapselung so eingestellt, dass keine übergeordnete Komponenten-CSS und alle verwendet werden. Es funktioniert auch, aber die übergeordnete Komponente hat die # paper-ID, die eine libary-CSS von Drittanbietern (rappidjs) anwendet (für SVG-Diagramm). Die gleiche wie die untergeordnete Komponente hat die ID #dataMapper. aber hier nimmt die Drittanbieter-CSS nicht, weil die untergeordnete Komponente auf gesetzt ist 'encapsulation: ViewEncapsulation.None'. Wenn ich entfernen werde, encapsulation: ViewEncapsulation.Nonefunktioniert es, aber Modal funktioniert nicht. Alle Modalitäten werden geladen, anstatt auf einen Klick zu klicken. Wie Sie dieses Problem lösen können, beraten Sie mich bitte.

Codierung:

Übergeordnete Komponente 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 der übergeordneten Komponente

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

Untergeordnete Komponente HTML

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

Untergeordnete Komponente 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');
  }

}

Modaler Servicecode

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

Bitte lassen Sie mich wissen, wenn weitere Details erforderlich sind.

bagya
quelle
3
Versuchen Sie, ein Stackblitz-Beispiel hinzuzufügen, anstatt eine Menge Code zu veröffentlichen.
Akhil Aravind
@AkhilAravind - Das Hinzufügen von stackblitiz kann länger dauern. Weil es eine große App ist und ich den Code nur dort platziert habe, wo das Problem auftritt.
Bagya
Wir brauchen nicht den ganzen Codeblock, nur ein minimales Beispiel, um das Problem zu reproduzieren.
Akhil Aravind
2
Können Sie einige Beispiele für das CSS, das angewendet werden soll, und die Selektoren veröffentlichen? Es ist unklar, was hier falsch läuft. Wenn dieses CSS eines Drittanbieters auf IDs basiert, ist dies sehr problematisch, wenn diese IDs mehrmals auf der Seite angezeigt werden, als ob diese Komponenten irgendwo wiederverwendet würden. Nur die erste Instanz einer ID nimmt die Stile an
bryan60
1
Es wäre für uns alle hilfreich, Ihr Problem zu lösen, wenn Sie in stackblitz ein minimal reproduzierbares Problem erstellen können. Schließen Sie nicht Ihr gesamtes Projekt ein, sondern nur den Teil, in dem Sie auf dieses Problem stoßen.
PrinceIsNinja

Antworten:

1

Wegen deines Modals. Die Modal auf erstellt wird Anfang der App, (aus Body - Tag , wenn man sich für den modal - Wrapper durch Inspektion.)

Dies ist die modale Ursache dafür, dass die Dom-Struktur nicht mit der ng-Komponentenstruktur synchronisiert ist

Warum funktioniert das Modal mit ng Encapsulation? Weil Ihr modaler Dienst damit umgehen kann.

Die CSS-Datei eines Drittanbieters ist jedoch nicht Teil Ihrer Winkelkompilierungskonfiguration (dh nur sass, scss funktioniert). Es ignoriert also alles, .cssselbst wenn Sie es richtig importieren.

Um dies zu lösen, können Sie die CSS-Datei global anwenden. Wenn Sie befürchten, dass andere globale Stile überschrieben werden , können Sie die CSS-Datei in '_somefile.scss' umbenennen (achten Sie auf den Bindestrich '_', dies ist wichtig.)

Dann unter der globalen Datei style.scss Ihres Projekts> Erstellen Sie einen Selektor, der Ihrem modalen Wrapper entspricht> unter dem Selektor: Fügen Sie eine Zeile hinzu, die @import somefile (keine Erweiterung hinzufügen)

style.scss

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

Wie von Ihnen in dem Problem beschrieben, dass Sie das CSS der übergeordneten Komponente innerhalb der untergeordneten Komponente erben möchten. Ich gehe also davon aus, dass Sie dieselben HTML-Elemente in übergeordneten und untergeordneten Komponenten haben und Ihr CSS nicht duplizieren möchten.

Da wir Ihr Problem nicht replizieren können und Sie keine Stackblitz-Instanz erstellt haben. Ich würde eine bessere Alternative vorschlagen, die funktionieren wird. Bitte finden Sie es unten:

Wir können mehrere CSS-URLs in der styleUrlsEigenschaft des @ComponentDecorator-Metadatenobjekts angeben . Daher würde ich vorschlagen, dass Sie auch die übergeordnete Stildatei Url übergeben.

Ich habe einen einfachen Stackblitz erstellt, der zeigt, wo ich auf CSS der übergeordneten Komponente zugreife: https://stackblitz.com/edit/angular-jhewzy

CSS-Datei der übergeordneten Komponente (app.component.css) - Ich gebe an, dass die Hintergrundfarbe des pTags im übergeordneten Element gelb sein soll. Ich möchte dies in der untergeordneten Komponente erben.

p {
  background-color: yellow;
}

Unten finden Sie die untergeordnete Komponente CSS (hello.component.css).

p {
  font-style: italic;
}

Wenn Sie die übergeordnete Komponente in der untergeordneten Komponente verwenden möchten, verwenden Sie einfach den Stil-URL-Pfad in der styleUrls-Eigenschaft

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

Ich hoffe es hilft dir.

PrinceIsNinja
quelle