Showing posts with label Angular. Show all posts
Showing posts with label Angular. Show all posts

Wednesday, 9 October 2024

Unsubscribe observable

How to Unsubscribe

Various ways to Unsubscribe

Use Async Pipe: Use Async pipe to subscribe to an observable, it automatically cleans up, when we destroy the component.

Use Unsubscribe(): Use Unsubscribe() method on the subscription. It will clean up all listeners and frees up the memory

To do that, first create a variable to store the subscription.

  obs: Subscription;

Assign the subscription to the obs variable

  this.obs = this.src.subscribe(value => {
    console.log("Received " + this.id);
  });

Call the unsubscribe() method in the ngOnDestroy method.

  ngOnDestroy() {
    this.obs.unsubscribe();
  }

When we destroy the component, the observable is unsubscribed and cleaned up.

Continue Reading →

Saturday, 21 September 2024

Dependency injection in Angular

Understanding dependency injection

Two main roles exist in the DI system: dependency consumer and dependency provider.

Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called Injector.

When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process, as well as any other injectors as needed.

Providing dependency

Imagine there is a class called HeroService that needs to act as a dependency in a component.

The first step is to add the @Injectable decorator to show that the class can be injected.

  @Injectable()
  class HeroService {}

The next step is to make it available in the DI by providing it. A dependency can be provided in multiple places:

  • At the Component level, using the providers field of the @Component decorator. In this case the HeroService becomes available to all instances of this component and other components and directives used in the template.
    For example:

  @Component({
    standalone: true,
    selector: 'hero-list',
    template: '...',
    providers: [HeroService]
  })
  class HeroListComponent {}

        When you register a provider at the component level, you get a new instance of the service
        with each new instance of that component.

  • For NgModule based applications, use the providers field of the @NgModule decorator to provide a service or other Injectable available at the application level.

for example:

  export const appConfig: ApplicationConfig = {
    //List of providers that should be available to the root component and all its children.
        providers: [
          { provide: HeroService },
        ]
    };

Then, in main.ts:

  bootstrapApplication(AppComponent, appConfig)

ApplicationConfig: Set of config options available during the application bootstrap operation.

At the application root level, which allows injecting it into other classes in the application. This can be done by adding the providedIn: 'root' field to the @Injectable decorator:

  @Injectable({
    providedIn: 'root'
  })
  class HeroService {}

When you provide the service at the root level, Angular creates a single, shared instance of the HeroService and injects it into any class that asks for it. Registering the provider in the @Injectable metadata also allows Angular to optimize an app by removing the service from the compiled application if it isn't used, a process known as tree-shaking.

Injecting a dependency

The most common way to inject a dependency is to declare it in a class constructor. When Angular creates a new instance of a component, directive, or pipe class, it determines which services or other dependencies that class needs by looking at the constructor parameter types. For example, if the HeroListComponent needs the HeroService, the constructor can look like this:

  @Component({ … })
  class HeroListComponent {
    constructor(private service: HeroService) {}
  }

When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector creates one using the registered provider, and adds it to the injector before returning the service to Angular.

When all requested services have been resolved and returned, Angular can call the component's constructor with those services as arguments.

 How Dependency Injection & Resolution Works in Angular?

The Angular creates a hierarchical dependency injection system. It creates a hierarchical tree of Injectors. Each Injector gets their own copy of Angular Providers. Together these two form the core of the Angular dependency injection framework. 

Injector

The Angular creates an Injector instance for every Component, Directive, etc it loads. It also creates an injector instance for the Root Module and for every lazy loaded module. But eagerly loaded modules do not get their own injector but share the injector of the Root Module.

Injector Tree

Angular Creates not one but two injector trees. Module Injector tree & Element Injector tree.

Module Injector tree is for Modules (@NgModule). For Root Module & for every Lazy Loaded Module.

Element Injector tree is for DOM Elements like Components & Directives.

Module Injector Tree

Angular creates the ModuleInjector for the services to be provided at Module Levels.

Angular Creates the Module Injector tree when the Application starts.

At the top of the Module Injector tree, Angular creates an instance of Null Injector. The Null Injector always throws an error unless we decorate the dependency with the Optional decorator.

Under Null Injector Angular creates an instance of PlatformInjector. Platform Injector usually includes built-in providers like DomSanitize etc.



