Components in Angular

Components in Angular

ยท

7 min read

Overview

Components are the main building block for Angular app.

  • An HTML template.

  • A Typescript class that defines behavior.

  • A CSS selector that defines the style of component.

Generating components from Angular CLI is

ng generate component <component-name>

What is Component Decorator?

@Component({
  selector: 'app-component',
  templateUrl: './app-component.component.html',
  styleUrls: ['./app-component.component.css']
})

selector:

  • Every component requires a CSS selector.

  • Selector instructs Angular to instantiate this component wherever it finds the corresponding tag in HTML file.

templateUrl:

  • Define a template for your component in one of two ways

    1. By referencing an external file (Better-way).

    2. Define directly within that component

styleUrls:

  • You can define or give a file for css of this particular component.

Component Lifecycle

How can a component decide the behavior of elements in multiple scenarios?

This life cycle hook gives us to chance to change the behavior of components and act on components at an appropriate moment.

There are many life cycle hooks are available which execute in the below sequence.

  1. ngOnChanges()

    • This is called when any input properties are changed.

    • This method receives a SampleChanges object from previous and current properties values

  2. ngOnInit()

    • Initialize the component after angular displays the properties and set the values for the same.

    • Called after ngOnChanges() and called first ngOnInit() when ngOnChanges() is not there.

  3. ngDoCheck()

    • Detect the changes that angular won't detect(because angular detects changes on only object reference)

    • Called immediately after ngOnChanges on every change detection run or immediately after ngOnInit first run.

    • This lifecycle detects change also when an object mutates.

      for more info

  4. ngAfterContentInit()

    • Content is what is passed as children usually to be projected at some <ng-content> element of a component.

    • This is called after components external content has been initialized.

    • Called only one time after ngDoCheck() is called.

  5. ngAfterContentChecked()

    • This is called after the component view and its child views has been initialized.

    • Called immediately after every subsequent of ngDoCheck() is called.

  6. ngAfterViewInit()

    • View is the template of the current component.

    • This is called after initializing the component's view and it's child view.

      (This is called for only during first change detection cycle.)

    • Called only one time after ngContentChecked().

  7. ngAfterViewChecked()

    • This is called after ngAfetrViewInit() and every subsequent of ngAfterViewChecked().

      (Called for every running change detection cycle on component and it's child)

  8. ngOnDestroy()

    • Clean up the process and destroys the component.

    • Unsubscribe observables to avoid memory leaks.

    • Called immediately before angular destroys the application.

Component Interaction

  • In angular mainly four types of interaction from component to component.

    1. Parent to Child communication (@Input).

    2. Child to Parent communication (@Output).

    3. Transfer data between sibling components.

    4. Transfer data using @ViewChildoperator.

Parent to Child Communication

  • We are using @Input decorator in Child component to take value from Parent component which is set by Parent itself.

    •   // This is child.component.ts file
        import { Component, Input } from '@angular/core';
      
        @Component({
          selector: 'app-child',
          templateUrl: './child.component.html',
          styleUrls: ['./child.component.css']
        })
        export class ChildComponent {
          @Input() ParentToChild?:string; 
        // we have to use this variable in .html file of this component.
        }
      
        <!-- This is child.component.html file-->
        <p>This is child component</p>
        <strong>{{ParentToChild}}</strong>
      
    • Now pass data from Parent component using input.
      (Whatever data we pass in input that reflects on child component)

        // This is parent.component.ts file
        import { Component, DoCheck, OnChanges, OnInit, SimpleChanges } from '@angular/core';
        import { FormControl } from '@angular/forms';
      
        @Component({
          selector: 'app-parent',
          templateUrl: './parent.component.html',
          styleUrls: ['./parent.component.css']
        })
        export class ParentComponent implements OnInit {
      
          p2cControl:FormControl<string>=new FormControl();
          fromParent?:string='';
          ngOnInit(){
            this.p2cControl.valueChanges.pipe().subscribe(q=>{
              this.fromParent=q;
          })
        }
        }
      
      
        <!-- This is parent.component.html file-->
        <p>This is parent component</p>
        <label for="fname">Whatever you type in below is transfer to child</label>
        <ul></ul>
        <input type="text" id="p2cid" [formControl]="p2cControl" name="p2Ccid">
        <app-child [ParentToChild]=fromParent></app-child>
      

Child to Parent Communication

  • We are using @Output decorator for Child to Parent data transfer and

    parent listens for child's event.

  • The parent binds to that event property and reacts to those events.

    //This is chl.component.ts file
    import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
    import { FormControl } from '@angular/forms';

    @Component({
      selector: 'app-child',
      templateUrl: './child.component.html',
      styleUrls: ['./child.component.css']
    })
    export class ChildComponent implements OnInit{

      @Output() ChildToParent=new EventEmitter<string>();
      c2pControl:FormControl<string>=new FormControl();
      ngOnInit(){   
        this.c2pControl.valueChanges.pipe().subscribe(q=>{
          this.ChildToParent.emit(q);
        })
      }

    }
    <!--This is child.component.html file-->
    <input type="text" #c2pid [formControl]="c2pControl" name="c2Pname">
  • Now get data from parent component and event emit through parent.component.html

      <!-- This is parent.component.html file-->
      <strong>{{fromChild}}</strong>
      <app-child [ParentToChild]=fromParent (ChildToParent)="addOutput($event)"></app-child>
    
      // This is parent.component.ts file
      import { Component, DoCheck, OnChanges, OnInit, SimpleChanges } from '@angular/core';
      import { FormControl } from '@angular/forms';
    
      @Component({
        selector: 'app-parent',
        templateUrl: './parent.component.html',
        styleUrls: ['./parent.component.css']
      })
      export class ParentComponent implements OnInit {
        p2cControl:FormControl<string>=new FormControl();
        fromChild?:string='';
      }
      addOutput(value:string)
      {
        this.fromChild=value;
      }
      }
    

