Angular 14 New Features

How to install Angular 14?

  • The following flag might be used to install Angular 14 with npm.
  • To install the most recent version of Angular, just launch a new command-line interface and enter the following command:
  1. npm install –global @angular/cli@next

Angular 14 Features

1. Standalone Components

  • A standalone component may be depended upon directly, without the requirement for an intermediary NgModule, and it is not specified in any existing NgModule. It also directly handles its dependencies (instead of having them maintained by a NgModule).

Key Points

  • Standalone component has the flag “standalone” we need to set the value true.
  • Not Required to add the standalone component in ngModule.
  • We can import the required modules in the component itself.
  • Command
    ng g c standalonedemo --standalone
    import { Component, OnInit } from '@angular/core';
    import { CommonModule } from '@angular/common';
    
    @Component({
        selector: 'app-standalonedemo',
        standalone: true,
        imports: [CommonModule],
        templateUrl: './standalonedemo.component.html',
        styleUrls: ['./standalonedemo.component.css']
    })
    export class StandalonedemoComponent implements OnInit {
        constructor() {}
        ngOnInit(): void {}
    }
    <div class="container pages text-justify pb-5">
        <h1 class="mb-4">Angular 14 Standalone Component</h1>
        <p>standalonedemo works!</p>
    </div>

     

2. Typed Forms

  • Strictly typed forms are the most often requested Angular feature on GitHub, which would enhance the framework’s model-driven approach to handling forms.

Key Points

  • This feature is only for reactive forms.
  • For using this feature tsconig.js should be in strict mode.
  • Typed forms ensure that the values inside of form control, groups and array are type safe across the entire API surface.
  • This helps developer for generating safer forms and it helps in case of complex nested object.
  • If you want to use the older version you can use the untyped version.

E.g. create a contact us standalone component and add 4 fields in it (name, number, email, message) and import ReactiveFormsModule in it as shown below,

import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, UntypedFormControl, UntypedFormGroup } from '@angular/forms';

@Component({
    selector: 'app-contactus',
    standalone: true,
    imports: [CommonModule, ReactiveFormsModule],
    templateUrl: './contactus.component.html',
    styleUrls: ['./contactus.component.css']
})
export class ContactusComponent implements OnInit {
    constructor() {}
    ngOnInit(): void {}
    contactForm = new FormGroup({
        name: new FormControl < string > (''),
        email: new FormControl(''),
        message: new FormControl(''),
        number: new FormControl()
    });
    contactFormUntyped = new UntypedFormGroup({
        name: new UntypedFormControl(''),
        email: new FormControl(''),
        message: new FormControl(''),
        number: new FormControl()
    });
    Submit() {
        console.log(this.contactForm.value);
        console.log(this.contactForm.value.email?.length); //check the null value
        console.log(this.contactForm.value.email!.length); //If you are sure value is not null
        console.log(this.contactFormUntyped.value.name.length); // throw error in browser
    }
}
<div class="container pages text-justify pb-5">
    <h1 class="mb-4">Angular 14  Typed Form</h1>
    <section class="mb-4">
        <!--Section heading-->
        <div class="row">
            <!--Grid column-->
            <div class="col-md-9 mb-md-0 mb-5">
                <form [formGroup]="contactForm" (ngSubmit)="Submit()">
                    <!--Grid row-->
                    <div class="row">
                        <!--Grid column-->
                        <div class="col-md-6">
                            <div class="md-form mb-0">
                                <input formControlName="name" type="text" class="form-control">
                                <label for="name" class="">Your name</label>
                            </div>
                        </div>
                        <!--Grid column-->
                        <!--Grid column-->
                        <div class="col-md-6">
                            <div class="md-form mb-0">
                                <input formControlName="email" type="text" class="form-control">
                                <label for="email" class="">Your email</label>
                            </div>
                        </div>
                        <!--Grid column-->
                    </div>
                    <!--Grid row-->
                    <!--Grid row-->
                    <div class="row">
                        <div class="col-md-12">
                            <div class="md-form mb-0">
                                <input formControlName="number" type="text" class="form-control">
                                <label for="subject" class="">Number</label>
                            </div>
                        </div>
                    </div>
                    <!--Grid row-->
                    <!--Grid row-->
                    <div class="row">
                        <!--Grid column-->
                        <div class="col-md-12">
                            <div class="md-form">
                                <textarea formControlName="message" type="text" rows="2" class="form-control md-textarea"></textarea>
                                <label for="message">Your message</label>
                            </div>
                        </div>
                    </div>
                    <!--Grid row-->
                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
            <!--Grid column-->
        </div>
    </section>