Dependency providers
  • Class providers: useClass : The useClass provider key lets you create and return a new instance of the specified class. You can use this type of provider to substitute an alternative implementation for a common or default class. The alternative implementation can, for example, implement a different strategy, extend the default class, or emulate the behavior of the real class in a test case. In the following example, the BetterLogger class would be instantiated when the Logger dependency is requested in a component or any other class.

      [{ provide: Logger, useClass: BetterLogger }]

  • Alias providers: useExisting
  • Factory providers: useFactory

Read more in detail https://www.tektutorialshub.com/angular/angular-dependency-injection/

https://www.tektutorialshub.com/https://www.tektutorialshub.com/

https://www.tektutorialshub.com/angular/angular-providers/


Continue Reading →

Trackby in ngFor Angular

  Angular Trackby option improves the Performance of the ngFor if the collection has a large no of items and keeps changing. This can significantly reduce the number of DOM manipulations required, especially in large lists.

Here's a brief overview of how to use trackBy:

Syntax

You can use trackBy by providing a function that returns a unique identifier for each item in the list. This function is typically defined in your component class.

Example

Suppose you have a list of items that you want to display:

// In your component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-item-list',
  template: `
    <ul>
      <li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>
    </ul>
  `
})
export class ItemListComponent {
  items = [
    { id: 1, name: 'Item 1' },
    { id: 2, name: 'Item 2' },
    { id: 3, name: 'Item 3' }
  ];

  trackById(index: number, item: any): number {
    return item.id; // Return unique identifier
  }
}

How It Works

  1. Define a Unique Identifier: The trackById function returns the unique id of each item. This helps Angular track which items have changed.

  2. Use trackBy in *ngFor: Add trackBy: trackById to the *ngFor directive.

Benefits

  • Performance: By using trackBy, Angular can skip re-rendering items that haven’t changed, which improves performance, especially with large datasets.
  • Reduced Reconciliation: It minimizes the work done during change detection by only updating the items that have changed.

When to Use trackBy

You should consider using trackBy whenever you're rendering lists, particularly when:

  • The list is large.
  • The items in the list may change frequently.
  • You want to improve the performance of your application.

Using trackBy is a best practice in Angular for rendering lists efficiently.



Continue Reading →

@Self, @SkipSelf & @Optional Decorators Angular

@Self, @SkipSelf and @Optional are Angular Decorators that configure how the DI Framework should resolve the dependencies. These decorators are called Resolution Modifiers because they modify the behavior of injectors. In this page, we will learn @Self, @SkipSelf, & @Optional. 

 How Angular DI Framework Resolves Dependencies

When a component asks for Dependency, the DI Framework resolves it in two phases.

In the first phase, it starts to look for the Dependency in the current component’s ElementInjector. If it does not provide the Dependency, it will look in the Parent Components ElementInjector. The Request bubbles up until it finds an injector that provides the service or reaches the root ElementInjector.

If ElementInjector does not satisfy the request, Angular looks for the Dependency in the ModuleInjector hierarchy. If Angular still doesn’t find the provider, it throws an error.

We have created an example project in Angular to explain the @Self, @SkipSelf, & @Optional. 

The Code contains a RandomService, which generates a Random Number when initialized. The Angular Service is added to the Providers array of the AppModule. We can inject this service anywhere in our Application.

