Angular add style tag into innerHTML - javascript

I create an Angular project and I wanted to insert style CSS into the html, but I don't want the inserted CSS replace other style that have the same tag or class name.
const testStyle = '<style>
body {color: red}
table {width : 200px}
h1{font-size:12px}
.another-same-class-name{color: blue;font-size: 13px}
</style>'
Above is my sample style that I want to insert into my component template
My Component
#Component({
selector : 'app-my-component',
templateUrl: './my-template.component.html',
styleUrls: ['./my-style.component.scss'],
})
export class MyComponent{
myStyle:string
...
ngOnInit(){
const testStyle = '<style>
body {color: red}
table {width : 200px}
h1{font-size:12px}
.another-same-class-name{color: blue;font-size: 13px}
</style>'
this.myStyle = testStyle
}
updateCss(newCss){
this.myStyle = `<style>${newCss}</style>`
}
}
<div #styleWillGoHere [innerHtml]="myStyle"></div>
Edit: I have update my question, to make it more clear :)
I appreciate any kind of solution.

You need to use DomSanitizer of #angular/platform-browser to sanitize the HTML. Take a look of the docs: https://angular.io/api/platform-browser/DomSanitizer.
In your particular case, you need to use bypassSecurityTrustHtml() method. Also, for apply styles only to one component, add an id to your target component and use it in your styles. (You can use class if that component will appear more than once in your web).
EXAMPLE:
import { Component } from '#angular/core';
import { DomSanitizer, SafeHtml } from '#angular/platform-browser';
#Component({
selector: 'my-app',
template: `
<div id="myId">
<div [innerHtml]="myStyle"></div>
<h1>Hello</h1>
</div>
`
})
export class AppComponent {
myStyle: SafeHtml;
constructor(private _sanitizer: DomSanitizer) { }
ngOnInit() {
this.myStyle =
this._sanitizer.bypassSecurityTrustHtml(`<style>#myId h1{color: red}</style>`);
}
}
DEMO: https://stackblitz.com/edit/angular-3kza7c?file=src%2Fapp%2Fapp.component.ts

Related

Get HTML content with styles in Angular

I have an application created using Angular. I need to get html of template of some big component but with styles that used there for classes. How can I do that in angular? Currently I'm trying to achieve this with getting innerHTML:
const myTemplate = document.getElementById("someWrapperId");
const content = myContent.innerHTML;
It doesn't return styled html.
I also tried with setting encapsulation: ViewEncapsulation.None - it also doesn't help in my case.
Styles are set in component.css file and not inline.
Hi I think you can use #ViewChild and ElementRef to get the HTML content style. I have a sample code below =>
HTML:
<div #infoDiv class='col-md-2' style='color: blue;width:152px'>INFO DIV</div>
<br>
Your Color:: {{styleColor}}
<br>
Your Width:: {{styleWidth}}
TS:
import { Component, ElementRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
styleColor:any='';
styleWidth:any='';
#ViewChild('infoDiv') infoDivRef: ElementRef;
ngAfterViewInit(): void {
if (this.infoDivRef.nativeElement) {
console.log(this.infoDivRef.nativeElement.style.color);
this.styleColor=this.infoDivRef.nativeElement.style.color;
this.styleWidth=this.infoDivRef.nativeElement.style.width;
}
}
}
NOTE: Code is also available in stackblitz. Please check the LINK DEMO link.

How does Angular Component CSS encapsulation work?

I want to understand that if I create two style sheets
Style 1
.heading {
color: green;
}
Style 2
.heading {
color: blue;
}
Now if these two styles are written in two different views, when rendering them
on a layout as a Partial View, then in this case a conflict could occur
and one could override the style of the other.
BUT
Using angular(see page 16), how come these two styles in different components render on the same page with encapsulation? How come the CSS is not overriden?
For example
import { Component } from '#angular/core';
#Component({
selector: 'app-user-item',
template: '<p class="heading">abc</p>',
styleUrls: ['./user-item.css']
})
export class UserItemComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
user-item.css
.heading{ color :green}
app-user.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-user',
template: '<p class="heading">abc</p>',
styleUrls: ['./user.css']
})
export class UserItemComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
user.css
.heading{ color :blue}
When rendering this on a page:
<app-user></app-user>
<app-user-item></app-user-item>
This is the result:
Angular (by default) emulates a shadow DOM.
It dynamically creates some HTML attributes that are only applicable to elements in that component.
For example:
<app-user></app-user>
<app-user-item></app-user-item>
will be transformed to
<app-user _ngcontent-1></app-user>
<app-user-item _ngcontent-2></app-user-item>
And your css will be transformed to:
.heading[_ngcontent-1] { color: blue }
.heading[_ngcontent-2] { color: green }
You can find a more complete explanation here and the documentation here
Angular comes with CSS encapsulation out of the box. When generating a new project, the default is for the styles.css file at the root of the project to apply globally to the application, and for component styles, such as the styles found in foo.component.css,to only apply to the foo component and nowhere else. But that is not the only way styles can be encapsulated in Angular, let us take a closer look.#Component({
selector: 'app-foo',
templateUrl: './foo.component.html',
styleUrls: ['./foo.component.css']
})

How to access css classes in typescript file?

