Skip to content
On this page

Angular Interview Q/A

Angular building blocks?

Angular module

ts
@NgModule({
  imports: [BrowserModule, FormsModule],
  declarations: [AppComponent, HelloComponent, PurePipe, ImpurePipe],
  Providers: [AppService]
  bootstrap: [AppComponent]
})
  • A set of relative meta data like - components, directives, modules and pipes etc.
  • Help angular compiler to properly resolve components and attach them to DOM elements into the template.
  • Purpose of ngModule - It helps to organize related things together, like components and directives etc.

Directives

ts
@Directive({
  selector: [appHighlightBackground],
}
export class HighlightBackgroundDirective {
  constructor()
}
  • Directives basically a classes which is decorated @Directive anotation.

  • Directives add additional behavior to the angular elements.

  • There are two types of directives

    • Attribute Directive which can be responsible of changing the behavior of the elements. such as highlighting the background color of the element.

      ts
      template: `<div appHighlightBackground></div>`
      
    • Structural Directive which can be responsible of changing the DOM element adding and removing from the DOM like - *ngIf or *ngfor theese are built in structural directives.

      ts
      template: `<div *ngIf="isVisible">It might be hidden</div>`
      

Components

ts
@Component({
  selector: 'app-hello',
  template: ` <h1>Hello, {{ name }}!</h1> `,
})
export class HelloComponent {
  name = 'Angular'
}
  • Components responsible for rendering the UI and handling user interactions.

  • Data Bindings - sync between the modal (class) and component's template.

  • There is three types of data bindings -

    • Event bindings -

      ts
      @Component({
        selector: 'app-button',
        template: `
          <button (click)="handleClick()">Click me!</button>
        `
      })
      
    • Property bindings -

      ts
      @Component({
        selector: 'app-button',
        template: `<button [disabled]="isDisabled">Click me!</button>`
      })
      
      
    • Interpolation bindings -

      ts
      @Component({
        selector: 'app-hello',
        template: `<h1>Hello, {{ name }}!</h1>`,
      })
      export class HelloComponent {
        name = 'Angular'
      }
      
    • There is another which is two way data bindings - Banana in the box

      ts
      @Component({
      selector: 'app-input',
      template: `
        <input [(ngModel)]="message">
        <p>You typed: {{ message }}</p>
      `
      

Services

ts
@Injectable({
  providedIn: 'root',
})
export class UserService {
  baseUrl = 'https://api/v1/example.com'

  constructor(private http: HttpClient) {}

  getUser() {
    return this.http.get(`${this.baseUrl}/user`)
  }
}

// Injected user service in the constructor of app component
export class AppComponent {
  constructor(private userService: UserService) {}
}

Services are used to share data and functionality across components. They are singleton objects that can be injected into components or other services

Pipes

ts
@Pipe({
  name: 'truncate',
})
export class TruncatePipe implements PipeTransform {
  transform(value: string, length: number = 25): string {
    if (value.length > length) {
      return value.substring(0, length) + '...'
    }
    return value
  }
}

Pipes are used to transform data in the UI. They take in data as input and output transformed data to the UI.

Two modules can we use one inside another module?

ts
@NgModule({
  declarations: [UserComponent],
  imports: [],
})
export class UserModule {}
ts
@NgModule({
  declarations: [ButtonComponent],
  imports: [],
})
export class ButtonModule {}

Let Assume we have two modules can we use one inside another module means can we do it something like this?: 🤔

ts
@NgModule({
  declarations: [ButtonComponent],
  imports: [ButtonModule],
})
export class ButtonModule {}
ts
@component({
  selector: 'app-user',
  template: `<app-button></app-button>`,
  styles: [],
})
export class ButtonModule {}
Solution

It's failed ( template: <app-button></app-button>, ) because by default all the declarations are private and if you want to make this work, you can make it declaration as public using export keyword.

ts
@NgModule({
  declarations: [ButtonComponent],
  imports: [],
  exports: [ButtonComponent],
})
export class ButtonModule {}

Can we have multiple root components?

ts
@NgModule({
  declarations: [],
  imports: [],
  exports: [],
  providers: [],
  bootstrap: [],
})
export class AppModule {}
Solution

Yes we can have multiple root components.

ts
@NgModule({
  declarations: [],
  imports: [],
  exports: [],
  providers: [],
  bootstrap: [AppComponent, UserComponent],
})
export class AppModule {}
html
<body>
  <app-root></app-root>
  <app-user></app-user>
</body>

Can we have multiple root modules?

Solution

Yes we can have multiple root modules.

ts
platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.log(err))

platformBrowserDynamic()
  .bootstrapModule(AnotherModule)
  .catch((err) => console.log(err))

Means that, those independent each other, So every of it has it's own ngZone instance, So change detection circles also independent.

Directives?

Directives are classes which add additional behavior to the DOM elements, components etc.

What types of directives exists?

Answer
  • Attributes Directives: - Those directives change the appearance or behavior of DOM elements, components etc.
  • Structural Directives: - Those directives change DOM layouts and adding or removing elements

Attributes Directives 🔧

Name of some built-in attributes directives?

Answer

NgClass, NgStyle, NgModel, routerLink etc.

Data & event bindings in directives?

Answer

For Event Bindings you can do something like this:

ts
@Directive({
  selector: [appHighlightBackgrond]
}
export class HighlightBackgroudDirective {
  @Input()
  color: ''
}
ts
@Component({
  selector: 'app-root',
  template: `<div appHighlightBackgrond [color]="'red'"></div>`,
  styles: []
}

For Event bindings you can do something like this: when you want to emit someting outside

ts
@Directive({
  selector: [appHighlightBackgrond]
}
export class HighlightBackgroudDirective {
  @Output()
  highlighted = new EventEmitter<void>();

  constructor(){
    this.highlighted.emit();
  }
}
ts
@Component({
  selector: 'app-root',
  template: `<div appHighlightBackgrond (highlighted)="someHandler()"></div>`,
  styles: []
}

Which selectors can we use for directives in angular?

Answer
  • Attribute selector:
ts
@Directive({
  selector: 'appHighlightBackgrond',
})
ts
template: `<appHighlightBackgrond></appHighlightBackgrond>
  • Class selector:
ts
@Directive({
  selector: '.appHighlightBackgrond',
})
ts
template: `<div class="appHighlightBackgrond"></div>
  • Element selector:
ts
@Directive({
  selector: 'input[type=text]',
})

or may be using not input type text.

ts
@Directive({
  selector: ':not(input[type=text])',
})
ts
template: `<input type="text">
  • Multiple selectors:
ts
@Directive({
  selector: 'appHighlightBackgrond, [appHighlightBackgrond]',
})

How to listen for DOM Events when attached to a directive?

Answer

You have to use @HostListeners

ts
@Directive({
  selector: 'appHighlightBackgrond',
})
export class HighlightBackgrondDirective {
  @HostListeners('mouseEnter', ['$event'])
  highlighted(event: Event) {
    // some logic
  }
}

How to get reference to host element?

Answer

You have to access by using dependencies injection.

ts
@Directive({
  selector: 'appHighlightBackgrond',
})
export class HighlightBackgrondDirective {
  constructor(private el: ElementRef)
}

Why direct changing of nativeElement in directive is bad?

ts
@Directive({
  selector: 'appHighlightBackgrond',
})
export class HighlightBackgrondDirective {
  constructor(private el: ElementRef) {
    this.el.nativeElement.style.backgroundColor = '#FFFFFF' //?
  }
}
Answer

Basically it's depends on the browser to browser might be code will not work properly so to solve this problem it's better to use abstraction layer instead using renderer2 service.

ts
@Directive({
  selector: 'appHighlightBackgrond',
})
export class HighlightBackgrondDirective {
  constructor(private el: ElementRef, private renderer: Renderer2) {
    this.renderer.setStyle((this.el, 'backgroudn-color', '#FFFFFF'))
  }
}

Can you query elements in Directives?

Answer

Answer is you can use @ContentChild but can not use @ViewChild

This doesn't work 👇🏻

ts
@Directive({
  selector: 'appHighlightBackgrond, [appHighlightBackgrond]',
})
export class HighlightBackgrondDirective {
  @ViewChild('SomeVariable')
  Private someElement!: ElementRef;
}

This will work 👇🏻

ts
@Directive({
  selector: 'appHighlightBackgrond, [appHighlightBackgrond]',
})
export class HighlightBackgrondDirective {
  @ContentChild('SomeVariable')
  Private someElement!: ElementRef;
}

Note

  • This same is applicable to ViewChildren & ContentChildren.
  • Because directives don't have it's own view hierarchy.

Structural Directives 🪜

Those directives changes the DOMLayouts and adding and removing elements.

Name of some built-in structural directives?

Answer

*ngIf,  *ngFor, *ngSwitch

What is * infront of directives name ?

Answer
ts
@Component({
  selector: 'app-root',
  template: `
  <div *ngIf="true">Hello structural directive</div>
  
  <!-- Is the same as -->
  <ng-template [ngIf]="true">
    <div>Hello structural directive</div>
  </ng-template>
  `,
  styles: []
}

Pipes 🪈

Basically the class responsible for data transformions.

ts
@Pipe({name: 'fileSize'})
export class FileSizePipe implements PipeTransform{
  transform(value: number): number {
    return snakeToCamelCase(value)
  }
}

@Component({
  selector: 'app-root',
  template: `
  <div Current date: {{ currentDate | fileSize }}></div>
  `,
}

Name of some built-in pipes?

Answer

Date, UpperCase, LowerCase, Currency, Percent, Decimal.

Pure Pipe vs Impure Pipe?

Answer

PurePipe → always create a new array or new object so the refrence of the object has been changed and that will treat as pure pipe.

ImppurePipe → They trigger transforms method every time the change detections is happening. and it happens quite frequently.

So the recommended is to use pure pipe because definitely the improved performance.

ts
@Pipe({
  name: 'purePipe',
  pure: true,
})
export class PurePipe implements PipeTransform {
  transform(status: string): string {
    if (status === null || status === undefined) {
      return '';
    }
    return status.toLocaleUpperCase();
  }
}

purePipe vs impurePipe


What is async pipe?

Async pipe is built-in pipe which allows you to subscribe and unsubscribe from your observables

Custom subscribable

ts
class CustomSubscriber implements Subscribable<any>{
  subscribe({next}: any) {
    next("Hi from custom subscribe")
    return {
      unsubscribe: ()=> console.log('unsubscribe!')
    }
  }
}

// Class component
@Component({
  selector: 'app-root',
  template: `
  <div>Observable values: {{ stream | async }}</div>
  <!-- Observable values: Hi from custom subscribe -->
  `,
}
export class AppComponent{
  stream = new CustomSubscriber
}

Component 🆚 Directives?

Component actually is directives behind the scenes when you look at the component in angular code you can see Component extentds with directive only with some extra properties.

Directives: - Use it when you need to change behavior / appearance of some DOM elements and share it accross the apps. Components: - User it when you need to create a view and attach it some behavior or data into the view.

What is DI ?

It is design pattern which claims that classes should request dependencies from external sources rather than creating them.

Which problems does DI resolved ?

DI Resolve tight coupling between classes.

The Problems

ts
class Wheel{}

class Car{
 wheel: Wheel;
 constructor(){
   this.wheel = new Wheel()
 }
}

// another problem
class Wheel{}
class LeatherWheel extends Wheel{}

class Car{
 wheel: Wheel; 
 constructor(){
   this.wheel = new Wheel()
 }
}

The Problems

  • Violates single responsibility
  • Not flexible
  • Hard or impossible to test

The Solution

ts
class Wheel{}
class LeatherWheel extends Wheel{}

class Car{
 wheel: Wheel; 
 constructor(whee: Wheel){
   this.wheel = wheel
 }
}

const car = new Car(new LeatherWheel())

The Solution

  • Car is not responsible for wheel creation
  • We can not easy replace wheel implementation
  • Easy to test

What zone Js ?

It is a library which creates an execution context for angular app and helps detect async events & run CD cycle by monkey-patching native browser APIs

What do you mean by monkey-patching ?

js
const defaultAler = window.alert;

window.alert = function(str){
  console.log('before start called!')
  defaultAler.apply(this, arguments)
  console.log('after start called!')
}

alert('Hey monkey-patching injection!')

Can we disable CD completely for component ?

ts
@Component({
  selector: 'app-root',
  changeDetection: ChangeDetectionStrategy.OnPush
})

constructor(private cd: ChangeDetectorRef){}

detachCD(){
  this.cd.detach()
}
detectChangesManually(){
  this.cd.detectChanges()
}
reattachComponentToCD(){
  this.cd.reattach()
}

Explain runOutsideAngular && why do we need it ?

ts
constructor(private ngZone: NgZone){}

ngOnInit() {
  this.ngZone.runOutsideAngular(()=> {
    setInterval(()=> {
      console.log('This code does not trigger change detection!')
    }, 1000)
  })
}

RxJs ?

What is operator in RxJs?

It is an pure function which creates a new observable based on the previous one.

ts
import {of} from 'rxjs'

const obs$ = of('hello') // creation operators
const stream$ = obs$.subscribe({
  next: (res)=> console.log(res),
  error: ()=> console.log(error),
  complete:()=> console.log('completed!')
})

How many types of operator in RxJs?

Two types of operators - pipeable operators & creation operators

pipeable operators

ts
// begin lesson code
import { of } from 'rxjs';
// pipeable operators are imported from rxjs/operators
import { map, filter } from 'rxjs/operators';

/*
 * Pipeable operators generally accept some config, returning
 * a function with takes the source observable. So one way to use would
 * be like below...
 */
map((value: any) => value + 10)(of(1, 2, 3, 4, 5)).subscribe(console.log);

/*
 * This is already pretty ugly though, imagine using multiple operators...
 */
filter((value: any) => value === 15)(
  map((value: any) => value + 10)(of(1, 2, 3, 4, 5))
).subscribe(console.log);

/*
 * The pipe method handles this for us, invoking the next operator
 * with the observable returned from the previous. This lets use much more
 * easily visualize the flow of data through our observables.
 * On subscription, each operator subscribes to it's source (observable),
 * then data flows downward through each operator until it reaches
 * your registered observer.
 */
of(1, 2, 3, 4, 5)
  .pipe(
    map((value) => value + 10),
    filter((value) => value === 15)
  )
  .subscribe(console.log);

What is subject ?

It is an special type of Observable which is combination of Observer and Observable and multicasts it's execution between subscriber

ts
import { interval, Subject, tap } from 'rxjs';

const subject$ = new Subject();

const observer = {
  next: (val) => console.log('next', val),
  error: (err) => console.log('err', err),
  complete: () => console.log('complete'),
};

const subscription = subject$.subscribe(observer);

subject$.next('Hey!'); // next Hey!

const interval$ = interval(2000).pipe(
  tap((val) => console.log('newValue', val))
);

interval$.subscribe(subject$);

// new interval
// 0
// next
// 0
// next
// 0

/*
subject is basically multicast the value and observer listen the value
*/

The Solution

  • subject is basically multicast the value and observer listen the value

Subject vs Behavior Subject ?

In programming, a "subject" typically refers to an object or entity that can be observed or subscribed to, while "behavior subject" specifically refers to a type of subject that remembers the last value it emitted. It is commonly used in reactive programming or event-driven architectures.

Subject -

ts
// Creating a Subject
const subject = new Subject();

// Subscribing to the subject
subject.subscribe(value => {
  console.log("Received value from subject:", value);
});

// Emitting a value from the subject
subject.next("Hello!");

// Output: Received value from subject: Hello!

When we call subject.next("Hello!"), the subject emits the value "Hello!" and any subscribed observers receive and process it.

Note

  • So, on the subject if you try to emit before the subscription you will get nothing and all the subscription get skipped, so you need emit after the subscription then only you will get the value.
ts
subject.next("Hello!");
subject.subscribe(value => {
  console.log("Received value from subject:", value);
});
subject.subscribe(value => {
  console.log("Received value from subject:", value);
});
// output - nothing and these subscriptions get skipped.

Behaviour Subject - BehaviorSubject" is a type of subject that has an initial value and remembers the last value it emitted. It also provides an extra method called getValue() that returns the last emitted value. Here's an example using BehaviorSubject:

ts
// Creating a BehaviorSubject
const behaviorSubject = new BehaviorSubject("Initial value");

// Subscribing to the behavior subject
behaviorSubject.subscribe(value => {
  console.log("Received value from behavior subject:", value);
});

// Emitting a value from the behavior subject
behaviorSubject.next("Hello!");

// Output: Received value from behavior subject: Initial value
// Output: Received value from behavior subject: Hello!

// Getting the last emitted value
const lastValue = behaviorSubject.getValue();
console.log("Last value:", lastValue);

// Output: Last value: Hello!

Note

  • So, to summarize, a subject is a general concept for an observable entity, while a behavior subject is a specific type of subject that remembers the last emitted value and provides the getValue() method to retrieve it.

ReplaySubject ?

ReplaySubject is another type of subject that remembers multiple values it emitted in the past. When a new observer subscribes to a ReplaySubject, it receives a specified number of previously emitted values.

ts
// Creating a ReplaySubject with a buffer size of 2
const replaySubject = new ReplaySubject(2);

// Emitting values to the replay subject
replaySubject.next("Value 1");
replaySubject.next("Value 2");
replaySubject.next("Value 3");

// Subscribing to the replay subject
replaySubject.subscribe(value => {
  console.log("Received value from replay subject:", value);
});

// Output: Received value from replay subject: Value 2
// Output: Received value from replay subject: Value 3

In this example, we create a ReplaySubject with a buffer size of 2, which means it will remember the last two emitted values. We then emit three values using replaySubject.next().

When we subscribe to the replaySubject, it immediately emits the buffered values to the new observer. In this case, the observer receives "Value 2" and "Value 3", which were the last two emitted values.

Note

  • ReplaySubject is useful when you want new subscribers to have access to a history of values emitted by the subject.

AsyncSubject ?

AsyncSubject is a type of subject that only emits the last value it received and does so only when the subject completes. It is commonly used in scenarios where you only need the final value of an asynchronous operation.

ts
// Creating an AsyncSubject
const asyncSubject = new AsyncSubject();

// Subscribing to the AsyncSubject
asyncSubject.subscribe(value => {
  console.log("Received value from AsyncSubject:", value);
});

// Emitting values to the AsyncSubject
asyncSubject.next("Value 1");
asyncSubject.next("Value 2");

// Completing the AsyncSubject
asyncSubject.complete();

// Output: Received value from AsyncSubject: Value 2

We call asyncSubject.next("Value 1") and asyncSubject.next("Value 2") to emit two values to the subject. However, the subscribers do not receive any values at this point.

Finally, we complete the AsyncSubject by calling asyncSubject.complete(). This triggers the subject to emit its last received value, which is "Value 2" in this case. The subscribers then receive this value.

Note

  • Note that AsyncSubject emits only the last value and only when it completes. If the subject completes without emitting any value, subscribers will not receive any value.

Rohit ❤️