Data sharing using @ViewChildoperator.

  1. @Viewchlid using Component.

    • In this way parent component will be able to access the properties and methods of child component.

    • The child component selector will be used in parent component HTML template.

        // This is child.component.ts file
        import { Component } from '@angular/core';
        @Component({
          selector: 'app-child',
          template: '<b>{{message}}</b>'
        })
        export class ChildComponent {
            messageShow() {
               this.message = "Message: " +"Yayyy this viewchild component works" ;
            }
        }
      
        // This is parent.component.ts file
        import { Component, ViewChild } from '@angular/core';
        import { ChildComponent } from './number.component';
      
        @Component({
               selector: 'app-parent',
               templateUrl: './parent.component.html',
               styleUrls: ['./parent.component.css']
        })
        export class ParentComponent {
         @ViewChild(ChildComponent)
         private childComponent = {} as ChildComponent;
         show() {
               this.childComponent.messageShow();
               }
        }
      
        <!-- This is parent.component.html file-->
        <;h3>@ViewChild using Component</h3>;
        Example:
        <button type="button" (click)="show()">Click me</button>
        <br/><br/>
        <app-child></app-child>
      
  2. @ViewChild using Directive.

    • This can instantiate a directive within a component and in this way the component will be able to access the directive methods.

        //This is directive.directive.ts file
        import { Directive, ElementRef, AfterViewInit } from '@angular/core';
        @Directive({ 
             selector: '[directive]' 
        })
        export class Directive implements AfterViewInit{
            constructor(private elRef: ElementRef) {
            }
            change() {
               this.elRef.nativeElement.innerText= 'ChangedText';
            }
        }
      
        //This is parent.component.ts file
        import { Component, ViewChild } from '@angular/core';
        import { CpColorDirective } from './cpcolor.directive';
      
        @Component({
            selector: 'app-parent',
            templateUrl: './parent.component.html',
            styleUrls: ['./parent.component.css']
        })
        export class ParentComponent {
            @ViewChild(directive)
            private refDirective = {} as Directive;
            change() {
                this.refDirective.change();
            }
        }
      
        <!-- This is parent.component.html file-->
        <;h3>@ViewChild using Directive</h3>;
        Example:
        <p directive>This text will change after button click</p>
        <div>
        <button type="button" (click)="change()">Click me</button>  
        </div>
      
  3. use @ViewChid to inject a reference to a DOM element.

    • In some cases we may require to change or modified the current component data or need to some operation with component's element then we have to use this method.

    • Like we discuss the example below viewchildcomponent .

    • But, before we move forward to eg. we know the...

      • When variables are injected via @ViewChild ?

        The value of this injected member variable is not immediately available at component construction time!

        Angular will fill in this property automatically, but only later in the component lifecycle, after the view initialization (nfAfterViewInit()) is completed.

          // This is viewchildcomponent.ts file
          import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
          @Component({
            selector: 'app-viewchildcomponent',
            templateUrl: './viewchildcomponent.component.html',
            styleUrls: ['./viewchildcomponent.component.css']
          })
          export class ViewchildcomponentComponent implements AfterViewInit {
        
            @ViewChild('viewchildcomponent')
            viewchildcomponent?:ElementRef;
        
            ngAfterViewInit(){
              console.log(this.viewchildcomponent?.nativeElement);
        
            }
          }
        
          <!-- This is viewchildcomponent.html file-->
          <p  #viewchildcomponent> viewchildcomponent works!</p>
        
  4. use @ViewChid to inject a reference to a DOM element of a component.

    • You can same achieve for this reference to a DOM element of a component.

    • You can take component as a reference in your parent-component and modify the content or using for other process also.

    • Like for below example parent-component and viewchildcomponent.

        // This is parent.component.ts file
        import { AfterViewInit, Component,ViewChild } from '@angular/core';
        import { ViewchildcomponentComponent } from '../viewchildcomponent/viewchildcomponent.component';
      
        @Component({
          selector: 'app-parent',
          templateUrl: './parent.component.html',
          styleUrls: ['./parent.component.css']
        })
        export class ParentComponent implements AfterViewInit{
        @ViewChild('viewchild')
        component?: ViewchildcomponentComponent;
        ngAfterViewInit() {
          console.log('Values on ngAfterViewInit():');
          console.log("component:", this.component);
        }
        }
      
        <!--This is parent.component.html file-->
        <p>This is parent component</p>
        <app-viewchildcomponent #viewchild></app-viewchildcomponent>
      

      yupp๐ŸŽ‰๐ŸŽ‰ that's it btw you can check out more for viewchild in angular-university and other.

      Thankyou ๐Ÿค๐Ÿค

ย