Can't select a bound attribute in Angular - css

I have a custom progress bar in angular. I'd like to bind to have a selector for the [value]. However if I bind the attribute in Angular it is no longer possible to select.
<progress-bar value="50"> works
<progress-bar [value]="value"> fails
The attribute doesn't exist in the second case it's just there as one of the ng-reflect-* attributes. Is this expected behavior?
component:
ProgressBar {
private currentValue;
#Input() set value(value: number) { this.currentValue = value; }
get value() { return this.currentValue; }
...
}
scss:
progress-bar {
display: block;
height: 4px;
width: 100%;
// determinate
&[value] {
background: map_get($color-palette, progress-bar-background);
.progress {
height: 100%;
background: map_get($color-palette, progress-bar-color);
animation: none;
transform-origin: top left;
transition: transform 250ms ease;
}
}
// indeterminate
&:not([value]) {
background: transparent;
}
}

Instead of property binding, you can use attribute binding:
<progress-bar [attr.value]="value">
export class ProgressBar {
constructor(private elementRef: ElementRef<HTMLElement>) {}
get value() {
const element = this.elementRef.nativeElement;
return element.getAttribute("value");
}
}
See this stackblitz for a demo.
A simpler solution is to set a class conditionally on the component with HostBinding:
export class ProgressBar {
private currentValue;
#Input()
get value() { return this.currentValue; }
set value(value: number) { this.currentValue = value; }
#HostBinding("class.has-value") get hasValue(): boolean {
return !!this.currentValue;
}
}
and to apply the styling according to the class selector:
progress-bar {
...
&.has-value {
...
}
&:not(.has-value) {
...
}
}
See this stackblitz for a demo.

You are trying to use a one way property binding between a object and method. Remove your getter and setter methods. They are kinda of useless since javascript doesn't have real private properties or methods.
ProgressBar {
#Input() public value: number
...
}

Related

Is it possible to use styles from an Angular service in scss?

I have a change-color.service.ts that has the following:
public defaultStyles = {
firstDesignBackgroundColor: '#a31329',
firstDesignFontColor: '#ffffff',
secondDesignBackgroundColor: '#d1cfcfff',
secondDesignFontColor: '#000000'
};
now I will like to add to my style.scss for the statement
:host ::ng-deep th span#optimize-checkbox-header .mat-checkbox label.mat-checkbox-layout .mat-checkbox-inner-container.mat-checkbox-inner-container-no-side-margin .mat-checkbox-frame {
border: 2px solid #fff !important;
}
replace the #fff with firstDesignFontColor from the change-service. Do you know how I can create this dependency? Is this possible at all?
There is actually a way to realize it with css variables that I will post here as a second answer.
You can change css variables from JavaScript code, so if you use variables for your class like this simplified example:
:root {
--bg-color: red;
}
.test {
background-color: var(--bg-color);
}
then you can change this from your ChangeColorService
interface Colors {
background: string;
}
#Injectable()
export class ChangeColorService {
colors$ = new BehaviorSubject<Colors>({ background: 'red' });
constructor(#Inject(DOCUMENT) private document: Document) { }
change(colors: Colors) {
const root = this.document.documentElement;
root.style.setProperty('--bg-color', colors.background);
this.colors$.next(colors);
}
}
Full example:
https://stackblitz.com/edit/angular-change-css-variable?file=src/app/app.component.ts
No that's not possible. What is possible, is to use style bindings.
class YourComponent {
styles: any;
constructor(private color: ChangeColor) {}
ngOnInit() { this.styles = this.color.defaultStyles; }
}
<div [style.background-color]="styles.firstDesignBackgroundColor"></div>

How to animate a MatDialog on close using scss/sass?

I am tending to override the scss-animations inside #angular/material/dialog. I have tried many ways and read many articles but I am still unable to reach to a solution. When the MatDialog popup opens, it has its own animations but when I close it, it closes immediately (without animation).
Firstly, the dialog opens by means of my NotifierService which looks like the following:
notifier.service.ts
#Injectable()
export class NotifierService {
...
constructor(
private dialog: MatDialog,
private dialogRef: MatDialogRef<OverlayComponent>
) { }
...
public open(notification: Notification): void {
this.dialogRef = this.dialog.open(NotificationComponent, {
...
panelClass: 'notifications-popup',
data: {
notification: notification
}
});
}
...
}
In my global scss file I have the following code:
styles.scss
...
#keyframes fadeOut {
0% { width: 85%; height: 85vh; }
100% { width: 0%; height: 0%; }
}
#keyframes fadeIn {
0% { width: 0vh; height: 0vh; }
100% { width: 85%; height: 85vh; }
}
...
div.notifications-popup {
animation: fadeIn 0.15s forwards !important;
animation-delay: 0.15s;
}
...
In my NotificationComponent I have the following above all:
notification.component.ts
...
#Component({ ... })
export class NotificationComponent {
...
public close(): void {
this.fadeOutOnClose(); // Theoretically this should animate the closure of the dialog??????
this.matDialogRef.close(this.data.overlay);
}
public fadeOutOnClose(): void {
const view = document.getElementsByClassName('notifications-popup');
for (let i = 0; i < view.length; i++) {
this.renderer.setStyle(view[i], 'animation', 'fadeOut 1s forwards !important');
this.renderer.setStyle(view[i], 'animation-delay', '1s');
}
}
...
}
...
Does anyone have any ideas about how to animate the closure of a MatDialog?
Unfortunately, it's not an easy task. That's why I chose this library for my projects:
https://www.npmjs.com/package/ng-dialog-animation

