Search code examples
angularadminlte

A class from a child component is not applied correctly


I'm doing a web application using Angular 8 and AdminLTE3 as my template.

I want to implement the Loading Style for a card, this code needs to be placed before the .card closing tag.

<div class="overlay">
  <i class="fas fa-2x fa-sync-alt fa-spin"></i>
</div>

Working example:

enter image description here

<!-- Main content -->
<section class="content">

  <!-- Card -->
  <div class="card">

    <div class="card-body">
      ...
    </div>
    <!-- /.card-body -->

    <!-- Loading Style -->
    <div class="overlay">
      <i class="fas fa-2x fa-sync-alt fa-spin"></i>
    </div>

  </div>
  <!-- /.card -->

</section>
<!-- /.content -->

Not working example:

When I move the Loading Style code to a reusable component and now this component is a child, the Loading Style is not applied correctly.

enter image description here

<!-- Main content -->
<section class="content">

  <!-- Card -->
  <div class="card">

    <div class="card-body">
      ...
    </div>
    <!-- /.card-body -->

    <!-- Loading Style -->
    <app-card-loading-state [isLoading]="true"></app-card-loading-state>

  </div>
  <!-- /.card -->

</section>
<!-- /.content -->

CardLoadingStateComponent

@Component({
  selector: 'app-card-loading-state',
  template: '
             <div class="overlay" *ngIf="isLoading">
               <i class="fas fa-2x fa-sync-alt fa-spin"></i>
             </div>
           ',
})
export class CardLoadingStateComponent {
  @Input() isLoading = false;
}

I have tried to apply encapsulation: ViewEncapsulation.None and host: {class: 'card'}, but, no luck.

--

The overlay class is located here, inside of the template's CSS. I inject that file in my angular.json.

"styles": [
      "node_modules/admin-lte/dist/css/adminlte.min.css",
      "src/styles.scss"
          ],

--

My goal is to apply the CSS of the CardLoadingStateComponent correctly when this is a child component.


Solution

  • I am not 100% sure but I suspect that .overlay class is used as a selector in a way that .card > .overlay which requires .overlay to be a direct children of .card

    When you use .overlay in a child component, it is no longer a direct children because of the component selector tag in between. That's why .card > .overlay doesn't work anymore.

    Using an attribute selector for child component, in order to get rid of component selector tag in DOM, may solve the problem.

    @Component({
      selector: '[app-card-loading-state]',
      template: '<i class="fas fa-2x fa-sync-alt fa-spin"></i>',
    })
    export class CardLoadingStateComponent {
      @HostBinding('class.overlay') overlay = true
    }
    
    <!-- Main content -->
    <section class="content">
    
      <!-- Card -->
      <div class="card">
    
        <div class="card-body">
          ...
        </div>
        <!-- /.card-body -->
    
        <!-- Loading Style -->
        <div app-card-loading-state *ngIf="isLoading"></div>
    
      </div>
      <!-- /.card -->
    
    </section>
    <!-- /.content -->
    

    Here is a proof of concept implementation: https://stackblitz.com/edit/angular-ivy-x5xpzr

    As i said at the beginnig I am not sure if this is the problem you are facing but it might be. So let me know if it works and i hope it helps.