@Injectable({
  providedIn: "root"
})
export class RandomService {

The project contains three Angular Components (AppComponent, ChildComponent & GrandChildComponent) all inject the RandomService and displays the Random Number from the Service.

We also have testDirective, which we include in the template of GrandChildComponent. It also displays the Random Number from the Service.

Ensure that the Providers array is empty in all components & directives. Run the App. Angular creates only one instance of the RandomService. That is why all the components and directives show the same number.


@Self: The @Self decorator instructs Angular to look for the dependency only in the local injector. The local injector is the injector that is part of the current component or directive.

import { ComponentSkipSelfSelfOptionalHost } from "@angular/core";
import { RandomService } from "./random-service";

@Component({
  selector: "my-grandChild",
  template: `
    <div class="box">
      GrandChildComponent => {{ randomNo }}
      <div class="dirbox" testDirective>fdf</div>
    </div>
  `,
  providers: [RandomService]
})
export class GrandChildComponent {
  randomNo;
  constructor(@Self() private randomServiceRandomService) {
    this.randomNo = randomService.RandomNo;
  }

This forces the Angular DI Framework to look for the Dependency attached to the current Component. I added the RandomService to the providers array of the GrandChildComponent.

As you can see from the image Angular creates two instances of RandomService. One from the AppModule and another from the GrandChildComponent. Also, note that testDirective picks up the RandomService provided from the GrandChildComponent and not from the AppModule

@SkipSelf: The @SkipSelf decorator instructs Angular to look for the dependency in the Parent Injector and upwards.

It tells Angular not to look for the injector in the local injector, but start from the Parent. You can think of this decorator as the opposite of the @Self

Open the GrandChildComponent again. Add the SkipSelf instead of Self decorator.

export class GrandChildComponent {
  randomNo;
  constructor(@SkipSelf() private randomServiceRandomService) {
    this.randomNo = randomService.RandomNo;
  }
}

As you can see from the image, the GrandChildComponent, picks up RandomService instance provided by the Module and not the one provided by itself. 
But, the testDirective still picks up the RandomService provided by the GrandChildComponent.

@Optional: Optional marks the dependency as Optional. If the dependency is not found, then it returns null instead of throwing an error

In the GrandChildComponent remove the RandomService from the Providers Array and add the @Self decorator. You will instantly receive the error “No provider for RandomService found in NodeInjector“.

Add the @Optional decorator along with the @Self. Now, the dependency injection will return null instead of an error.

Also, remember to add the ? in randomService?, else you will get the “Cannot read property ‘RandomNo’ of null” error.

export class GrandChildComponent {
  randomNo;
  constructor(@Optional() @Self() private randomServiceRandomService) {
    this.randomNo = randomService?.RandomNo;
  }
}

As you can see in the image, GrandChildComponent does not receive any values, while testDirective picks up the RandomService provided by the AppModule



Continue Reading →

Friday, 24 February 2023

View encapsulation in Angular

 In Angular, a component's styles can be encapsulated within the component's host element so that they don't affect the rest of the application.

The Component decorator provides the encapsulation option which can be used to control how the encapsulation is applied on a per component basis.

Choose from the following modes:

ViewEncapsulation.ShadowDom: Angular uses the browser's built-in Shadow DOM API to enclose the component's view inside a ShadowRoot, used as the component's host element, and apply the provided styles in an isolated manner.

ViewEncapsulation.ShadowDom only works on browsers that have built-in support for the shadow DOM (see Can I use - Shadow DOM v1). Not all browsers support it, which is why the ViewEncapsulation.Emulated is the recommended and default mode.                             

ViewEncapsulation.Emulated: Angular modifies the component's CSS selectors so that they are only applied to the component's view and do not affect other elements in the application, emulating Shadow DOM behavior. For more details, see Inspecting generated CSS.

ViewEncapsulation.None: Angular does not apply any sort of view encapsulation meaning that any styles specified for the component are actually globally applied and can affect any HTML element present within the application. This mode is essentially the same as including the styles into the HTML itself.

Reference: https://angular.io/

Continue Reading →

Sunday, 29 January 2023

Angular authentication

Here I am providing only code snippet, required for angular authentication. If you are angular guy then you will understand the code easily and use in your application.

I have a User Model. Below is the code.

1- Creating user model

export class User {
    isAuth = false;
    userId: string;
    email: string;
    password: string;
    name: string;
    address: string;
    role: string;
    roles = [];
    token: string;
    contact: string;
    createdDate: any;
    updatedDate: any;
    costructor() { }
}


Environment.ts file code snippet.

export const environment = {
  production: false,
  apiAddress: 'http://localhost:1300/api',
}



2- Creating AuthService

First we will create a Auth service in Angular. Below is the code for AuthService.

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { UserLogin } from '../public/models/userLogin';
import { Observable } from 'rxjs/Rx';

import { User } from '../models/user';
import { environment as env } from '../../environments/environment';

declare const localStorage: any;

@Injectable()
export class AuthService {
    headers: Headers;
    user: User;
    constructor(private http: Http) {
        this.headers = new Headers({ 'content-type': 'application/json' });
        this.loadAuthUser();
    }
    loadAuthUser() {
      if (localStorage['authInfo'] !== undefined && localStorage['authInfo'] !== null) {
            this.user = JSON.parse(localStorage['authInfo']);
      }
    }
    SignOut() {
        localStorage.removeItem('authInfo');
        this.user = undefined;
    }
    setAuthUser(user: User) {
        localStorage['authInfo'] = JSON.stringify(user);
        this.user = user;
    }
    ValidateUser(user: UserLogin): Observable<User> {
        return this.http.post(env.apiAddress + '/auth', JSON.stringify(user),
            { headers: this.headers }).map((res) => {
                return res.json();
            }).catch((err) => Observable.throw(err));
    }
}


3- Creating LoginComponent code

Then We will call Login function for user authentication and token storage. Below is the code for Login Component.

import { Component, OnInit } from '@angular/core';
import { UserLogin } from '../models/userLogin';
import { AuthService } from '../../services/auth.service';
import { User } from '../../models/user';
import { Router, ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styles: []
})
export class LoginComponent implements OnInit {
  user: UserLogin;
  ref = '';
  constructor(private authService: AuthService, private router: Router,
                                                    private route: ActivatedRoute) {
    this.user = new UserLogin();
  }