Lit-element not applying classes static get styles

I am making a simple component to test newest Lit-element a checkbox.
Upon testing static get styles only the first element I style is shown, I have seen in the documentation what I am trying should be correct, may I have some help?.
this is my component:
import {LitElement, html, css} from 'lit-element';
class CheckboxMJ extends LitElement {
static get properties(){
return{
check:{type:Boolean},
name:{type:String},
}
}
static get styles() {
return css`
.checkWrapper{
font-family: Roboto;
background-color: red;
font-weight: 500;
font-size:14px;
color:#283D3B;
border:none;
outline:none;
height: 150px;
width: 300px;
border-radius: 3px;
overflow:hidden;
padding:3px;
}
input[checkbox i]{
background-color:red;
}
`;
}
constructor(){
super();
this.check=false;
this.name="";
}
render() {
return html`
<div class="checkWrapper">
<input class="checkbox-mj" type="checkbox" name="${this.name}" value="${this.check}"> ${this.name}
</div>
`
}
}
customElements.define('checkbox-mj', CheckboxMJ);
I have been encountering this issue several times with other components, kept changing order, and names of classes until it worked but I feel so lost about how this should be done right, please somebody enlighten me on how to use this feature correctly.
You have to keep in mind that checkboxes are very difficult to stylize. Many properties simply have no effect on this input. On the other hand you have to use a standard css selector to stylize the checkbox input[type="checkbox"].
If you want the check property to be reflected in your checkbox you must do it this way:
?checked="${this.check}"
Look at this guides for more information https://lit-element.polymer-project.org/guide/templates (Bind properties to templated elements).
import {
LitElement,
html,
css
} from 'lit-element';
class CheckboxMJ extends LitElement {
static get properties() {
return {
check: {
type: Boolean
},
name: {
type: String
},
}
}
static get styles() {
return css `
.checkWrapper{
font-family: Roboto;
background-color: red;
font-weight: 500;
font-size:14px;
color:#283D3B;
border:none;
outline:none;
height: 150px;
width: 300px;
border-radius: 3px;
overflow:hidden;
padding:3px;
}
input[type="checkbox"]{
margin:1rem
}
`;
}
constructor() {
super();
this.check = true;
this.name = "Check";
}
render() {
return html `
<div class="checkWrapper">
<input class="checkbox-mj" type="checkbox" name="${this.name}" ?checked="${this.check}"> ${this.name}
</div>
`
}
}
customElements.define('checkbox-mj', CheckboxMJ);

Align text to center inside Snackbar (Angular Material)

