Angular 5 and :host pseudo class - css

I have been using the :host pseudo class in Angular 4 with no problems. We are converting to Angular 5, and now the style does not seem to be getting added to the host component. Is there a different way to add this now in the new version of Angular?
:host {
border: 10px solid black;
&.isLeft {
display: flex;
}
}
#media (max-width: 599px) {
:host {
display: flex;
}
}
The isLeft class is set up based on a parameter that is passed into the component from the parent component because this particular control can be displayed in 2 different formats, one of which is responsive. Inside the component, I have the following code:
#HostBinding('class.isLeft') isLeft: boolean;
#Input()
placement: string = 'responsive';
ngOnInit() {
this.isLeft = (this.placement.toLowerCase() === 'left');
}
I know there is a suggestion to use #HostBinding to do all of this. First of all, I'm not sure how that would work when I have to use media queries. Secondly, the only way to use #HostBinding with this would be to include styling inside the component, which goes against our company standards.
Thanks in advance!

You could use:
#HostBinding('style.border') styleborder = '10px solid black';
define isLeft in css, and put:
#HostBinding('class.isLeft') someField: boolean = true;

Code had included
encapsulation: ViewEncapsulation.None
Is working now that that is removed.

Related

Can Lit or Web Components know attribute of parent component?

I have code like this:
<theme-component theme="dark">
<my-component></my-component>
</theme-component>
Is it possible for my-component to know it is within theme-component with a theme of dark? Or do I also need to pass theme=dark manually into my-component?
my-component has styles defined like this:
static darkStyle = css`
:host {
--my-bkg: #535353;
--my-items: #474747;
--my-gutter: #4a4a4a;
--my-border: #474747;
--my-item-border: #535353; /* on dark themes only this is the same color as the background instead of the footer border */
--my-divider: #636363;
}
`;
static lightStyle = css`
:host {
--my-bkg: #b8b8b8;
--my-items: #c7c7c7;
--my-gutter: #ababab;
--my-border: #adadad;
--my-item-border: #adadad; /* on light themes only this is the same color as the footer border */
--my-divider: #9e9e9e;
}
`;
static styles = [this.darkStyle, sheet];
I would love to have some kind of ternary to switch between this.darkStyle or this.lightStyle. Or is there some kind of CSS I can write that is like
static styles = [css`
theme-component[theme=dark] :root {
--my-bkg: #535353;
}
`, sheet];
I see documentation about SuperElement.styles, but it's not clear to me how to use that when I am relying on variables based on an attribute here. I'm not trying to share a style as much as use the attribute to determine some new variables.
Edit after clarifications:
A component could technically find out the attribute on a direct parent component by imperatively doing the following:
this.parentElement.getAttribute('theme').
I am not sure how that could be done in CSS. Below this edit I've outlined a common approach to solving the issue of theming using CSS custom-properties which have the default behavior of inheriting through the shadow DOM. Also see video by Lit team: "How to style your Lit elements" for more context.
Original answer:
I think what you're looking for is the :host() CSS pseudo-class function.
Your setup is correct where the theme-component is providing CSS custom properties that inherit to all children. my-component does not need any changes.
The only change from your example that should be needed is:
static darkStyle = css`
:host([theme="dark"]) {
--my-bkg: #535353;
--my-items: #474747;
--my-gutter: #4a4a4a;
--my-border: #474747;
--my-item-border: #535353;
--my-divider: #636363;
}
`;
This will select and apply the dark theme CSS custom properties when the theme-component has the theme attribute set to value "dark". These custom properties will then inherit into the children.
Runnable sample:
<script type="module">
import {html, css, LitElement} from "https://cdn.jsdelivr.net/gh/lit/dist#2/core/lit-core.min.js";
class ThemeEl extends LitElement {
static styles = css`
:host {
--my-bkg: green;
display: block;
border: 2px dotted var(--my-bkg);
}
:host([theme="dark"]) {
--my-bkg: gray;
}
`;
render() { return html`<slot></slot>`; }
}
class ChildEl extends LitElement {
static styles = css`
:host {
display: block;
background-color: var(--my-bkg);
}
`;
render() { return html`<p>Child El</p>`; }
}
customElements.define('theme-el', ThemeEl);
customElements.define('child-el', ChildEl);
</script>
<theme-el>
<p>Default Theme</p>
<child-el></child-el>
</theme-el>
<theme-el theme="dark">
<p>Dark Theme</p>
<child-el></child-el>
</theme-el>
This technique can also be used such that a custom element can change its own host styling. By setting attributes on itself and using :host().
If the child component also needs to know what theme is set from JavaScript, that could also be communicated via a CSS custom property and queried with window.getComputedStyle(this).getPropertyValue(<custom property>).

How I can override specific styles of MUI Accordian in next.js by using css module

