Create component with dynamic styleUrls in angular 9 - javascript

I want to make one component and use it several times in another component,Since the templates and logic of this component are always the same and the style is different, I decided to create a single component instead of creating multiple components and just dynamically define the style file.
There is a common method called Lazy Load CSS at runtime which I will include a link to but the problem is this method that the css file is added globally and since all css files have classes of the same name the last file in the DOM Added effects all components (that is, capsulation is not used in this method), so this method is ineffective.
https://egghead.io/lessons/angular-lazy-load-css-at-runtime-with-the-angular-cli
Finally I put a picture below that clearly shows what I want to do exactly.
player.component.ts:
#Component({
selector: 'app-player',
templateUrl: './player.component.html',
styleUrls: ['./player-' + number + '.css']
})
export class PlayerComponent implements OnInit {
#Input() number: number;
constructor() {}
ngOnInit(): void {}
}
player.component.html:
<p class="title">player works!</p>
player-1.css:
.title {
color: red;
}
player-2.css:
.title {
color: orange;
}
game.component.html:
<div>
<app-player [number]="1"></app-player>
<app-player [number]="2"></app-player>
<app-player [number]="3"></app-player>
</div>
How can this be done? Any solution is appreciated.
Thanks.

If you are solely looking to dynamically change colors, font sizes etc.. you should reconsider making use of global theming.
Whereas if there are major layout differences you have several options:
Create a base component class
contains all the logic
Derive your other components from this component with different
styling files.
Benifit of the solution above is that you can also use appropriate naming for the
child components which would make the code/directive more readable.
Instead of using numbers 1,2,3 you would have darkListComponent, lightListComponent etc..
Make use of ngClass:
<div [ngClass]="'my-component-style-' + number"></div>
You can still seperate your styling sheets by passing them to your styleUrls in your
component.ts file. (styleUrls: ['theme1.scss','theme2.scss'])
Or you can declare all classes in one file for max styling reusability.
my-component-style-1,my-component-style-2 {
...same styling
},
my-component-style-2 {
color: orange;
}
Option 2 is closer to yours and you'd only have to update your template and styling sheet
for it to work.

Related

How to prevent style tags of unused React components

I think this question may expand beyond React, but I'm still not sure if React itself is responsible for the problem.
The environment is React with TypeScript. I use CSS imports in the component files, so that each component has its specific stylesheet and I presume that those styles will not be added to the <head> element until the respective component is instantiated. But it turns out that if I import a component from a file, which just reexports all of them, the styles of all the other components, which I do not use, are still added in the DOM.
Here is a simple example, let's say I have two simple components in the lib folder - Avatar and Button. They look like this (the Button is similar):
import React from 'react';
import './avatar.css';
const Avatar: React.FC = (props: any) => {
return (
<div className="avatar">
{props.children}
</div>
);
}
export { Avatar };
Then I add index.ts to reexport the components, in order to have simple import path:
import { Avatar } from './Avatar';
import { Button } from './Button';
export { Avatar, Button };
And finally, in my AppComponent I want to use only the Button component:
import React from 'react';
import { Button } from './lib';
const App: React.FC = () => {
return (
<div className="App">
<Button>example</Button>
</div >
);
}
export default App;
To my surprise, in the <head> element there are <style> tags not only for the Button, but also for the Avatar. Why is this happening? Is my reexport configuration wrong?
Notice that if I import the component directly from its file - import { Button } from './lib/Button' I do not get the Avatar styles.
The example is really simple, but the real scenario is related to a React component library, which contains a lot of components with a lot of stylesheets. I want to avoid inserting so many <style> tags in the DOM, unless they are really needed.
Thank you for spending time on this!
so that each component has its specific stylesheet and I presume that those styles will not be added to the element until the respective component is instantiated
This presumption is wrong. React uses webpack to bundle its files and the way webpack works for CSS imports is that it loads all the CSS files that your project depends on and put them in the <head> element right at the beginning.
You might ask: Then how do I keep my styles separated and don't get them mixed.
There are three solutions to this
A good way is to Add a CSS Modules Stylesheet
Another suggestion is to make the <div> that wraps your component have a className that is the same name as the component so your component will look like this
export default class ComponentOne extends Component {
...
render() {
return(
<div className="ComponentOne">
...
</div
)
}
}
And your component CSS file will look like:
.ComponentOne div img {
...
}
.ComponentOne .class-one {
...
}
With this way, using CSS preprocessor like SASS will come in handy, so your .scss file will simply begin with:
.ComponentOne {
...
}
Another solution is to have the styles as an object inside your component. This way the style will only be scoped to your component and will be removed when the component unmounts, but then you will lose the ability to easily create #media queries andother special effects like:hover` plus this approach is not recommended for small components that get mounted and unmounted too often because this creates a performance issue once the application gets larger
You also might ask: since all the style sheets get imported at the begging, then why don't I put all my styles in one big style sheet and not splitting them up.
Other than the fact that splitting your styles will make them easy to handle so that each component will have its separate CSS file and webpack will handle importing them, There is one other benefit:
Say you have a feature1 component which also has a feature1.css file. In the beginning, when you have feature1 imported in your main app, webpack will also import its style sheet and put it in the <head> element.
But say in the future you decided you don't want to use feature1 component anymore and you are using another feature2 component now which has its own feature2.css file. Now since no other component is importing feature1 component, webpack will also ignore importing feature1.css into the <head> element.

