Cannot Understand the Use of :host in components in Angular2
What i have understood of host is that if i have a child component
inside a parent component and we want to style a child component from
the parent component we can use :host . and :host-context for
vice-versa
No, this is not what it used for.
:host
selector comes from shadow DOM spec.
...This scoped subtree is called a shadow tree. The element it's
attached to is its shadow host.
In angular world, a component's template is a shadow tree. The component's element is a shadow host. So when you're defining styles for :host
selector, the styles are applied to the component's element.
:host
In your example, if you defined styles in my-app
component, the styles will be applied to <my-app>
DOM element. This particular configuration:
:host(.mine){
color:red;
}
Will be applied to the host element that has .mine
class:
<my-app class="active">
If you defined styles in app-ngrx
component, the styles will be applied to <app-ngrx>
DOM element, NOT <my-app>
. This particular configuration:
:host(.mine){
color:red;
}
Will be applied to the host element that has .mine
class:
<app-ngrx class="active">
:host-context
Now, :host-context
is also applied to the host element, but the function (parenthesis) takes a selector that is checked not against the host element itself, but against all ancestors up to document root. If such element is found, the styles are applied.
For example, this selector
:host(.mine){
color:red;
}
matches such structure:
<my-app class="mine">
whereas, this selector:
:host-context(.mine){
color:red;
}
matches this structure:
<div class="mine">
...
<my-app>
This is useful, if you want to apply styles to components view (shadow root) conditionally. This makes h2
always bold:
h2 {
font-weight: bold;
}
whereas this
:host-context(.make-inner-components-bold) h2 {
font-weight: bold;
}
makes them bold only if your component is inside an element with class .make-inner-components-bold
.
Angular 2: How to style host element of the component?
There was a bug, but it was fixed in the meantime. :host { }
works fine now.
Also supported are
:host(selector) { ... }
forselector
to match attributes, classes, ... on the host element:host-context(selector) { ... }
forselector
to match elements, classes, ...on parent componentsselector /deep/ selector
(aliasselector >>> selector
doesn't work with SASS) for styles to match across element boundariesUPDATE: SASS is deprecating
/deep/
.
Angular (TS and Dart) added::ng-deep
as a replacement that's also compatible with SASS.UPDATE2:
::slotted
::slotted
is now supported by all new browsers and can be used with `ViewEncapsulation.ShadowDom
https://developer.mozilla.org/en-US/docs/Web/CSS/::slotted
See also Load external css style into Angular 2 Component
/deep/
and >>>
are not affected by the same selector combinators that in Chrome which are deprecated.
Angular emulates (rewrites) them, and therefore doesn't depend on browsers supporting them.
This is also why /deep/
and >>>
don't work with ViewEncapsulation.Native
which enables native shadow DOM and depends on browser support.
angular style not applied on components (despite the use of host selectors)
About the width issue your facing in the test component, assuming you want the whole element to span to a width of 350px, you should define its display property to block:
:host {
background: blue;
display: block;
}
Custom elements does not have a default display property and your browser can't guess what your means are.
About applying the .test
style on your component, the app-component
styles are encapsulated using the _nghost-c0
and _ng-content-c0
attributes and therefor not being applied on test.component
. If you want to apply the .test
on other components you can either write the CSS RULE on the global styles.css
file which is applied globally:
//styles.css
.test {
background-color: red;
width: 350px;
}
or use the viewEncapsulation
property on your @component
decorator like this:
//app.component.ts
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
encapsulation: ViewEncapsulation.None
})
and then you can leave the CSS RULE on the app.component
file
//app.component.css
.test {
background-color: red;
width: 350px;
}
but now the styles in that file are not encapsulated and will penetrate other components.
Angular2: replace host element with component's template
Finally I found solution: injecting ElementRef
to MyItem
and using its nativeElement.innerHTML
:
MyList:
import { Component, ContentChildren, QueryList } from 'angular2/core'
import { MyItem } from './myitem'
@Component({
selector: 'my-list',
template: `
<ul>
<li *ngFor="#item of items" [innerHTML]="item.innerHTML"></li>
</ul>
`
})
export class MyList {
@ContentChildren(MyItem) items: QueryList<MyItem>
}
MyItem:
import { Directive, Inject, ElementRef } from 'angular2/core'
@Directive({selector: 'my-item'})
export class MyItem {
constructor(@Inject(ElementRef) element: ElementRef) {
this.innerHTML = element.nativeElement.innerHTML
}
}
Working plunk is here
What is the use case of :host-context selector in angular
This answer explains the difference between host
and host-context
. Here is an example of host-context
usage. Suppose you have a component that wraps an input and this input can be used inside two different components - table and dropdown. When inside a dropdown it should occupy 50% of the width, when in table - 100%. Now if you have these two components selectors defined like this:
<my-dropdown>
<my-table>
Then the styles for the input component can be defined like this:
:host-context(my-dropdown) input { width: 50% }
:host-context(my-table) input { width: 100% }
How to access host component from directive?
You can just inject it
class MyDirective {
constructor(private host:MyComponent) {}
A severe limitation is, that you need to know the type of the component in advance.
See also https://github.com/angular/angular/issues/8277
It also provides some workarounds for when you don't know the type in advance.
Related Topics
Css3 Radial Gradients with Rgba()
How to Make a Box with Arrow in CSS
Svg "Fill: Url(#....)" Behaving Strangely in Firefox
Change Navbar Height in Bootstrap3
Make Div Inside Parent 100% Width of Body, Not Parent Div
CSS Transform Scale, Don't Scale Child Element
::After on :Hover Does Not Work in Ie
Display Footer in Primefaces Template, When Fullpage of P:Layout Is Set to False
Sass Watching Multiple Directories
Image Mysteriously Ignoring Max-Width in Firefox & Ie
What Is the Different Between Clearfix Hack and Overflow:Hidden VS Overflow:Auto
What Are Cross-Browser, Cross Platfom Web Safe Fonts
CSS Dotted Border Render Issue
Why Do /**/ Comments Work in Stylesheets But // Comments Don'T