In my Angular application, I have two components, A and B, the first is a toggle button and the second is a form. B component subscribes to the state of the A component using a service in order to set its CSS according to the observed toggle state. For example, if the A component is set to state 'leftPressed', the component B reacts to this state setting its own CSS to 'enable' (through [ngStyle]) in order to make the form usable by the user, instead if the A component is set to the state 'rightPressed' the B component sets its own CSS to 'disable'. This is the code of the CSS disable style:
.disable {
opacity: 30%;
pointer-events: none;
}
This strategy will opacize the form and make the same form not clickable by the user.
My problem is that this thing worked until I introduced in my project Bootstrap in order to make my application more responsive (I have just placed these two buttons in the div-row-col scheme according to the Bootstrap modus operandi), but the strange thing is that only the opacity does not work on the B component but the 'mouse-event: none' worked as expected.
How can it be possibile that a CSS, in that case, is valued partially? The only thing I know is that if I roll back putting those components in my previous HTML without Bootstrap code, everything works fine.
Update with more code:
This is the code of my HTML component in which is declared more components
<!--This is the bar without Bootstrap that works-->
<div class="searchBar">
<app-button-search-city-polygon-component></app-button-search-city-polygon-component>
<app-search-city-bar [ngClass]="[cityBarStyle]"></app-search-city-bar>
<app-clear-polygon-bar [ngClass]="[polygonBarStyle]"></app-clear-polygon-bar>
<app-button-search-centers-or-operators></app-button-search-centers-or-operators>
<app-validate-and-search-button></app-validate-and-search-button>
</div>
<!--This is the bar developed using Bootstrap and the CSS opacity DOES NOT WORK on the component 'app-search-city-bar'-->
<div class="searchBar row align-content-lg-center">
<div class="col-lg-1">
</div>
<div class="col-lg-2">
<app-button-search-city-polygon-component></app-button-search-city-polygon-component>
</div>
<div class="col-lg-4">
<app-search-city-bar [ngClass]="[cityBarStyle]"></app-search-city-bar>
</div>
<div class="col-lg-1">
<app-clear-polygon-bar [ngClass]="[polygonBarStyle]"></app-clear-polygon-bar>
</div>
<div class="col-lg-2">
<app-button-search-centers-or-operators></app-button-search-centers-or-operators>
</div>
<div class="col-lg-1">
<app-validate-and-search-button></app-validate-and-search-button>
</div>
<div class="col-lg-1">
</div>
</div>
This is the CSS of this component:
.searchBar {
background-color: #eeeeee;
padding-top: 15px;
display: flex;
justify-content: center;
}
.cityBarDisabled {
opacity: 30%;
pointer-events: none;
}
.polygonBarDisabled {
opacity: 30%;
pointer-events: none;
}
.cityBarEnabled {
}
.polygonBarEnabled {
}
This is the TS code:
import {AfterViewInit, Component, OnInit} from '#angular/core';
import {Subscription} from 'rxjs';
import {ToggleCityPolygonService} from '../../_service/toggleCityPolygonService/toggle-city-polygon.service';
#Component({
selector: 'app-search-bar',
templateUrl: './search-bar.component.html',
styleUrls: ['./search-bar.component.css']
})
export class SearchBarComponent implements OnInit {
state = '';
cityBarStyle = '';
polygonBarStyle: '';
constructor(private toggleCityPolygonService: ToggleCityPolygonService) {
}
ngOnInit(): void {
this.toggleCityPolygonService.getCityPolygonStateObs().subscribe(v => {this.state = v[''];
// console.log('i\'m gettin value: ' + v);
if (v === 'searchByCity') {
// #ts-ignore
this.polygonBarStyle = 'polygonBarDisabled';
this.cityBarStyle = 'cityBarEnabled';
} else {
if (v === 'searchByPolygon'){
this.cityBarStyle = 'cityBarDisabled';
// #ts-ignore
this.polygonBarStyle = 'polygonBarEnabled';
}
}
})
}
}
The 'toggleCityPolygonService' is the service which holds the 'cityPolygonState' that change between two values when the user click on the relative toggle button which can assume only two states: 'searchByCity' and 'searchByPolygon'
Opacity takes value 0.1 - 1. Try changing opacity: 30% to opacity: 0.3;
https://www.w3schools.com/css/css_image_transparency.asp
This is not the issue caused by Bootstrap. It's because of css optimiser (cssnano) on production build.
To avoid this, you can use the values between 0 and 1.
In your case, you can use 0.3 instead 30%.
opacity: 0.3; // opacity: 30%;
MDN guild on opacity
Issue reported on GitHub
Related
I have some code that looks like this:
<section>
<div style="height: 100%; max-width: 10%; background-color: deepskyblue;">my content</div>
<router-outlet style="height: 100%; min-width: 90%; background-color: gold;"></router-outlet>
</section>
I want the div to work as a side-bar with the router-outlet taking up the remaining 90% of the space. But what ends up happening is that the content displayed from the router-outlet is pushed beneath the div rather than beside it. It also appears that no CSS is being applied to the router-outlet, as the background color doesn't change. Is there any way to get CSS to make changes to this router-outlet?
simple solution is to to just put router-outlet in a style div.
<section>
<div style="height: 100%; max-width: 10%; background-color: deepskyblue;">my content</div>
<div style="height: 100%; min-width: 90%; background-color: gold;">
<router-outlet ></router-outlet>
</div>
</section>
Short answer
Use:
:host { background: cornflowerblue; }
as the css for the hosted component, to change background of the router outlet.
Long Answer:
Angular CSS pseudo selector/modifier
You can affect the hosting component with the :host modifier. In the case that you would like to change the router oulet styling, add css to the component that will be hosted.
e.g. Change the router outlet blue when showing the page-edit component.
// This is your routing to place your page component in the outlet when
navigating to the edit/1 url.
const routes: Routes = [
{
path: 'edit/:pageId',
component: PageComponent,
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PageEditorRoutingModule {}
// PageComponent - stub of component to be rendered in outlet.
#Component({
selector: 'app-page-editor',
templateUrl: './page-editor.component.html', //implement as desired.
styleUrls: ['./page-editor.component.scss']
})
export class PageEditComponent {
// Your implementation
}
// Put this in your page-editor.component.scss to change the router outlet background blue
:host{
background: cornflowerblue;
}
I have been struggling with this for a quite some time now, and i couldn't find a sufficient answer. Basically i have one parent component which html goes as follows:
<div class="container">
<child-one></child-one>
<child-two></child-two>
</div>
the problem is that the child-one component has its size set as auto, with some padding to look good,
child-one {
width: auto;
height: auto;
padding: 0.5rem;
}
and child-two has a fixed width and height in it's own scss.
child-two {
width: 10rem;
height: auto;
}
is there a way to somehow change the width of child-two in the parent without editing the child-two?
I was hoping for something along the lines of storing the width of the child-one, and setting the width of child-two to the same value.
child-one {
width:auto;
padding: 0.5rem;
$width: this.width !global //idk about this one
}
child-two {
width: $width
padding: 0.5rem
}
please note that the child-one and child-two scss don't look this way in the code, and are normally written, this is just for the purpose of simplifying the question
Is this what you are looking for?
app.component.html - Parent Component
<child-one #childOne></child-one>
<child-two #childTwo></child-two>
<br>
<button (click)="changeWidth()">Change child two width</button>
app.component.ts
export class AppComponent {
#ViewChild('childOne', {
read: ElementRef
}) childOne: ElementRef;
#ViewChild('childTwo', {
read: ElementRef
}) childTwo: ElementRef;
constructor(private renderer: Renderer2) {}
changeWidth() {
const childOneWidth = this.childOne.nativeElement.getElementsByClassName('child-one')[0].offsetWidth;
const childTwoElement = this.childTwo.nativeElement.getElementsByClassName('child-two')[0];
this.renderer.setStyle(childTwoElement, 'width', `${childOneWidth - 2}px`);
}
}
Here is the working Stackblitz
Suggestion
#SivakumarTadisetti's suggestion is a valid suggestion, alternatively, you could use ngStyle to provide dynamic styling for the component or ngClass for conditionally applying style class to the component. You could, which requires more code, also write a directive that changes the style behaviour of the component based on certain conditions.
Example using ngStyle
https://stackblitz.com/edit/stack-help-01
I'm building a library and I have a <my-card> component. It's a component that will often have a (click) handler on it.
What I'm looking to do is to add cursor: pointer automatically when the component has (click) attached to it.
So for example, <my-card> would have the default cursor, and <my-card (click)="onClick()> would apply cursor: pointer to the component element.
Any clean way of doing this?
If you're able to change (click) to click then you could do this using CSS.
HTML:
<my-card>Look at me</my-card>
<my-card click="onClick()">Click me</my-card>
CSS:
my-card {
border-radius: 3px;
display: inline-block;
padding: 5px;
}
[click] {
background-color: red;
color: white;
cursor: pointer;
}
The [click] part in the CSS references an attribute of an element. So, this will target any element you use with the click attribute. If you only want to target any <my-card> element with the click attribute then you would change your CSS to my-card[click].
Here's a fiddle for you to reference: https://jsfiddle.net/8w9Lqxr4/1/
The Angular way to do this is to use a directive, take a look at this example:
import { HostBinding, Directive } from '#angular/core'
#Directive({
selector: '[myClick]'
})
class MyClickDirective {
#HostBinding('class.mousepointer') private isClick: boolean;
constructor(private el: ElementRef,
private renderer: Renderer) {
}
#HostListener('click') onMyElemClicked() {
this.isClick =!this.isClick;
}
}
I've not tested this example but this is the way you must investigate.
I was developing a login screen within angular with the within the app.component.html as such:
app.component.ts
<div class="container">
<app-login></app-login>
</div>
and css as such:
login.css
.form-group {
display: block;
margin-bottom: 15px;
}
.form-group label {
display: block;
margin: 0 0 5px 0;
}
app.component.css
.container {
display: grid;
height: 100%;
}
app-login {
width: 100%;
max-width: 274px;
place-self: center;
}
However, since I have now incorporated routing into my app, I display the login page using the <router-outlet> component, but this has ruined the CSS of the login page is it once was...
app.component.ts
<div class="container">
<router-outlet></router-outlet>
</div>
How can I change my CSS files such that I can get back the look I once had?
Here is a stackblitz to my example
Update
Solution found to the missing CSS (see below)
However now it appears is hogging much of the screen, pushing my element downward?
You need to set
encapsulation: ViewEncapsulation.None
on the AppComponent to allow styles to affect also those components which are used inside AppComponent.
import { Component, ViewEncapsulation } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ],
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
name = 'Angular';
}
But it will be better to use styles on those components for which they were declared.
This is a working Stackblitz.
You were targeting <app-login> in the app.component.css file and styling it to have a fixed width and align it center. What you have to remember is that, Angular enforces emulated view encapsulation and also when you are using router, <app-login> may be changed to some random dynamic name at run time thereby making your css classes that you might have written in app.component.css ineffective.
Its always a best practice to write styles for a component in its respective CSS file rather than the root components css file.
Here is a changed Stackblitz
Here is the result:
I'm working with angular and angular-material.
Inside a page, I have a form, and some buttons (grouped in a div) which are depending on this form.
But, I'd like to have these buttons (the div) sticking the bottom of the page, even if I scroll.
Here's some code :
<form (ngSubmit)="update()" #updateForm="ngForm">
<div> some content with inputs and selects </div>
<div class="button-container"> buttons like save, cancel, ... </div>
</form>
and :
.button-container {
position: sticky !important;
bottom: 0;
float: right;
z-index: 999;
}
If I put the buttons out of the form, they don't work anymore. Thing is, it'd be better if I don't change the buttons' methods, and only modify HTML and CSS.
What I did doesn't work, any idea ?
I did this on plunker, with the same CSS properties as my project https://plnkr.co/edit/pw7zOruWwhV0o1Vya717?p=preview
In case you cannot reproduce the failing version in plunkr, then some other css-styling in your project might be preventing the sticky-position.
In my case the sticky-position did not work in case the containing div had
overflow:hidden;
Maybe you have the value set on the containing div?
I think I had the same problem. Normally I would use position fixed but this wouldn't work because material used transform: translate3d(0,0,0). This made fixed to behave like absolute. To solve this problem I used the below:
//Place this in your form
<app-fnls-displacer>
<div style="position: fixed; right: 30px; bottom: 30px; padding-bottom: 2em; z-index: auto">
<button mat-fab class="fab" type="submit" (click)="myfunction()">
<mat-icon>add</mat-icon>
</button>
</div>
</app-fnls-displacer>
This is the component and directive used:
import {AfterViewInit, Component, Directive, OnDestroy, TemplateRef, ViewChild, ViewContainerRef} from '#angular/core';
import {Overlay, OverlayRef, OverlayConfig, TemplatePortal} from '#angular/material';
#Directive({ selector: '[displacerPortal]' })
export class DisplacerPortalDirective extends TemplatePortal<any> {
constructor(templateRef: TemplateRef<any>, viewContainerRef: ViewContainerRef) {
super(templateRef, viewContainerRef);
}
}
#Component({
selector: 'app-fnls-displacer',
template: `
<ng-template displacerPortal>
<ng-content></ng-content>
</ng-template>
`
})
export class DisplacerComponent implements OnDestroy, AfterViewInit {
private _config = new OverlayConfig();
#ViewChild(DisplacerPortalDirective)
private _portal: DisplacerPortalDirective;
private _overlayRef: OverlayRef = undefined;
constructor(private _overlay: Overlay) {}
public ngOnDestroy() {
this._overlayRef.detach();
}
public ngAfterViewInit() {
this._overlayRef = this._overlay.create(this._config);
this._overlayRef.attach(this._portal);
}
}
I found it on a material GitHub page. It places the content inside it directly to the body, so that you can use position: fixed.
Set a fixed height to the scrolling element and fix the button position:
<div style="height:calc(100vh - 100px) !important; overflow: scroll !important" class="mat-tab-body-content ng-trigger ng-trigger-translateTab">
......
<button style="top: calc(100vh - 50px) !important; position: fixed !important" md-button (click)='alert("clicked!");'>button</button>
Plunker