How can i modify downloaded html in an ionic app?

I'm new to ionic, we're trying to build a reader app that downloads documents in html from a service and then displays them. I know how to modify html that is part of the ionic application itself, but the documents we download are displayed inside the ionic app. We want to add a search function that finds and highlights all occurrences of the entered words. We find them and highlight them by wrapping them in a span that has a css class that sets a yellow background. But it doesn't reflect the changes in the app.
The document is downloaded from the service and then wrapped in a div, here's what we have do far, this is a snippet from the document.html for the document page in the app and is where the downloaded content lives:
<ion-content id="content">
<div [ngClass]="isNight ? 'night' : 'day'">
<div [ngClass]="isSingle ? 'single' : 'double'">
<div id="inputText" class="document" [innerHtml]="document | keepHtml" [ngStyle]="{'font-size': fontSize+'em' }"></div>
</div>
</div>
</ioncontent>
The javascript that highlights the hits is, I've left out the search box stuff since it's really just boilerplate, the highlight method is where the problem lies:
highlight(keyword) {
var inputText = document.getElementById("inputText");
var innerHTML = inputText.innerHTML;
inputText.innerHTML = innerHTML.replace(new RegExp(keyword, 'g'), "<span class=\"keyword\">" + keyword + "</span>");
}
If the user searched for "the", for example, after the highlight() method runs we should see every "the" in the document highlighted in yellow. But we don't. If we remove the "| keepHtml" from the div for the document, search works.
If we display the document html using an alert from the typescript method we see our changes, but if we run the javascript console in the browser and look at the html in the Dom of the browser, the changes we made are not there.
I know I'm missing something obvious or fundamental to ionic/angular but so far I can't see what it is. Maybe I'm so far off that nobody can help me but I thought I'd take a shot. Thanks for understanding.
Adding the keepHtml code:
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
/**
* Generated class for the KeepHtmlPipe pipe.
*
* See https://angular.io/api/core/Pipe for more info on Angular Pipes.
*/
#Pipe({ name: 'keepHtml', pure: false })
export class KeepHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {
}
transform(content) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
We discovered the problem; ionic/angular thought our html was unsafe. We started sanitizing it before we added it back in and it works.
We actually found two solutions, one was to run a sanitizer in the page class (excuse me if my angular-speak is not quite right, I've lived through so many "Waves of the Future" that at this point in my career they're all starting to run together) with bypassSecurityTrustHtml and the other, surprisingly was to add the modified HTML back into this.document instead of element.innerHTML.
The second solution seems like black magic, I'm not sure I understand why it works. I actually prefer the first solution.

React Styling with Create React App

