How to add CSS to Angular Materials component? - css

I have a web app using angular 2 and angular materials. I am using a simple modal:
<h1 md-dialog-title *ngIf="data">{{data.title}}</h1>
<div md-dialog-content>What would you like to do?</div>
<div md-dialog-actions></div>
But when I run the app the modal's height is 100%. When I inspect with Chrome dev tools, it looks like Angular Materials/Angular 2 is injecting some classes that wrap around the md-dialog-content. Here is a snapshot:
Anyways, does anyone have any suggestion how to override the behavior so I can manually affect the size? Thanks.

Have you tried opening your dialog with specific height that you need? like:
let dialogRef = dialog.open(UserProfileComponent, {
height: '400px',
width: '600px',
});
Another way to force custom styles is to customize the theme itself. you can have a look at the guide here.

You can override material styling from your scss/css.
But due to view encapsulation, you need to use /deep/ selector that will allow you to get hold of the Material class added when the component is rendered. For example:
/deep/ .mat-tab-group.mat-primary .mat-ink-bar{
background-color: red;
}

Related

Angular component custom style from parents

I would like to enable custom CSS variables to customize a component in my Ionic application.
I read about using custom CSS properties but I can't figure out how it works.
From Angular official docs:
Authoring a component to support customization
As component author, you can explicitly design a component to accept customization in one of four different ways.
Use CSS Custom Properties (recommended)
You can define a supported customization API for your component by defining its styles with CSS Custom Properties, alternatively known as CSS Variables. Anyone using your component can consume this API by defining values for these properties, customizing the final appearance of the component on the rendered page.
While this requires defining a custom property for each customization point, it creates a clear API contract that works in all style encapsulation modes.
I tried using #HostBinding:
#HostBind('style.--custom-property') customProp;
But I don't understand how to apply the css property to my component from one of its parents.
Finally I found how to solve this:
Child component
.cmp-class {
color: var(--custom-color, red);
}
<div class="cmp-class"><p>Hello</p></div>
Parent component
child-cmp {
--custom-color: blue;
}
<child-cmp></child-cmp>
You can use ng-deep, for example from parent component use:
child-cmp ::ng-deep .cmp-class {
color: blue;
}

Angular - How To Organize CSS Overrides Across Components For The App