  ngOnInit() {  
    this.route.queryParams.subscribe((params) => {
      this.ref = params.ref;
    });
  }
  Login() {
    this.authService.ValidateUser(this.user).subscribe((res) => {
      const authObj: User = res;
      if (authObj.email !== '') {
        authObj.isAuth = true;
        this.authService.setAuthUser(authObj);
        if (this.ref !== undefined && this.ref !== '') {
          this.router.navigate([this.ref]);
        }
        else {
          if (authObj.roles.indexOf('Admin') > -1) {
            this.router.navigate(['admin']);
          } else {
            this.router.navigate(['user']);
          }
        }
      }
    });
  }
}


4- Creating AppRouting file 

Below is the Code of app.routing.ts file.

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AdminAuthGuard, UserAuthGuard } from './services/auth.guard';

const routes: Routes = [
    { path: '', loadChildren: 'app/public/public.module#PublicModule' },
    { path: 'user', loadChildren: 'app/user/user.module#UserModule',
                                                    canActivate:[UserAuthGuard] },
    { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule',
                                                    canActivate: [AdminAuthGuard] }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule],
})
export class AppRoutingModule { }


5- Creating Route Guard file 

Below is the code of auth.guard.ts file.

import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class AdminAuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) { }
  canActivate() {
    if (!(this.authService.user != null && this.authService.user.isAuth)) {
      this.router.navigate(['login']);
      return false;
    } else if (this.authService.user.roles.indexOf('Admin') > -1) {
      return true;
    } else {
      this.router.navigate(['unauthorize']);
      return false;
    }
  }
}

@Injectable()
export class UserAuthGuard implements CanActivate {
  constructor(private authService: AuthService, private router: Router) { }
  canActivate() {
    if (!(this.authService.user != null && this.authService.user.isAuth)) {
      this.router.navigate(['login']);
      return false;
    } else if (this.authService.user.roles.indexOf('User') > -1) {
      return true;
    } else {
      this.router.navigate(['unauthorize']);
      return false;
    }
  }
}

Creating Sign-out feature 

Below is the code snippet from a component.

  ...
    <ul class="nav navbar-nav pull-right" *ngIf="authService.user!=undefined">
      <li style="padding: 15px;">
        Welcome : {{authService.user.name}}
      </li>
      <li>
        <a href="javascript:void(0)" (click)="signout()">SignOut</a>
      </li>
    </ul> ...


  ...       constructor(public authService: AuthService, private router: Router) { }
      signout() {
        this.authService.SignOut();
        this.router.navigate(['/login']);
      }     ...

Sending token value in Request header- 

1- Using Http-Interceptors

2- Using RequestOptions (below is example code snippet)

@Injectable()
export class ProductService {
  private baseUrl = '';
  private headers: any;
  private options;
  constructor(private http: Http, private authService: AuthService) {
    this.options = new RequestOptions({     headers: new Headers({                           'authorization': this.authService.user.token,
                          'Content-Type': 'application/json'
                         })
    });
    this.baseUrl = env.apiAddress;
  }

  getAll(): Observable<Product[]> {
    return this.http.get(`${this.baseUrl}/product`, this.options)
      .map((res: Response) => res.json())
      .catch((error: any) => Observable.throw(error.json().error || 'Server error'));
  }
  add(product: Product): Observable<Response> {
    return this.http
      .post(`${this.baseUrl}/product`, JSON.stringify(product), this.options)
      .catch((error: any) => Observable.throw('Server error'));
  }
    .......         ......


Continue Reading →

Tuesday, 17 January 2023

Understanding dependency injection Angular