</div>

3. Streamlined page title accessibility (Title Strategy)

  • While you are creating apps, your page title displays the content of your page in a different way. The new Route.title attribute in the Angular router simplified the process of adding titles in Angular 13. When adding a title to your page, Angular 14 does not require any additional imports.
  • Visit the routing module, where we are currently defining our routes. By modifying the approuting module as shown, we have the ability to add the title to the route and implement the TitleStrategy.
    import { NgModule } from '@angular/core';
    import { RouterModule, RouterStateSnapshot, Routes, TitleStrategy } from '@angular/router';
    import { ContactusComponent } from './contactus/contactus.component';
    import { HomeComponent } from './home/home.component';
    import { StandalonedemoComponent } from './standalonedemo/standalonedemo.component';
    
    const routes: Routes = [
      {path:'',component:HomeComponent, title : "Core Knowledge Sharing"},
      { path: 'standalonedemo', component: StandalonedemoComponent, title : "Stand alone Component" },
      { path: 'contactus', component: ContactusComponent, title : "Contact Us" }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule extends TitleStrategy {
      updateTitle(snapshot: RouterStateSnapshot): void {
         const pageTitle = this.buildTitle(snapshot);
         if(pageTitle != undefined){
          document.title = "${pageTitle}"
         }
      }
    }

     

4. Extended developer diagnostics (ng compilation)

  • With the help of this feature from Angular v14, you may gain deeper insights into your templates and receive recommendations for future improvements. In our component, such as the contact us component, you delete the reactive, it also checks for syntax errors.

5. Bind to protected component members

  • In v14, you can now bind to protected component members directly from your templates
@Component({
    selector: 'my-component',
    template: '{{ message }}',  // Now compiles!
})
export class MyComponent {
    protected message: string = 'Hello world';
}

6. Optional Injectors in Embedded Views

  • v14 adds support for passing in an optional injector when creating an embedded view through ViewContainerRef.createEmbeddedView and TemplateRef.createEmbeddedView. The injector allows for the dependency injection behavior to be customized within the specific template.
  • This enables cleaner APIs for authoring reusable components and for component primitives in Angular CDK.
    viewContainer.createEmbeddedView(templateRef, context, {
      injector: injector,
    })

     

7. NgModel OnPush

  • I have two parts: the first is a straightforward child component that accepts input and provides rudimentary support for the [ngModel] directive using the ControlValueAccesor interface. The second one is a parent component with a onPush change detection technique that uses the [ngModel] directive to populate a value into the child component (after which it is tagged for changes using the ChangeDetectorRef class). Despite the component object having the correct value in the target property when [ngModel] is changed, the child component continues to display an outdated value in the template.
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-onpushdemo',
    template: `<div>
  <app-child [ngModel]="value"></app-child>
</div>`,
    styleUrls: ['./onpushdemo.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnpushdemoComponent implements OnInit {
    public value: any = "old value";
    constructor(private _changeDetector: ChangeDetectorRef) {
        setTimeout(() => {
            debugger;
            this.value = "new value";
            this._changeDetector.markForCheck();
        }, 5000)
    }
    ngOnInit(): void {}
}
import { Component, forwardRef, OnInit } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
    selector: 'app-child',
    template: `<div (click)="click()">Current Value: {{value}}.
  Click me to force change detection</div>`,
    styleUrls: ['./child.component.css'],
    inputs: ['value'],
    providers: [{
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => ChildComponent),
        multi: true
    }],
})
export class ChildComponent implements OnInit {
    constructor() {}
    public value: any;
    public onChange: (_: any) => void = (_: any) => {
        // do nothing
    };
    public onTouched: () => void = () => {
        // do nothing
    };
    public writeValue(value: any): void {
        this.value = value;
    }
    public click(): void {
        debugger;
        this.value = "child new value";
        // event just forces angular to re run change detection
    }
    public registerOnChange(fn: (_: any) => void): void {
        this.onChange = fn;
    }
    public registerOnTouched(fn: () => void): void {
        this.onTouched = fn;
    }
    ngOnInit(): void {}
}

 

Submit a Comment

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

Subscribe

Select Categories