I want to override the default MUI CSS of the accordion component and I want to do this using the CSS module but problem is that the class is dynamically added by mui. Hence I cannot target that class directly.
I tried this below solution but it is not working:-
Css code:-
`.accordian_summary {
&:global(.MuiAccordionSummary-root) {
padding: 0px !important;
}
&:global(.MuiAccordionSummary-content) {
display: block !important;
}
}`
JSX Code:-
Accordian component code
DOM Tree structure and the class which I want to override
Browser code
*Note:- One of the CSS is getting applied i.e
`&:global(.MuiAccordionSummary-root) { padding: 0px !important; } `
but this is not working
` &:global(.MuiAccordionSummary-content) {
display: block !important;
}`
Please help if possible and Thanks for your help in advance.
Possible solution:
div[class*="MuiAccordionSummary-root"] {
display: block;
}
For example to change style for input error label:
label[class*="Mui-error"] {
text-decoration: underline;
}

Dynamically generating CSS classes at runtime in Angular 7

I have an Angular 7 application where I need to dynamically generate CSS classes in my component at runtime.
First off: I know about [ngStyle] and [ngClass]! I need to do some stuff using pseudo-selectors which I can't generate using these.
Now, the naive approach: I'll just use Angular to template my CSS!
<style *ngFor="let class of classes">
.{{class.prefix}}-target {
border: 1px solid maroon;
text-align: center;
}
.{{class.prefix}}-control:hover ~ .{{class.prefix}}-target {
background: red;
}
</style>
The problems with this approach:
VS Code complains that I'm putting Angular templating inside a CSS class.
Angular doesn't interpolate {{class.prefix}} in the final resulting HTML- it just literally puts {{class.prefix}} there.
Is there a way to do this in Angular, either with a library that's meant for this or an approach I can use? Thanks in advance!
Depending upon how dynamic you need the component to be...
You could declare the prefix (or dynamically generate it) outside of the component class. Then use a JavaScript template string to interpret the styles before they get processed by the #Component() decorator's metadata.
Like so:
const classPrefix = 'bar';
#Component({
selector: 'app-foo',
template: `
<!-- Your HTML template -->
`,
styles: [`
.${classPrefix}-target {
border: 1px solid maroon;
text-align: center;
}
.${classPrefix}-control:hover ~ ${classPrefix}-target {
background: red;
}
`]
})
export class FooComponent {
/* . . . */
}

overriding body background color in angular 7 [duplicate]

This question already has answers here:
How to change <body> tag style from child component?
(3 answers)
Closed 2 years ago.
I have been trying to override the background body of my login and register components but it's not working
I tried adding a div with a CSS class setting its background color but the bottom part of the page isn't set to the color I picked.
I would appreciate any suggestion on the best way to solve it.
.login-page{
height: 100% !important;
background-color: #e40134 !important;
}
If you want change the class of body in some components you use ngOnInit and ngOnDestroy
//inject in the constructor the "document"
constructor(#Inject(DOCUMENT) private _document) { }
//in init you add a class to de body
ngOnInit() {
this._document.body.classList.add('new-body-class');
}
//in destroy remove the class
ngOnDestroy() {
this._document.body.classList.remove('new-body-class');
}
And
.new-body-class{
background-color: #e40134;
}
The new-body-class can be a class defined in styles.css or you can use ViewEncapsulation.None. Be Carefull, ViewEncapsulation.None makes that the .css of the componet is common to all the aplication, so if you write, e.g.
h5{color:red}
.new-body-class{
background-color: #e40134;
}
futhermore change the background, all yours h5 in your application becomes red
Use encapsulation key at #Component
import {Component, ViewEncapsulation} from "#angular/core";
#Component({
selector: 'login-page',
templateUrl: './login-page.component.html',
encapsulation: ViewEncapsulation.None
})
and use ::ng-deep in css => https://blog.angular-university.io/angular-host-context/
for example:
::ng-deep .login-page {
height: 100% !important;
background-color: #e40134 !important;
}
These are the different ways of encapsulation:
I think this is actually a problem because your has a margin by default.
So in styles.scss, I would just add this:
body: {
margin: 0
}
Try with
.login-page{
height: 100vh !important;
background-color: #e40134 !important;
}
If with this you still do not have the expected result you can add position: absolute.
In any case you can always reset the body by applying a margin: 0. It would be very helpful to know what you see if you inspect it with the browser.

Angular2 Material Dialog css, dialog size

