Angular8のビューのカプセル化の問題を解決するにはどうすればよいですか?


8

親コンポーネントと子コンポーネントがあります。モーダルコンポーネントとして作成された子コンポーネント。だから私は親コンポーネント内に子コンポーネントセレクターを含め、ビューのカプセル化をなしに設定したので、親コンポーネントのCSSとすべてを取ってそれも機能しますが、親コンポーネントはいくつかのサードパーティ(rappidjs)ライブラリcssを適用する#paper idを持っていますSVGダイアグラム)。子コンポーネントと同じように#dataMapper idがあります。ただし、子コンポーネントがに設定されているため、ここではサードパーティのcssは使用していません'encapsulation: ViewEncapsulation.None'。削除するencapsulation: ViewEncapsulation.Noneと機能しますが、モーダルは機能しません。onclickの代わりにすべてのモーダルがロードされます。この問題の解決方法を教えてください。

コーディング:

親コンポーネント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

<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

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

子コンポーネントT

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

}

モーダルサービスコード

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

詳細が必要な場合はお知らせください。


3
コードの束を投稿するのではなく、stackblitzの例を追加してみてください。
Akhil Aravind

@AkhilAravind-stackblitizの追加には時間がかかる場合があります。大きなアプリなので、問題のある場所にのみコードを配置しました。
バジャ

コードブロックの完全な束は必要ありません。問題を再現するための最小限のサンプルのみです。
Akhil Aravind

2
適用されるはずのCSSとセレクタのいくつかの例を投稿できますか?ここで何が悪いのかは不明です。このサードパーティのcssがIDに基づいている場合、これらのコンポーネントがどこでも再利用されているかのように、これらのIDがページに複数回表示されると、非常に問題があります。idの最初のインスタンスのみがスタイルを取得します
bryan60

1
stackblitzで最小限の再現可能な問題を作成できれば、私たち全員が問題を解決するのに役立ちます。プロジェクト全体ではなく、この問題が発生している部分のみを含めてください。
PrinceIsNinja

回答:


1

あなたのモーダルのため。 モーダルはアプリの上部に作成されます(モーダルラッパーを検査して探す場合、bodyタグの外にあります)。

モーダルが原因でdom構造がngコンポーネント構造と同期していません

では、モーダルがngで機能するのはなぜEncapsulationですか?モーダルサービスがそれを処理できるからです。

ただし、サードパーティのCSSファイルは、角度コンパイル構成の一部ではありません(つまり、sass、scssのみが機能します)。したがって、.css適切にインポートしても無視されます。

これを解決するには、.cssをグローバルに適用します。または、他のグローバルスタイルを上書きすることを恐れている場合は、cssファイルの名前を '_somefile.scss'に変更できます(ダッシュ '_'に注意してください。重要です)。

次に、プロジェクトのグローバルstyle.scssファイルの下で>モーダルラッパーに一致するセレクターを作成>セレクターの下で、@ import somefileという行を追加します(拡張子を追加しないでください)。

style.scss

.modal-wrapper {
    @import somepath/somefile
}

0

子コンポーネント内の親コンポーネントのcssを継承したいという問題で説明したとおり。したがって、親コンポーネントと子コンポーネントに同じHTML要素があり、CSSを複製したくないと想定しています。

問題を再現できず、stackblitzインスタンスを作成していないため。私はうまくいくより良い代替案を提案します。以下でそれを見つけてください:

デコレータメタデータオブジェクトのstyleUrlsプロパティ内に複数のCSS URLを指定できます@Component。したがって、親スタイルファイルのURLも渡すことをお勧めします。

私は親コンポーネントのCSSにアクセスしている場所を示す基本的なstackblitzを作成しました:https ://stackblitz.com/edit/angular-jhewzy

親コンポーネントのcssファイル(app.component.css)- p親の内側のタグの背景色を黄色にするように指定しています。これを子コンポーネントに継承したい。

p {
  background-color: yellow;
}

以下は子コンポーネントCSS(hello.component.css)です

p {
  font-style: italic;
}

子コンポーネント内で親コンポーネントを使用したいので、styleUrlsプロパティでスタイルURLパスを使用します

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

お役に立てば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.