How does Angular Component CSS encapsulation work? - javascript

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']
})

Related

medium-zoom implementation is not working in Angular 13

I am trying to implement medium-zoom from https://www.npmjs.com/package/medium-zoom
These are the steps I followed
ng new medium_zoom_test (Angular 13) with routing & css
npm install medium-zoom
image is kept in assets
app.component.html
<h1>Zoom test</h1>
<img class="zoomy" width="50%" src="assets/image.svg">
app.component.ts
import { Component } from '#angular/core';
import mediumZoom from 'medium-zoom';
mediumZoom('.zoomy', {
margin: 40,
background: '#ffffff',
scrollOffset: 40
})
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'medium_zoom_test';
}
On serving the application the webpage with image is visible. However, there's no zoom icon on hover and the image won't zoom on click. It's just a normal webpage with no change.
Any alternatives to implement the zooming of images are welcome too.
I don't think mediumZoom will work when the passed selector has no corresponding element in the DOM. What I mean is where you call mediumZoom function the component is not attached to the DOM yet. If you want to guarantee that you need to call it on ngOnInit lifecycle hook. Or you can do better which is to define a directive that applies the zoom affect like this :
import mediumZoom from 'medium-zoom';
#Directive({
selector: '[appZoomie]'
})
export class ZoomieDirective {
constructor(private el: ElementRef) {
mediumZoom(el.nativeElement, {
margin: 40,
background: '#ffffff',
scrollOffset: 40
})
}
}
And use it like this :
<img appZoomie src=".."/>
Stackblitz

Integrate xterm.js to Angular

I'm new to Angular.
I'm trying to use xterm.js (https://xtermjs.org/) but it display badly.
Here is the render :
Render
I created a xterm component. The xterm.component.ts file code is :
import { Component, OnInit } from '#angular/core';
import { Terminal } from "xterm";
#Component({
selector: 'app-xterm',
templateUrl: './xterm.component.html',
styleUrls: ['./xterm.component.css'],
})
export class XtermComponent implements OnInit {
public term: Terminal;
container: HTMLElement;
constructor() { }
ngOnInit() {
this.term = new Terminal();
this.container = document.getElementById('terminal');
this.term.open(this.container);
this.term.writeln('Welcome to xterm.js');
}
}
My xterm.component.html only contains this :
<div id="terminal"></div>
I don't really know what to do more ...
Thanks in advance guys
You must set the component encapsulation
#Component({
encapsulation: ViewEncapsulation.None,
...
})
Encountered the same problem and found this page.
Maybe this is too late for the OP, but could be useful for others.
The styles are wrong because 1) the xterm.css is not loaded, and 2) the encapsulation.
My solution to 1) was to add #import 'xterm/dist/xterm.css'; in the scss file for this component.
And 2) can be solved by setting encapsulation: ViewEncapsulation.None as Victor96's answer, or better setting encapsulation: ViewEncapsulation.ShadowDom.
Hope this helps.
I know this is old, but I had to put terminal initialation in ngAfterViewInit. Otherwise the DOM elements are undefined.
Try to use in template reference variable by using the hash symbol
<div #myTerminal></div>
and in component
#ViewChild('myTerminal') terminalDiv: ElementRef;
In ngOnInit
ngOnInit() {
this.term = new Terminal();
this.term.open(this.terminalDiv.nativeElement);
this.term.writeln('Welcome to xterm.js');
}

Angular add style tag into innerHTML

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

Javascript Angular 4 using eventEmitter though several layers of components

I am having a bit of a problem with getting the following situation done in Angular.
I am using Angular 4 and this is the situation.
app.component.html contains a wrapper div which I would like to be able to change it's color by adding a class to it.
My problem is that I have different layers of components.
For example, if I wanted to change the class in app.component.html it would have this:
app.component - root
button-wrapper.component - holds the button
button.component - message comes from there.
Normally I could do this:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'app';
myClass = '';
handleEvent(value) {
console.log(value);
myClass = value;
}
}
and in app.component.html have this:
<div [ngClass]="myClass">
<app-button (outputEvent)="handleEvent($event)"></app-button>
</div>
BUT, my problem is that app-button component is inside button-wrapper component so it looks like this:
<div [ngClass]="myClass">
<button-wrapper></div>
</div>
So where would I put this:
(outputEvent)="handleEvent($event)"
How can I go round this issue?
You can chain events as long as their direct children:
button.component.ts (selector: app-button)
startChainEvent() {
this.outputEvent.emit('className');
}
button-wrapper.component.html
<app-button (outputEvent)="handleEvent($event)"></app-button>
button-wrapper.component.ts (selector: app-button-wrapper)
handleEvent(e) {
this.outputEvent.emit(e);
}
app.component.html
<app-button-wrapper (outputEvent)="handleEvent($event)"></app-button-wrapper>
app.component.ts
handleEvent(e) {
myClass = e;
}

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