How to access local css class names from within the angular component - css

I need to access the generated css classname from within an angular component, in order to style a 3rd-party component.
Angular does some magic transformations on the local css classnames to enable scoping. I need to apply some custom styles to an ngx-datatable component. To do this, I need to pass it custom classnames. Because of what angular does to the classnames, these no longer match.
Adding the classnames to the global scope or using ::ng-deep both work, however I would rather not break the encapsulation.
dashboard-component.ts
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent {
getRowClass(row){
return 'my-class';
}
}
dashboard-component.scss
.my-class {
background: green;
}
dashboard-component.html
<ngx-datatable
[rowclass]="getRowClass"
></ngx-datatable>
The way I see it I should be able to access some reference to the css class from within the component, say this._styles, which will then carry the generated name of the class at runtime, so I can do
getRowClass(row){
return this._styles['my-class'];
}

I think you are not able to propagate your styles to ngx-datatable.
You can use encapsulation: ViewEncapsulation.None within your #component but make sure you use it carefully as it will lead to some weird css behaviours.
Next, What you can do is create a container for your dashboard.html file like:
<div class="dashboard-container">
<ngx-datatable></ngx-datatable>
</div>
and inside your dashboard.scss you can reference the parent container
.dashboard-container {
.my-style{}
}

Just put the css classes in the global style file ,otherwise you will need to use ::ng-deep,so my advice to put ngx-datatable in the global style file
check the ngx-datatable demo asset/app.css where the did the same
another option you can set the encapsulation: ViewEncapsulation.None on the component the the class name will be the same
#Component({
selector: "app-demo",
templateUrl: "./demo.component.html",
styleUrls: ["./demo.component.scss"],
encapsulation:ViewEncapsulation.None
})
export class DemoComponent implements OnInit {
demo.component.scss
ngx-datatable {
.green-color {
background:green;
& div {
color :#fff;
}
}
}
set the encapsulation to none or put the style in global style file are the same here because both ways will be the style globally without any change
demo 🔥

Related

Styling child components template from parent component css angular

How to force CSS of child component from parent using ::ng-deep or something?
I have parent component where I put child component:
....parent.component...
<app-likes></app-likes>
.....parent.component......
Not inside that likes component there is he following HTML:
<div class="mainDiv">
<div class="secondDiv"><i class="far fa-heart fa-3x"></i></div></div>
Now I want to set color of fa-heart class to white from parent parent.component.css.
How can I do that?
You can do this way, in the css of the parent component:
parent.component.css:
:host ::ng-deep .fa-heart {
color: red;
}
or
:host ::ng-deep app-likes .fa-heart {
color: red;
}
Well I will go against the folks above and suggest that you don't do this.
If you consider the component an isolated building block in your app, you would consider it an advantage, that it looks the same in every place you use it. Using ::ng-deep to override this behaviour will cause you trouble in larger apps.
Angular promotes using #Inputs as the interface of passing data into the component. My suggestion is to use #Input to modify the view. Or, if in larger contexts you can use Dependency Injection to provide a token that specifies a theme for all children of a component.
<app-likes theme="white"></app-likes>
#Component({selector: 'app-likes'})
class AppLikesComponent {
#Input() theme: string;
#HostBinging("class") get themeBinding() {
return 'theme--' + this.theme;
}
}
You could set the ViewEncapsulation option in the parent component to remove the shadow DOM. This essentially allows the child component to use the selector definitions from the parent component.
Try the following
Parent component
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
encapsulation: ViewEncapsulation.None // <-- no shadow DOM
})
export class AppComponent {
}
Parent CSS
.fa-heart {
color: white;
}
Working example: Stackblitz

How do I style child component from parent's SCSS without ng-deep?