Hey how can I align text inside SnackBar to be center?
this is my code and it doesn't work:
import { Injectable } from '#angular/core';
import { MatSnackBar, MatSnackBarConfig } from '#angular/material';
#Injectable({
providedIn: 'root'
})
export class MaterialService {
constructor(public snackBar: MatSnackBar) { }
openSnackBar(message:string){
let config = new MatSnackBarConfig();
config.panelClass = 'text-align:center';
this.snackBar.open(message);
}
}
thanks you :)
Simply add this in your style.css (or any global css, in my case I put it in my app.component.scss)
margin:auto; will center the span tag inside the snackBar
text-align:center; will center the text inside the span
simple-snack-bar span {
margin:auto;
text-align: center;
}
Settings like this will apply to all your SnackBars.
For angular 7 w/material, I use this in global style.css:
.mat-simple-snackbar span {
margin: auto;
text-align: center;
}
The panelClass property of MatSnackBarConfig accepts a CSS class which you can define in your main app's styles.css:
openSnackBar(message: string) {
let config = new MatSnackBarConfig();
config.panelClass = 'center-snackbar';
this.snackBar.open(message);
}
Just make sure you use the !important selector as well!
.center-snackbar {
text-align: center !important;
}
For on demand centred text.
SASS:
snack-bar-container.text-center {
span {
margin-left: auto;
margin-right: auto;
text-align: center;
}
}
Then you add "text-center" to your panelClass
let config = new MatSnackBarConfig();
config.panelClass = "text-center";
this.snackBar.open(message);
That way you can have standard appearance if the Snackbar comes with an action.
Try this
import { Injectable } from '#angular/core';
import { MatSnackBar, MatSnackBarConfig } from '#angular/material';
#Injectable({
providedIn: 'root'
})
export class MaterialService {
horizontalPosition: MatSnackBarHorizontalPosition = 'center';
verticalPosition: MatSnackBarVerticalPosition = 'top';
constructor(public snackBar: MatSnackBar) { }
openSnackBar(message:string){
let config = new MatSnackBarConfig();
config.verticalPosition = this.verticalPosition;
config.horizontalPosition = this.horizontalPosition;
this.snackBar.open(message);
}
Ref:https://material.angular.io/components/snack-bar/api
Example:https://stackblitz.com/edit/angular-snackbar
Although this question is quite old, I thought posting my solution might be helpful to someone out there.
After lots of research and some trial and error, the below code is all I needed to get my snackbar working with centered text. (hint: I'm using the most stable Angular version as at today).
// extract from my-notification-service.ts file
// Note that I created the above service file, imported "MatSnackBar"
// & "MatSnackBarConfig" from #angular/material/snack-bar,
// and added a property of type "MatSnackBar" into the constructor.
// After that, I created the below object and function.
// The function will be called by any submit button in the project.
mySnackBarConfig: MatSnackBarConfig = {
duration: 3000,
horizontalPosition: 'center',
verticalPosition: 'bottom'
}
displayMessage(msg: string) {
this.mySnackBarConfig['panelClass'] = ['notification','success'];
this.snackBar.open(msg, '', this.mySnackBarConfig);
}
The following code was added to the global styles.css file
// extract from styles.css (global)
snack-bar-container.success {
background-color: rgb(31, 121, 39);
color: rgb(255, 255, 255);
}
snack-bar-container.notification simple-snack-bar {
font-size: 18px !important;
}
// this part is all I did to center the text.
// Take note of the css declaration, not just the style inside.
simple-snack-bar > span {
margin: 0 auto;
text-align:center !important;
}

Reactjs and SCSS - how to write height: selfheight x 2

I want to double the height of the div every time it is clicked.
I am thinking to apply a additional CSS class to a div when ever I click a button. The CSS concept will be like:
#divToBeDoubled {
height: 100px;
&.doubleHeight{
height: selfHeight*2
}
}
How can I achieve this by using Reactjs and SCSS?
I think if you want to change a css value with the component state, you need to move the property you want to change in you component or use JSS...
to move the property in the render, you can do this :
class MyComponent extends React.Component{
state = {
divHeight : 100
}
doubleSize = ()=>{
this.setState({ divHeight : this.state.divHeight * 2 })
}
render() {
const style = {
height: this.state.divHeight
};
return (
<div style={style} onClick={this.doubleSize}>Content</div>
);
}
}
If using sass. You can use this, and toggle class in JSX onclick event.
$height: 100px;
.normal {
height: $height;
}
.double {
height: $height * 2;
}

Resources