 Dependency injection, or DI, is one of the fundamental concepts in Angular. DI is wired into the Angular framework and allows classes with Angular decorators, such as Components, Directives, Pipes, and Injectables, to configure dependencies that they need.

Two main roles exist in the DI system: dependency consumer and dependency provider.

Angular facilitates the interaction between dependency consumers and dependency providers using an abstraction called Injector. When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry. Angular creates an application-wide injector (also known as "root" injector) during the application bootstrap process, as well as any other injectors as needed. 

Providing dependency

Imagine there is a class called HeroService that needs to act as a dependency in a component.

The first step is to add the @Injectable decorator to show that the class can be injected.

@Injectable()
class HeroService {}

The next step is to make it available in the DI by providing it. A dependency can be provided in multiple places:

At the Component level, using the providers field of the @Component decorator. In this case the HeroService becomes available to all instances of this component and other components and directives used in the template. For example:

  @Component({
    selector: 'hero-list',
    template: '...',
    providers: [HeroService]
  })
  class HeroListComponent {}

When you register a provider at the component level, you get a new instance of the service with each new instance of that component. 

At the NgModule level, using the providers field of the @NgModule decorator. In this scenario, the HeroService is available to all components, directives, and pipes declared in this NgModule. For example:

  @NgModule({
    declarations: [HeroListComponent]
    providers: [HeroService]
  })
  class HeroListModule {}

When you register a provider with a specific NgModule, the same instance of a service is available to all components in that NgModule. 

At the application root level, which allows injecting it into other classes in the application. This can be done by adding the providedIn: 'root' field to the @Injectable decorator:

  @Injectable({
    providedIn: 'root'
  })
  class HeroService {}

When you provide the service at the root level, Angular creates a single, shared instance of the HeroService and injects it into any class that asks for it. 

Injecting a dependency

The most common way to inject a dependency is to declare it in a class constructor. When Angular creates a new instance of a component, directive, or pipe class, it determines which services or other dependencies that class needs by looking at the constructor parameter types. For example, if the HeroListComponent needs the HeroService, the constructor can look like this:

  @Component({ … })
  class HeroListComponent {
    constructor(private service: HeroService) {}
  }

When Angular discovers that a component depends on a service, it first checks if the injector has any existing instances of that service. If a requested service instance doesn't yet exist, the injector creates one using the registered provider, and adds it to the injector before returning the service to Angular.

When all requested services have been resolved and returned, Angular can call the component's constructor with those services as arguments.


Angular Providers: UseClass, UseValue, UseFactory & UseExisting 

Reference: https://angular.io/

Continue Reading →

Wednesday, 11 January 2023

Improve Performance of Angular app

Improve Performance of Angular app

1: Lazy loading module

The enterprise application built using angular contains many feature modules. All these modules are not required to be loaded at once by the client. With large enterprise applications, the size of the application increases significantly with time, and it also increases the bundle size.

Once the bundle size increases, the performance goes down exponentially because every KB extra on the main bundle contribute to slower:-
  • Download
  • Parsing
  • JS Execution
This can be solved using lazy loading. Lazy Loading is loading only the necessary modules at the initial load. This not only reduces the bundle size but also decreases the load time. Other modules are only loaded when the user navigates to the created routes. This increases the application load time by a great deal.

2: Pure Pipes

In Angular, pipes transform the data to a different format. E.g., the:- 'date | short date converts the date to a shorter format like 'dd/MM/yyyy.' Pipes are divided into two categories:-
  • Impure pipe
  • Pure Pipe
The impure pipe is those pipes that produce different results for the same input over time. The pure pipes are the pipes that produce the same result for the same input. 

3: use AOT compilation

As we know that Angular provides two types of compilation:-
  • JIT(Just-in-time)
  • AoT(Ahead-of-time)
Afterward 8 version, Angular provides the AoT compilation by default, which increases the performance. Because the JIT compiles the application in the runtime. Also, the JIT compilation bundles the compiler with itself, which increases the size of the bundler. Also, it increases the rendering time of the component.

But with the AoT compilation, compiles the application in the build time, produces only the compiled templates, and doesn't include the compiler. So, the bundle size decreases, and rendering time increases significantly. So, We should always use AoT compilation for our applications.

4: Remove Unnecessary Imports and packages from projects.

5: Unsubscribe the Observable after rendering the content Click here to learn how to UnSubscribe

6: Use trackBy option for *ngFor directive 

7: Cache static content using Angular Progressive Web App (PWA)
Caching the static content will make your Angular app load faster as it will already be in the browser. This is easily done using Angular PWA which will use service workers to cache the static content, that is the js, css bundles, images and static served files, and present them without making a call to the server.

8: OnPush change detection
The default change detection behavior for components is to re-render every time an asynchronous event has happened in the app such as click, XMLHttpRequest, setTimout. This can become a problem because this will cause many unnecessary renderings of the templates, that may not have been changed

OnPush change detection fixes this by only re-rendering a template if either:

One of its input properties has gotten a new reference
An event from the component or one of its children eg. click on a button in the component
Explicit run of change detection
To apply this strategy you just need to set the change-detection strategy in the component’s decorator:

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styles: [],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class LoginComponent implements OnInit {

}

9: Preloading Strategies 
There are two types of preloading mechanisms.

Preloading modules — Loading modules asynchronously in the background is called preloading modules. This technique should be used with lazy loading.
@NgModule({
    imports: [RouterModule.forRoot(routes, {preloadingStrategy : PreloadAllModules})],
    exports: [RouterModule],
})
export class AppRoutingModule { }

Preloading in Angular means loading the Lazy loaded Modules in the background asynchronously, while user is interacting with the app. This will help boost up the loading time of the app. 
    By Preloading the lazy loaded module, the user do not have to wait for the module to be downloaded as the module is already downloaded in the background.

Preloading component data —Using resolvers for the routes to block a component from rendering until the data is available.

Continue Reading →

Tuesday, 29 June 2021

ng-template, ng-container and ng-content