Angular2 material team recently released the MDDialog https://github.com/angular/material2/blob/master/src/lib/dialog/README.md
I'd like to change the looking and feel about the angular2 material's dialog. For example, to change the fixed size of the popup container and make it scrollable, change the background color, so forth. What's the best way to do so? Is there a css that I can play with?
There are two ways which we can use to change size of your MatDialog component in angular material
1) From Outside Component Which Call Dialog Component
import { MatDialog, MatDialogConfig, MatDialogRef } from '#angular/material';
dialogRef: MatDialogRef <any> ;
constructor(public dialog: MatDialog) { }
openDialog() {
this.dialogRef = this.dialog.open(TestTemplateComponent, {
height: '40%',
width: '60%'
});
this.dialogRef.afterClosed().subscribe(result => {
this.dialogRef = null;
});
}
2) From Inside Dialog Component. dynamically change its size
import { MatDialog, MatDialogConfig, MatDialogRef } from '#angular/material';
constructor(public dialogRef: MatDialogRef<any>) { }
ngOnInit() {
this.dialogRef.updateSize('80%', '80%');
}
use updateSize() in any function in dialog component. it will change dialog size automatically.
for more information check this link https://material.angular.io/components/component/dialog
Content in md-dialog-content is automatically scrollable.
You can manually set the size in the call to MdDialog.open
let dialogRef = dialog.open(MyComponent, {
height: '400px',
width: '600px',
});
Further documentation / examples for scrolling and sizing:
https://material.angular.io/components/dialog/overview
Some colors should be determined by your theme. See here for theming docs:
https://material.angular.io/guide/theming
If you want to override colors and such, use Elmer's technique of just adding the appropriate css.
Note that you must have the HTML 5 <!DOCTYPE html> on your page for the size of your dialog to fit the contents correctly ( https://github.com/angular/material2/issues/2351 )
With current version of Angular Material (6.4.7) you can use a custom class:
let dialogRef = dialog.open(UserProfileComponent, {
panelClass: 'my-class'
});
Now put your class somewhere global (haven't been able to make this work elsewhere), e.g. in styles.css:
.my-class .mat-dialog-container{
height: 400px;
width: 600px;
border-radius: 10px;
background: lightcyan;
color: #039be5;
}
Done!
You can inspect the dialog element with dev tools and see what classes are applied on mdDialog.
For example, .md-dialog-container is the main classe of the MDDialog and has padding: 24px
you can create a custom CSS to overwrite whatever you want
.md-dialog-container {
background-color: #000;
width: 250px;
height: 250px
}
In my opinion this is not a good option and probably goes against Material guide but since it doesn't have all features it has in its previous version, you should do what you think is best for you.
sharing the latest on mat-dialog
two ways of achieving this...
1) either you set the width and height during the open
e.g.
let dialogRef = dialog.open(NwasNtdSelectorComponent, {
data: {
title: "NWAS NTD"
},
width: '600px',
height: '600px',
panelClass: 'epsSelectorPanel'
});
or
2) use the panelClass and style it accordingly.
1) is easiest but 2) is better and more configurable.
For the most recent version of Angular as of this post, it seems you must first create a MatDialogConfig object and pass it as a second parameter to dialog.open() because Typescript expects the second parameter to be of type MatDialogConfig.
const matDialogConfig = new MatDialogConfig();
matDialogConfig.width = "600px";
matDialogConfig.height = "480px";
this.dialog.open(MyDialogComponent, matDialogConfig);
dialog-component.css
This code works perfectly for me, other solutions don't work.
Use the ::ng-deep shadow-piercing descendant combinator to force a style down through the child component tree into all the child component views. The ::ng-deep combinator works to any depth of nested components, and it applies to both the view children and content children of the component.
::ng-deep .mat-dialog-container {
height: 400px !important;
width: 400px !important;
}
I think you need to use /deep/, because your CSS may not see your modal class. For example, if you want to customize .modal-dialog
/deep/.modal-dialog {
width: 75% !important;
}
But this code will modify all your modal-windows, better solution will be
:host {
/deep/.modal-dialog {
width: 75% !important;
}
}
This worked for me:
dialogRef.updateSize("300px", "300px");
You can also let angular material solve the size itself depending on the content.
This means you don't have to cloud your TS files with sizes that depend on your UI. You can keep these in the HTML/CSS.
my-dialog.html
<div class="myContent">
<h1 mat-dialog-title fxLayoutAlign="center">Your title</h1>
<form [formGroup]="myForm" fxLayout="column">
<div mat-dialog-content>
</div mat-dialog-content>
</form>
</div>
my-dialog.scss
.myContent {
width: 300px;
height: 150px;
}
my-component.ts
const myInfo = {};
this.dialog.open(MyDialogComponent, { data: myInfo });
On smaller screen's like laptop the dialog will shrink. To auto-fix, try the following option
http://answersicouldntfindanywhereelse.blogspot.com/2018/05/angular-material-full-size-dialog-on.html
Additional Reading
https://material.angular.io/cdk/layout/overview
Thanks to the solution in answersicouldntfindanywhereelse (2nd para).
it worked for me.
Following is needed
import { Breakpoints, BreakpointObserver } from '#angular/cdk/layout'
component.ts
const dialog = matDialog.open(DialogComponent, {
data: {
panelClass: 'custom-dialog-container',
autoFocus: false,
},
});
styles.scss
// mobile portrait:
#media (orientation: portrait) and (max-width: 599px) {
// DIALOG:
// width:
.cdk-overlay-pane {
max-width: 100vw !important;
}
// padding
.custom-dialog-container .mat-dialog-container {
padding: 5px !important;
}
}

Resources