Cannot Understand the Use of :Host in Components in Angular2

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) { ... } for selector to match attributes, classes, ... on the host element
  • :host-context(selector) { ... } for selector to match elements, classes, ...on parent components

  • selector /deep/ selector (alias selector >>> selector doesn't work with SASS) for styles to match across element boundaries

    • UPDATE: 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



Leave a reply



Submit