 Difference between ng-template, ng-container and ng-content

1: <ng-template></ng-template>

As the name suggests the <ng-template> is a template element that Angular uses with structural directives ( *ngIf , *ngFor , [ngSwitch] and custom directives). These template elements only work in the presence of structural directives, which help us to define a template that doesn’t render anything by itself, but conditionally renders them to the DOM. It helps us create dynamic templates that can be customized and configured.

<div>
   <span *ngIf = "isavailable;then condition1 else condition2">
Condition is valid.
   </span>
   <ng-template #condition1>Condition is valid from template</ng-template>
   <ng-template #condition2>Condition is invalid from template</ng-template>
</div>

Is it possible to use two structural directives together in one single element?

No, if we try to do so, we will get the error “Uncaught Error: Template parse errors: Can’t have multiple template bindings on one element.”

So instead of doing this:

<div *ngIf="details" *ngFor="let info of details">
  {{ info.content }}
</div>

We may need to introduce an additional wrapper component, however, this can be avoided by using ng-container:

2) <ng-container></ng-container>

ng-container is an extremely simple directive that allows you to group elements in a template that doesn’t interfere with styles or layout because Angular doesn’t put it in the DOM

This is helpful if you don’t want any extra div on DOM, you can simply use ng-container. 

<ng-container *ngIf="details">
  <div *ngFor="let info of details">
    {{ info.content }}
  </div>
</ng-container>

The advantage here is that we no longer need any additional wrapper(div) elements.

3) <ng-content></ng-content>

ng-content is used to project content into Angular components. You use the <ng-content></ng-content> tag as a placeholder for that dynamic content, then when the template is parsed Angular will replace that placeholder tag with your content.

<app-child>
  <divChild Component Details </div>
</app-child>

If you check on your browser <div>Child Component Details</div> inside

<app-child></app-child> would not be visible. What if we want to show this content?
So this is where the ng-content directive comes into the picture. What we need to do is, just add “ng-content” inside the component template and it will find the content inside the directive tag and add it to that template at that particular place where we added the “ng-content” tag.


Reference: https://vibhas1892.medium.comhttps://www.educative.io/

Continue Reading →

Topics

ADFS (1) ADO .Net (1) Ajax (1) Angular (47) Angular Js (15) ASP .Net (14) Authentication (4) Azure (3) Breeze.js (1) C# (55) CD (1) CI (2) CloudComputing (2) Coding (10) CQRS (1) CSS (2) Design_Pattern (7) DevOps (4) DI (3) Dotnet (10) DotnetCore (20) Entity Framework (5) ExpressJS (4) Html (4) IIS (1) Javascript (17) Jquery (8) jwtToken (4) Lamda (3) Linq (10) microservice (4) Mongodb (1) MVC (46) NodeJS (8) React (10) SDLC (1) Sql Server (32) SSIS (3) SSO (1) TypeScript (3) UI (1) UnitTest (2) WCF (14) Web Api (16) Web Service (1) XMl (1)

Dotnet Guru Archives