Angular 4

Angular 4 Tutorial : View Encapsulation and Local References

Local References Angular 4 tutorial

Hello all, in the previous post, http://mytechthinking.in/2017/10/11/angular-4-tutorial-custom-data-bindings/ we learned about the custom two way data binding. In this post, we will learn more about the components and how angular manages the components view and also about the local references in templates.

View Encapsulation

As we know every component has its styles and template. In the last post, we saw multi components example, in that if I change the style of any HTML element in any one component CSS file the same element in other components will not have those styles. For example, in Component Display-Output, I change the background-colour of paragraph tag,

p {
background-color: blue;
}

which will set the color of paragraph tag of Display-Output component only and not other components. But we know that this not the way CSS works; it will apply changes to every p tag in the page. This restriction is imposed by angular, on compilation angular gives every component an unique id and also modifies the CSS too. And therefore we can design every component separately. But if we want we can change the default behaviour of angular by adding a property to the Component decorator.

import { Component, ViewEncapsulation } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  encapsulation: ViewEncapsulation.None
})
When the encapsulation property is set to ViewEncapsulation.None angular does not add the unique attribute to the elements of that component, so any global changes will reflect these elements.
ViewEncapsulation enum has two more properties, Emulated and Native which apparently seems to same. The difference is that if encapsulation is set Emulated angular we emulated the shadow dom technology for non supporting browsers, whereas in case of Native it will use the shadow dom technology only for supported browsers. For most of the cases, it is recommended to use Emulated or None only. By default, angular sets this property to Emulated as to support all browsers.

Local References

In the previous, you would have seen that to access a component we used data binding. For example, to get the text entered in the input field we bind to some string variable using [(ngModel)] attribute. But there’s another way to do that using local references.
The local reference is like creating a unique variable to point it to the particular HTML element. Local reference can be created for any element by setting the variable name with prefix #. Like <p #content> in this content will hold the reference to whole <p> element and not only its value. But the local reference can be used in the template only and not in typescript unlike data binding or interpolation. But we can always pass it as a parameter to the methods and then can access it in typescript. In the below example, the input element is accessed in the typescript using the local reference.

<form class="example-form">
    <mat-toolbar>Local References</mat-toolbar>
    <mat-form-field class="example-full-width">
      <input  #contentText matInput placeholder= "Enter text content" >
    </mat-form-field>
    <button mat-raised-button (click)="setText(contentText)" color="primary">Set Text </button>
    <span class="mat-h3">
      Displayed Text : {{displayContent}}
      </span>
    </form>
export class AppComponent {
displayContent = '';
  setText(inputElement: HTMLInputElement) {
    this.displayContent = inputElement.value;
  }
}
 Screen Shot:
Local References-screenshot

 

 

 

 

In the above example, we passed the Element to a method to access it, but there is another way to access DOM element in typescript code and that without passing as an argument, using the @ViewChild() decorator.


ViewChild Decorator

ViewChild decorator takes input as the local reference name and binds it to the property making the DOM element accessible through the typescript code.
But it differs from local references which we discussed earlier. In the earlier example, the local reference passed was of type HTMLInputElement, but here we get the reference of the DOM element and not the actual element so it is of type ElementRef fo angular/core package. Let’s see the above example with ViewChild decorator.

import { Component, ViewEncapsulation, ViewChild, ElementRef } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  /* encapsulation: ViewEncapsulation.None */
})
export class AppComponent {
  colorArray = [{color: 'pink', content: 'I am pink!'}];
  displayContent = '';
  @ViewChild('contentText') textInput: ElementRef;
  /* setText(inputElement: HTMLInputElement) {
this.displayContent = inputElement.value;
  } */
  setText() {
    this.displayContent = this.textInput.nativeElement.value;
  }
}

<form class="example-form">
    <mat-toolbar>Local References</mat-toolbar>
    <mat-form-field class="example-full-width">
      <input  #contentText matInput placeholder= "Enter text content" >
    </mat-form-field>
    <button mat-raised-button (click)="setText()" color="primary">Set Text </button>
    <span class="mat-h3">
      Displayed Text : {{displayContent}}
      </span>
    </form>

As you can see we are binding the same local reference to the property and accessing the native element without passing it to the method. We change the way to access it but the output remains the same.

ng-Content

Till now we learned different ways to pass data to components, access the elements. There is one more way to pass data to a component.
There might be some use case where you may need to pass the content of child component from the parent component. And you might have noticed that whenever we use component selectors(component tags) we don’t add anything between the opening and closing tags of the components. We can do that too, we can pass content from the parent component where we have used child components and add the content between the closing and opening tags.
By default angular ignores anything between the tags, so to let angular render the content from the parent component we’ll have to use a special directive ng-content. When ng-content is used angular we render the passed content from the parent to the child template. Let see an example of that. To explain I’ll use display component and app component.
App Component

<form class="example-form">
<!-- <mat-toolbar>Local References</mat-toolbar> -->
<app-display>
<mat-form-field class="example-full-width">
<input #contentText matInput placeholder= "Enter text content" >
</mat-form-field>
<button mat-raised-button (click)="setText()" color="primary">Set Text </button>
<span class="mat-h3">
Displayed Text : {{displayContent}}
</span>
</app-display>
</form>

Display Component

<mat-toolbar>Local References</mat-toolbar>
<ng-content></ng-content>

In the above, as you can see the markup of input field and button are added between the tags of the display component. And in display component, we have added the tag to tell angular that this place please project the passed elements. Points note is that ng-content is required to let angular project the content and also the place where the ng-content tag is added only there the content will be projected. Like in our example below the toolbar.

In the next post, http://www.mytechthinking.in/2017/10/14/angular-4-tutorial-component-lifecycle/ we will learn about the lifecycle of a component.

Leave a Reply

Your email address will not be published. Required fields are marked *