Angular 2 Dart: How to add body class from inside component? - css

My Angular 2 Dart application has many nested components. If a certain property of one of my components is set to true, a popup is shown.
If this popup is shown I want to add a class to the document body.
Pseudo code example:
<html>
<head>
</head>
<body class="">
<app-component>
<home-component> <!-- with routers -->
<inner-component>
<popup-component>
// if I am active I want to add a body class
</popup-component>
</inner-component>
</home-component>
</app-component>
</body>
</html>
Simple reason: If the popup component is displayed I want to disable body scrolling (overflow-x:hidden;). The popup component is shown if the property bool show_popup within popup_component.dart is set to true.
Unfortunatly in CSS - as far as i know - there is no selector to check this (Is there a CSS parent selector?) - otherwise I would say something like
body:has(.my_popup)
in the main.css file or something similar.
How can I achieve the desired result?

There are two way.
You can use
#HostBinding('class.someclass') bool isSomeClass = true;
in the root component if it has
selector: 'body'
or
document.querySelector('body').classes.add('someClass');
You can use :host-context(...) to style a component depending on a selector matching a parent
:host-context(body.someClass) {
background-color: red;
}
will make the background color red when the body element has class="someClass" set.

Related

how to change style prev-icon & next-icon props in vuetify <v-slide-group>?

i am trying add background color and change the icon color on prev icon and next icon on vuetify slide group prop. if i target the class which i got from console it's not working. but if i remove scoped from my style tag or try to change the color on console style it's working.
.v-slide-group__next.theme--light.v-icon
{
color: rgb(234, 10, 10)!important;
}
I have tried this way but it's not working.how can i style those props icon? thanks in advance.
In order to target the elements with class it's necessary to use <style> without 'scopped', because 'scopped' automatically adds unique hashes in the class selector on each app build. And this prevents targeting Vuetify's elements using this way. I would suggest you to add some class on your wrapper container, let's say class="my-slider" and to target it like this:
<template>
<div>
<v-slide-group class="my-slider">
</div>
</template>
<style>
.my-slider > .v-slide-group__next.theme--light.v-icon
{
color: rgb(234, 10, 10)!important;
}
</style>

I want to apply a background image to the body of only one component