I'm new to React.
Quotes from Create React App:
Generally, we recommend that you don’t reuse the same CSS classes across different components. For example, instead of using a .Button CSS class in AcceptButton and RejectButton components, we recommend creating a Button component with its own .Button styles, that both AcceptButton and RejectButton can render (but not inherit).
Following this rule often makes CSS preprocessors less useful, as features like mixins and nesting are replaced by component composition.
I don't think I understand it fully. Why sass nesting and mixing are less useful with composition? Any example?
Does that also mean I shouldn't have global styles, for example, for an input field? If all the input fields in my app look the same or similar, I should create a component for it, just for the styling purpose?
SASS nesting helps ensure your styles don't leak outside the parent class(es). With component composition, this is automatically enforced because you nest components within components.
Mixins are a way of reusing styles across selectors. With component composition, the reusing comes from composing in the JSX instead of CSS.
Old Way
CSS
.button {
color: #fff;
&.button-accept {
background-color: green;
}
&.button-reject {
background-color: red;
}
}
JSX
function AcceptButton() {
return <button className="button button-accept">Accept</button>;
}
function RejectButton() {
return <button className="button button-reject">Reject</button>;
}
React Way
const buttonStyles = { color: '#fff' };
function Button(props) {
return <button style={Object.assign({}, buttonStyles, props.style)}>
{props.children}
</button>;
}
const acceptStyles = { backgroundColor: 'green' };
function AcceptButton(props) {
return <Button style={acceptStyles}>Accept</Button>;
}
const rejectStyles = { backgroundColor: 'red' };
function RejectButton(props) {
return <Button style={rejectStyles}>Reject</Button>;
}
Note that this uses inline-styles, which may not be ideal in real-world situations where you repeatedly render the same element and the styles are present for each element in the DOM. To solve that, check out some of the CSS-in-JS solutions, such as JSS.
Does that also mean I shouldn't have global styles, for example, for an input field? If in my app all the input fields look the same or similar, I should create a component for it, just for the styling purpose?
That depends on whether you are using any UI framework. If you are rolling out your own from scratch, then it might be possible to do so. Otherwise, global styles are almost unavoidable.
Not that this is not a binary decision. Many of the existing CSS frameworks are not written just for React and will not play well with the CSS-in-JS approaches that React encourages.

Conditional stylesheet in .vue component

I'm working with vue component (cli .vue)
I need to have my stylesheet appear only if certain boolean is true/false.
Simplest explanation would be something like :
When myVar==false, component is not loading styles.
<style v-if="myVar" lang="scss"> #import 'mystyles.css' </style>
I know it is impossible in that way, but how I'm able to do 'similar' thing?
I need to load my styles in vue if user want to use default Styles, if not I need to prevent them from being loaded.
My component is used not once but many times in page, but that condition of using/not using default css need to be apply by all components as well, so no problem here.
Any ideas?
Thanks for help or any ideas in advance :)
Using SCSS, you can wrap that CSS in a class, something like this:
<style lang="scss">
.conditional-class {
#import 'stylesheet.scss';
}
</style>
And then use a Vue class binding for that class:
<div :class="{ conditional-class: true }">
...
</div>
This way the CSS won't apply unless the class is active on that element. If you want the styles to apply all over the app, then put that class on the app root element.

How can I embed angular directive style within the js code?

I have a project written in angular 1.5 Until I upgrade to angular 2, I would like to reach a state where I write something like
angular.module(..).directive('name', () => {
return {
restrict: 'A',
template: `
<div> ... some template... </div>
`,
style: `// this is what I am missing
div{
// some css
}
`,
controller: function($scope){ ... }
}
})
The only piece I am missing is the style part. How can I get that? Is it supported in angular 1.x? Is there a tool that can help me get this functionality?
To make it clear - I am not asking about scoped css.
I don't care that these rules will be global or not.
I just want to be able to write the css next to the template and the controller.
So if you know about a tool like babel for example that can extract the style part to a css/scss file, that would qualify.
It can even be a general solution that I can use for this scenario.
Taken from Reddit
To my knowledge, there is no way to do that "automatically". Personally when i create a component i just give a specific ID / class to the top element, and restrict the component's CSS to that element.
Example: my-component.html
<div class="my-component-wrapper">
....
</div>
my-component.scss
.my-component-wrapper {
// style that applies only to my component
}
A style property on an angular 1.5 component is not supported or it'd have been mentioned in the docs

Categories

Resources