Here I want to add CSS classes dynamically to the element using ngClass directive in angular.js.
<p [ngClass]="addClasses()">testing content</p>
and below is my ts code:
isbold: boolean = false;
isItalic: boolean = true;
addClasses() {
let classes = {
boldClass: this.isbold,
italicsClass: this.isItalic
};
return classes;
}
boldClass and italicsClass are two classes in my css file, these classes should apply depending on the value in the corresponding boolean variables.
But I'm getting the error as Can not find name for both boldClass and italicsClass. Any help appreciated.
The issue is with your JSON, when you declare a JSON, the properties of it shouldn't be with the "=", try to use something like:
addClasses(){
let classes={
boldClass: this.isbold,
italicsClass: this.isItalic
};
return classes;
}
There was a pending "," after this.isbold, and also, you had this.Italic, and it should be this.isItalic.
This is one way you can add dynamic classes
<p [class.boldClass]="isbold"
[class.italicsClass]="isItalic">testing content </p>
Try using Angular's Renderer2
#ViewChild('el') element: ElementRef
constructor(private renderer: Renderer2) {
}
addClasses(classes: Array<string>){
classes.forEach(class => this.renderer.addClass(this.element.nativeElement, 'someClass'))
}
<p #el>testing content </p>
ts:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
isbold: boolean = false;
isItalic: boolean = true;
addClasses() {
let classes = {
boldClass: this.isbold,
italicsClass: this.isItalic
};
return classes;
}
}
template:
<p [ngClass]="addClasses()">testing content </p>
css:
.boldClass {
font-weight: bold;
}
.italicsClass {
font-style: italic;
}
Demo
[ngClass]="{'italicsClass':isItalic,'boldClass':isbold}"

Nest two dynamically created components in Angular [duplicate]

I would like to set the body of <ng-content> while instantiating a component dynamically using ComponentFactoryResolver.
I see that I can get access to input & output using ComponentRef, but not a way to set <ng-content>.
Please note <ng-content> I'm planning on setting can contain simple text/can span dynamically created components
#Component({
selector: 'app-component-to-project',
template: `<ng-content></ng-content>`
})
export class ComponentToProject implements AfterContentInit {
ngAfterContentInit() {
// We will do something important with content here
}
}
#Directive({
selector: 'appProjectionMarker'
})
export class ProjectionMarkerDirective implements OnInit {
constructor(private viewContainerRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
const componentFactory: ComponentFactory<ComponentToProject> = this.componentFactoryResolver.resolveComponentFactory(ComponentToProject);
const componentRef: ComponentRef<ComponentToProject> = this.viewContainerRef.createComponent(componentFactory);
// Question: How to set content before the child's afterContentInit is invoked
}
}
#Component({
selector: 'appTestComponent',
template: `<div appProjectionMarker></div>`
})
export class TestComponent {}
There is the projectableNodes parameter for the vcRef.createComponent method
createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
You can use it to dynamically inject one component into another.
Let's say we have the following component
#Component({
selector: 'card',
template: `
<div class="card__top">
<h2>Creating a angular2 component with ng-content dynamically</h2>
</div>
<div class="card__body">
<ng-content></ng-content>
</div>
<div class="card__bottom">
<ng-content></ng-content>
</div>
`
})
export class CardComponent {}
We want to create it dynamically and insert some controls to its ng-content locations. It could be done like follows:
const bodyFactory = this.cfr.resolveComponentFactory(CardBodyComponent);
const footerFactory = this.cfr.resolveComponentFactory(CardFooterComponent);
let bodyRef = this.vcRef.createComponent(bodyFactory);
let footerRef = this.vcRef.createComponent(footerFactory);
const cardFactory = this.cfr.resolveComponentFactory(CardComponent);
const cardRef = this.vcRef.createComponent(
cardFactory,
0,
undefined,
[
[bodyRef.location.nativeElement],
[footerRef.location.nativeElement]
]
);
Plunker Example
See also
Why is projectableNodes an any[][]?
Pawel Kozlowski - Reactive parenting with Angular 2 - NG-BE 2016

Is it possible to style the same component different in Angular 2?

I have a generic component I want to re-use throughout my app. The problem is that I want to style it differently for various parts of the site. Is this possible?
I'm guessing there's a way to pass in a path for the styleUrl, but that seems really messy and i'm hoping there's a better alternative.
I also tried this but it didn't work: When specifying the component, add in the class, something like this
<generic-component class="customStyle1"></generic-component>
and then added styling based on customStyle1 into generic-component's stylesheet, but it didn't seem to pick up on the style.
You may use :host-context in the style to theme your component based upon some class applied where it is being used.
Read more about it here!!
test.css
:host-context(.theme-green) h3 {
background-color: green;
}
:host-context(.theme-red) h3 {
background-color: red;
}
app.component
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h3 class="title">Basic Angular 2</h3>
<my-test class="theme-green" ></my-test>
<my-test class='theme-red' ></my-test>
`
})
export class AppComponent {
constructor(){}
}
test.component
#Component({
selector: 'my-test',
template: `<h3>Test Component</h3>
`,
styleUrls : ['./app/test.css']
})
export class TestComponent {
constructor(){}
}
Here is the Plunker!!
Hope this helps!!
You can use the :host(...) selector combined with #HostBinding() like:
#Component({
selector: 'my-comp',
styles: `
:host([type-default]) {
background-color: red;
}
:host([type-header]) {
background-color: blue;
}
:host([type-main]) {
background-color: green;
}
`
})
export class MyComponent {
#Input()
#HostBinding('component-type')
componentType:String="type-default"
}
and then switch style like
<header>
<my-comp componentType="type-header"></my-comp>
</header>
<main>
<my-comp componentType="type-main"></my-comp>
</main>
<my-comp></my-comp>
You can also apply a class from the outside like in your question and then use the :host(...) selector like
:host(.customStyle1) {
Then you don't need this part
#Input()
#HostBinding('component-type')
componentType:String="type-default"
but this way might be beneficial if you want to combine styling with other configuration settings for the component.

Categories