I am very new to React, so apologies for the mistakes in advance.
In my React app, say I have 2 components and as the CSS styles are global, it picks up CSS styles from all the files.
However, I wish to add a full background image to one of the components which I was able to achieve by using this code in my CSS file:
body {
background-image: url("../image.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
The problem is that the same image is also being applied to another component. I read a few answers and found that I can use ComponentDidMount hook and add the image to the body tag there. I tried that, but it doesn't show anything.
componentDidMount() {
document.body.style.backgroundImage = "url('../image.jpg')";
document.body.style.backgroundPosition = "center";
document.body.style.backgroundRepeat = "no-repeat";
document.body.style.backgroundSize = "cover";
}
EDIT
I realized I had the wrong wording for the question. What I mean to say is that I have two pages in React. For one of the pages, I want a full background image. However, because CSS styles are global, the background image is getting applied to all the pages.
You can use inline styling or specific styling by assigning a specific class or ID to the top element of one component.
INLINE STYLING Example:
// If Background variable has url to the background image.
const style = {
backgroundImage: `url(${Background})`
}
// in component use that inline style
return (
<div style={style}></div>
);
IF YOU WANT TO WORK with body only...
then add a class to body on component A mount and remove the class on component B mount. And attach the background property to the class.
A component usually return some jsx and in most cases a div. In other to apply a css to a single component I mean the jsx the component is rendering. you should define a css class, that apply a background image to the div the component is rendering and make the height of the div the window height. you can do this via inline css all
const MainDiv =()=>(
<div classname="testClass">
This will show background image in the covering the entire body
//Other content of your page can be added here like the rest of your page contents
<header>
This is my blog post
</header>
<nav>
this is my navbar
</nav>
</div>
);
ReactDOM.render(<MainDiv />, document.getElementById("root"));
.testClass{
backgroundImage :"url('../image.jpg')";
backgroundPosition :"center";
backgroundRepeat : "no-repeat";
background-size : "cover";
width: 100%;
height: 100vh
}

Applying dynamic styling to injected HTML in Angular 2

For an Angular project I'm working on, I'm injecting HTML into a <div> like so:
<div class="myClass" [innerHTML]="htmlToInsert"></div>
The htmlToInsert contains a variety of things, notably <a> tags. Previously we were styling all these tags like so:
.myClass ::ng-deep a {
color: #f00;
text-decoration: none;
}
And this worked fine. But now I need the color of these links to be dynamically generated during component initialization, based on data coming in from elsewhere. All of the dynamic styling I've seen in Angular requires you to apply things directly to the HTML tag, but we don't have them here to work with.
How can I apply dynamic styling to HTML that is also dynamically generated? Can I directly change the CSS class somehow? Would using a pipe be the correct approach here? Is there another method I don't know about? I could maybe refactor code if there is absolutely no other way of doing this.
So if you can't modify the innerHTML you are passing in, you can achieve this functionality with a custom directive. Essentially you would tag your div that contains your innerHTML with a custom directive. That directive then looks for any anchor tags in it and changes the color based on an input.
// component.html
<div anchorColor [color]="dynamicColor" [innerHTML]="htmlToInsert"></div>
// directive.ts
#Directive({selector: '[anchorColor]'})
export class AnchorColorDirective implements OnAfterViewInit {
#Input() color: string;
constructor(private el: ElementRef){
}
// afterViewInit lifecycle hook runs after DOM is rendered
ngAfterViewInit(){
// get anchor element
let anchorEl = this.el.nativeElement.querySelector('a');
// assign color
if(anchorEl){
anchorEl.style.color = this.color;
}
}
}
Here is a working plunkr https://plnkr.co/edit/QSYWSeJaoUflP94Cy4Hm?p=preview

React Routes - different styling on body css tag

I have two routes on my React app: /a and /b.
For /a, I want the body css tag to have a background-color: red;.
For /b, I want the body css tag to have a background-color: blue;.
Both components a and b live in different .JSX files, and both import their own main.scss file which defines their own respective body background-color.
However, since the entire app is compiled into the body tag, there seems to be a conflict, and only one of the body tags is respected for both routes.
<body>
<script src="bundle.js" type="text/javascript"></script>
</body>
The reason I want it on the body tag and not just a container div is that I want the background-color to be visible when I scroll outside the bounds of the page (the bounce effect on Mac and iOS).
What's the proper way to do this?
That's happening because when you import your styles in your component without CSS Modules, the styles are global so your body style is defined two times (you can see all the styles in the <head> tag).
You can fix that by setting the background color in your component componentDidMount() method.
Example
componentDidMount(){
document.body.style.backgroundColor = "red"// Set the style
document.body.className="body-component-a" // Or set the class
}
or, if youre using functional components you can do the same with useEffect...
useEffect(() => {
document.body.className = 'class-name';
}, []);
I agree with what QoP said but, as an add on to that, you should also make sure to use componentWillUnmount to set it back to whatever it normally is outside that component.
for example:
if normally for the whole application text-align is left but for one component you want it to be center, but after the component it needs to return to being left, you will do the following:
componentDidMount() {
document.body.style.textAlign = "center"
}
componentWillUnmount(){
document.body.style.textAlign = "left"
}
Add this code
componentDidMount(){
document.body.style.backgroundColor = "white"
}
Hope to help.

Dynamically change element styles via custom properties?

For example, you can change the ink colour in paper-tabs by changing --paper-tab-ink: var(--accent-color);. Is it possible to change the value of the CSS custom properties dynamically similar to how you can toggle a class or change the style in JS?
There are different ways to do this, but a simple answer is to use the Polymer.updateStyles() method after making your class changes.
For example, let's say your styles are:
<style>
.yellow x-example {
--light-primary-color: #fdd85f;
}
.red x-example {
--light-primary-color: red;
}
</style>
and you want to make the component use the styles in the .red class. You simply add it as you normally would in javascript, then be sure to also use this function to actually update it on the page.
<div class="yellow" onclick="this.className='red'; Polymer.updateStyles()">
<x-example></x-example>
</div>
Yes, first get the object of your custom element. Then get the customStyle object. Add a style to that object. And then run element.updateStyles();
t.clickListener= function(e) {
var t = Polymer.dom(e).localTarget; //retarget if needed
t.customStyle['--the-color-etc'] = 'pink';
t.updateStyles(); // mandatory for the CSS variables shim
};
See the docs

Resources