I'm relatively new to angular. In the process of converting a React app to Angular just for learning purposes. I have a parent component that has a button (Custom Button Component). This button when loaded in the parent should be hidden and on hover should show the button. So you probably get an idea that I have some CSS selectors related to the parent component that override the child CSS. First should be display: none and then on hover I change it to display: flex
So the first problem I encountered was that I could not override the child CSS from the parent CSS. After reading all kinds of posts I moved the CSS overrides from the parent CSS to the global stylesheet and also added encapsulation: ViewEncapsulation.None to the child component.
Next thing I noticed is that the align-items: center was not working on the child. First thought I had that guess I have to add that part to the global styles also? but what I really need to know is that is this the norm in Angular? If yes, then some things don't make sense to me. These styles are really not global. They are only related to the parent component then it seems kind of weird to add those to the global stylesheet.
In regards to the align-items not aligning the child (custom-button), I believe that happens because of the extra div being added around the button. So how do you handle such situations?
Appreciate any advice/tips.
Thank you!
You can overwrite children CSS classes from the parent componet. this is the way:
Assuming your child component have this CSS
.child-class {
background-color: blue;
}
When you use this component the background color will be blue. But if you want to change that color to RED. In the parent component where you want the change you need to do this:
In your parent component
:host {
::ng-deep{
.child-class {
background-color: red;
}
}
}
:host this refers to the component's HTML tag (that is created by Angular, in your case the tag of the component that contains the app-custom-button). Also you can apply css to the component tag.
for example:
:host{
width: 100vw;
height: 100vh
}
And with ::ng-deep you can overwrite ALL styles inside your compoent. Does not matter if is a style from your child compoenent, grandchild, great-great-grandson, etc... even if its a component from an external library.
So... For example you can have the "custom background color as blue" then in one component you can keep that color but in other component you can change the color to red and in other component you can change the color to green....
Angular have the concept of ViewEncapsulation. By default, the value is set to ViewEncapsulation.Emulated and the css you put in the component is specific to the component and only to this component. The CSS will not be applied to the child components.
You can switch to ViewEncapsulation.None and you will disable this behavior and all the css rules in your css file will be applied to all your components in the application, and maybe you don't want this behavior. That's why I advice you to leave this option.
The other option you got is to put your specific css rule in src/style.css (if you didn't modify the default path). All css rules put in this file will be applied for all the application and you can keep the ViewEncapsulation of your component.
For align-items, i think you are right : the app-custom-button is wrapping your button, so you need to set a width: 100% to your button, then eventualy resize your app-custom-button

How to change z-index of Angular CDK Drag and Drop?

I am using the Angular Material CDK Drag and Drop Functionality in my application. The drag and drop functionality is working fine, unless I am using it within a dialog (for most components I am using Nebular, in this case the Nebular dialog). The problem I am encountering is, as soon as I drag a draggable element within the dialog, the element disappears behind the dialog. After dropping it, it reappears on the correct position. In the screenshot, I am dragging the "AAAA" element away from the list - it disappears behind the dialog.
Stackblitz: https://stackblitz.com/edit/angular-znqckb
I am using the following implementation:
<div cdkDropList cdkDropListOrientation="horizontal" class="example-list" [cdkDropListData]="techs"
(cdkDropListDropped)="drop($event)">
<button *ngFor="let tech of techs" nbButton cdkDrag>{{tech}}</button>
</div>
Component.ts:
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.techs, event.previousIndex, event.currentIndex);
}
I did not modify the style sheet. I assume this issue can be solved somehow by modifying the z-index but I don't know how to apply it to the "dragging" element.
You can change the DragRefConfig injecting the right config (with the desired z-index) in your component. For example:
const DragConfig = {
dragStartThreshold: 0,
pointerDirectionChangeThreshold: 5,
zIndex: 10000
};
providers: [{ provide: CDK_DRAG_CONFIG, useValue: DragConfig }]
The z-index of the preview element will be 10000 ;-)
For more infos: https://material.angular.io/cdk/drag-drop/api#DragRefConfig
I'm struggling with this problem myself and I'm using a crude workaround for now. Forcing the z-index of .cdk-overlay-container to 1000 in your global styles (styles.scss) should get you the result you want. It's not best practice though.
Add this in styles.scss:
.cdk-overlay-container {
z-index: 1000 !important;
}
Stackblitz here
To my knowledge, it's not possible to force a z-index on the drag preview ("dragging" element) because the cdk sets its z-index dynamically as inline style. The Nebular library you are using seems to be setting the z-index of the overlay container to 1040. The Angular Material library sets the drag preview's z-index as 1000, that's why it goes behind the overlay. Vanilla Angular Material sets the z-index of cdk overlay to 1000, so drag & drop will work in that scenario.
For previous angular material versions than 9.
In the html dragable element:
<div ... cdkDrag (cdkDragStarted)="onDragStarted($event)"</div>
In the compoonent ts:
export class ...{
zIndexSerial: number = 1000;
onDragStarted(event: CdkDragEnd): void {
event.source.element.nativeElement.style.zIndex=this.zIndexSerial+"";
this.zIndexSerial = this.zIndexSerial+1;
}
for anyone struggling with the same issue.I found the solution to be z-index only work on positioned elements Refer to this link description here
For Angular version 8, I added the following to styles.scss and got it to work in the modal:
.cdk-drag-preview {
z-index: 9000 !important;
}
See .cdk-drag-preview in https://material.angular.io/cdk/drag-drop/overview#styling

Changing body css from within an Angular component

Angular4
Hi All. I'm have a single page within a large Angular4 app that needs to have body css that's different to the rest of the app.
I don't want to set ViewEncapsulation.None because it's just the one component that needs to be affected.
Can I use :host(), :host-context() or ::ng-deep in some way to select the body and apply the css rules? If so then how please? If not, is there another way to achieve this?
Thanks!
Thank you both very much. #Palpatine1991, you asked why I would want to access the <body> DOM element. This is because I have one page in the app which is a full screen game that is played on mobile devices and has drag and drop functionality within it. On iOS the "bounce" effect present in Safari makes drag and drop a very poor experience. So I wanted to add the following css to the body and html DOM elements of that single page, which suppresses that bounce effect.:
html,
body {
height: 100%;
width: 100%;
overflow: auto;
}
I had a look into the solutions you gave (thank you!) and went with the following solution:
ngOnInit() {
this.renderer2.addClass(document.body.parentElement, 'wholeClassGameBody_student');
this.renderer2.addClass(document.body, 'wholeClassGameBody_student');
}
ngOnDestroy() {
this.renderer2.removeClass(document.body.parentElement, 'wholeClassGameBody_student');
this.renderer2.removeClass(document.body, 'wholeClassGameBody_student');
}
This seems to work.
Thank you :)
Why do you need to add your CSS to <body> if it affects only one component?
Using :host() it will apply the styles to the element which is selected by component's selector.
Using ::ng-deep you can select only elements which are somewhere under the host element (but <body> is not under your host!)
The only way how to change the styles of the body from the component which has ViewEncapsulation.Emulated is using the Renderer2 API but it seems to me like a very bad practice
If you need to override some global <body> styling of your component, you can do it using :host-context. Example here: https://stackblitz.com/edit/angular-material2-issue-oodjmm

How to edit css of child component imported from other module Angular 2+

I use agm-snazzy-window from amg-snazzy-window
There is explanation that I can override css class but when I do it it won't work.
This is my example:
map-component.html
<agm-snazzy-info-window [closeWhenOthersOpen]="true">
<ng-template>
My snazzy window
</ng-template>
</agm-snazzy-info-window>
I want to have wider content so I made this:
map-component.scss:
.si-content {
width: 500px !important;
}
What am I doing wrong?
::ng-deep .si-content {
width: 500px !important;
}
This will tell angular to attach correct ViewEncapsulation.Emulated classes to your styles. It doesn't do this by default because it cannot find them in your template.
Without ::ng-deep, your style will be .si-content[_ngcontent-1], or something similar. In such case [_ngcontent-1] comes from the map-component. Using ::ng-deep you instruct angular to look for "deeper" to find correct component agm-snazzy-info-window.

Resources