I've been trying to style a BoxedComponent style from HeaderComponent without using ::ng-deep, but I'm not finding a way to so properly.
The BoxedComponent component class contains nothing different but a ViewEncapsulation.None.
#Component({
selector: 'labs-boxed',
templateUrl: './boxed.component.html',
styleUrls: ['./boxed.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class BoxedComponent {}
HTML
<div class="boxed">
<ng-content></ng-content>
</div>
I created two classes in its SCSS file to use everywhere, but I realized I couldn't still stylize the responsiveness of the component due to the same problem.
.boxed {
/* rules */
}
.tall .boxed {
height: 500px;
width: 360px;
}
.squared .boxed {
height: 340px;
width: 340px;
}
In HeaderComponent's HTML file, I am making use of labs-boxed as follows:
<div id="who-we-are" class="d-flex justify-content-around">
<labs-boxed [ngClass]="'tall'">
<p>
...
...
...
So far it works, but then entering in the SCSS file, I have attempted many ways to access lab-boxed's styles and changing it:
.boxed { ... }
.tall .boxed { ...}
and so on, but without success.
How can I do it, please?
Since BoxedComponent has ViewEncapsulation.None all rules defined in boxed.component.scss becomes global. When HeaderComponent has default encapsulation, all rules defined in header.component.scss are isolated from global scope and becomes specific to HeaderComponent. As a matter of fact ng-deep works by making single rules global. In other words it removes rules from isolated scope and puts into the global scope and it is the only way of making a single rule global within an encapsulated styles file. Without help of ng-deep you can override child component styles in following ways;
Apply another global style to child and add related styles to global; styles.scss file.
in header.component.html
<labs-boxed class="custom-box-style">
in styles.scss
.custom-box-style .boxed {
// new rules
}
Programatically set styles on specific child instance.
in header.component.html
<labs-boxed #childEl class="squared">squared and red</labs-boxed>
in header.component.ts
#ViewChild('childEl', {read: ElementRef, static: true}) childEl: ElementRef;
ngAfterViewInit() {
const box = this.childEl.nativeElement.getElementsByClassName("boxed");
box[0].style.backgroundColor = "red"
}
Here is a demonstration of both approaches.

Grid Styling - Overwrite style of ag-grid

I have the following style:
.ag-theme-fresh .ag-row-selected {
background-color: #bde2e5;
}`
It comes from a css style file of a theme. But I want to overwrite it with this style:
.ag-theme-fresh .ag-row-even .ag-row-selected {
background-color: #1428df;
}
But it has not effect and my component uses the first style. How can I overwrite the first style 1? I tried with !important but it does nothing.
Should I define my custom style at the beginning of the css file?
UPDATE:
I found I can use the function gridOptions.getRowClass to set the style class to be used. But I would like to solve the issue central (for all the angular grids that I use in my application). Any idea?
You should use ViewEncapsulation
Just add to your component encapsulation: ViewEncapsulation.None:
import { Component, ViewEncapsulation } from "#angular/core";
#Component({
selector: '....',
templateUrl: '....',
styles: [`
.ag-theme-fresh .ag-row-selected {
background-color: #1428df !important;
}
`],
encapsulation: ViewEncapsulation.None
})
To override the ag-grid use you need to use ng-deep as the style defined in angular component do not overide ag-grid css
:host ::ng-deep .ag-header-cell-label {
justify-content: center;
}
update : this will make the style global. By changing the encapsulation set as none (ViewEncapsulation.None) at component will make style global as well.
if you are using sass or scss you could override in the style.scss/sass. this would be applicable at all places
#import "../node_modules/ag-grid-enterprise/dist/styles/ag-grid.scss";
#import "../node_modules/ag-grid-enterprise/dist/styles/ag-theme-alpine/sass/ag-theme-alpine-mixin";
.ag-theme-alpine {
#include ag-theme-alpine(
(
// use theme parameters where possible
alpine-active-color: #c066b2,
)
);
.ag-header-cell-label {
justify-content: center;
}
}
if you have need of doing at a specific grid, prefer custom class and make sub-class for the ag-grid.
You can also apply the styles globally and if you do so it will override the styles for all your ag-Grid components. This might not be an option if you are trying to style the components individually, but it's a good way to give a global base style override.
Also, you should try to use more specific selectors instead of using important.
Here is an example:
.ag-theme-alpine > .ag-row.ag-row-selected {
background : red;
}

Prevent global CSS being applied a component in Angular 5

In .angular-cli.json, I got some global styles:
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.css",
"../node_modules/font-awesome/css/font-awesome.css",
"../node_modules/ng2-toastr/bundles/ng2-toastr.min.css",
"styles.scss"
],
But I don't want any of them being applied to a specific component - is it achievable?
EDIT 1:
Unfortunately, overriding the CSS style in the component style won't work because the HTML in the template of the component is fetched from a Web API backend - I guess I can't realistically override every possible class/selector?
CSS cascades (hence the term, Cascading Style Sheets).
for full browser support your only option is to override selectors.
another option, not as common due to lack of support on IE and Edge,
is the all property.
html
<div class="component-container">
<!-- your components html template ... -->
</div>
css
.component-container {
all: initial;
all: unset;
}
Using component styles
For every Angular component you write, you may define not only an HTML template, but also the CSS styles that go with that template, specifying any selectors, rules, and media queries that you need.
One way to do this is to set the styles property in the component metadata. The styles property takes an array of strings that contain CSS code. Usually you give it one string, as in the following example:
#Component({
selector: 'app-root',
template: `
<h1>Test Text</h1>
`,
styles: ['h1 { font-weight: normal; }']
})
export class AppComponent {
/* . . . */
}
styleUrls
One or more URLs for files containing CSS stylesheets to use in this component.
styleUrls: string[]
styles
One or more inline CSS stylesheets to use in this component.
styles: string[]
You can use the :not selector in your global CSS.
You'd have to play around with it to get the desired behaviour but it should be something like this:
h1:not(.my-specific-class) {
font-size: 3rem;
}
You can use angular built in shadowDom API from view encapsulation. Which will make your component elements loaded inside a separate DOM tree so global css wont affect your component elements.
#Component({
selector: 'app-root',
template: `
<h1 class="head-app">Test Heading</h1>
`,
styles: ['./app.component.scss'],
encapsulation: ViewEncapsulation.ShadowDom
})
export class AppComponent {
/* . . .
You can define styles at component level using styleUrls property inside the scope of #Component. Please have a look at below code:-
#Component({
selector: 'app-manageUser',
templateUrl: './manageUser.component.html',
styleUrls: ['./manageUser.component.css'],
providers: [UserService]
})

Angular 2 #Component Styles

How can I use Angular 2 styles in #Component with multiple classes on the same tag?
#Component({
styles: `.class1 .class2{background-color:red;}`
})
This generates the following css code:
.class1[<RANDOM_ANGULAR_ATTR>] .class2[<RANDOM_ANGULAR_ATTR>]{
background-color: red;
}
This will not select a tag defined like this:
<div class=".class1 .class2" RANDOM_ANGULAR_ATTR></div>
Is there any way to make this approach work?
Your styles should have the classes without a space between them. Multiple classes in the same selector must be written directly after each another – with no white space. For example:
.class1.class2 { background-color:red; }
And in order to select your object you should have the classes added like this:
<div class="class1 class2">Test css</div>
See the code below:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
styles: [
`
.class1.class2{background-color:red};
` ],
template: `
<h1>My First Angular 2 App</h1>
<div class="class1 class2">Test css</div>
`
})
export class AppComponent { }
For more options see also the following blog posts (about Shadow DOM, Encapsulation Types .. any other cool things):
https://scotch.io/tutorials/all-the-ways-to-add-css-to-angular-2-components
http://blog.thoughtram.io/angular/2015/06/29/shadow-dom-strategies-in-angular2.html
Have you looked at Justin Schwartzenberger's NG-Conf talk on CSS styles and the randomly generated tag? https://www.youtube.com/watch?list=PLOETEcp3DkCq788xapkP_OU-78jhTf68j&v=J5Bvy4KhIs0
potential options are to:
Use a styleUrls template
change encapsulation
use a different class (since its only relevant to this component its ok to name something simple vs using 2)

Resources