Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 7 CSS not working while using reusable component

I am fairly new to Angular and came from React.js background.

I have made a simple grid component like below:

grid.component.js

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

@Component({
  selector: 'app-grid',
  template: `
    <div [ngStyle]="styles()" [ngClass]="passClass">
      <ng-content></ng-content>
    </div>
  `,
  styles: [`
    div {
      display: flex;
    }
  `]
})
export class GridComponent implements OnInit {
  @Input() direction: string;
  @Input() justify: string;
  @Input() align: string;
  @Input() width: string;
  @Input() passClass: string;

  constructor() { }

  ngOnInit() {
  }

  styles() {
    return {
      'flex-direction': this.direction || 'row',
      'justify-content': this.justify || 'flex-start',
      'align-items': this.align || 'flex-start',
      ...(this.width && { width: this.width })
    };
  }
}

And I want to use it in other components like below: aboutus.component.html

<app-grid passClass="about-us page-container">
  <app-grid direction="column" passClass="left">
    <div class="title blue bold">
      An open community For Everyone
    </div>
    <div class="large-desc grey">
      This conference is brought to you by
      the Go Language Community in
      India together with the Emerging
      Technology Trust (ETT). ETT is a non-
      profit organization, established to
      organize and conduct technology
      conferences in India. It’s current
      portfolio includes
    </div>
  </app-grid>
</app-grid>

aboutus.component.sass

.about-us
  position: relative
  .left
    width: 50%
    &:after
      bottom: 0
      right: 0
      z-index: 0
      margin-right: -5vw
      position: absolute
      content: url(../../assets/images/footer.svg)

But, what happens is the CSS attached with the second component will not work.

I know a little bit about CSS isolation but could not understand if it affects here.

P.S.: Please feel free to provide feedback to things outside of scope this question as well.

like image 510
Tolsee Avatar asked Feb 03 '19 15:02

Tolsee


1 Answers

It is not possible to pass CSS classes as variables in your template. So if your expectation in aboutus.component.html was to be able to pass the left CSS class as a variable in your template, that will not work.

There are a few things I can point out that will hopefully help:

  1. If you want to modify a CSS class that is internal to a component from outside that component, one option is to use ng-deep.

  2. In your particular case, I don't think ng-deep is necessary. I'd suggest to drop the div element within the app-grid component and instead apply the styles to the host element using @HostBinding decorator. With that approach you can drop the passCss altogether because now wherever you use yourapp-grid component you can style that component in CSS using the app-grid selector.

    grid.component.ts:

    import { Component, OnInit, Input, HostBinding, SafeStyle } from '@angular/core';
    
    @Component({
      selector: 'app-grid',
      template: `<ng-content></ng-content>`,
      styles: [`
        :host {
          display: flex;
        }
      `]
    })
    export class GridComponent implements OnInit {
      @Input() direction: string;
      @Input() justify: string;
      @Input() align: string;
      @Input() width: string;
    
      constructor(private sanitizer:DomSanitizer) { }
    
      ngOnInit() {
      }
    
      @HostBinding('style')
      styles(): SafeStyle {
        const styles = `
          flex-direction: ${this.direction || 'row'};
          justify-content: ${this.justify || 'flex-start'};
          align-items: ${this.align || 'flex-start'};
       `;
        return this.sanitizer.bypassSecurityTrustStyle(styles);
      }
    }
    

    aboutus.component.sass:

      app-grid {
        // You can style the host element of a component
        // just like any native HTML element and without
        // needing to use `ng-deep`
      }
    
  3. You may also want to look into CSS Custom Properties. Custom CSS properties are not shielded by view-encapsulation. This gives you the ability to create a CSS API for a component, if you will, and those properties can be used anywhere within a component.

    aboutus.component.sass

    app-grid {
      --image: url(../../assets/images/footer.svg)
    }
    

    grid.component.sass

    div {
      content: var(--image);
    }
    
like image 118
Sam Herrmann Avatar answered Sep 16 '22 16:09

Sam Herrmann