Common places and scenarios where new keyword is used in Angular projects

 In Angular, the new keyword is used to create instances of classes. While Angular primarily relies on Dependency Injection (DI) for services and components, you may explicitly use new in specific scenarios. Below is a categorized list of common use cases:

Common Use of new in Angular

Where it's usedExampleExplanation
  • Creating a class instance
  • let person = new Person();
  • Standard JavaScript usage in services or components
  • Creating Dates
  • let now = new Date();
  • Frequently used in date pickers or logging
  • Creating FormGroups
  • new FormGroup({...})
  • Reactive Forms: defining a new form group
  • Creating FormControls
  • new FormControl('value')
  • Reactive Forms: defining individual form controls
  • Custom Error Classes
  • throw new CustomError('Something went wrong');
  • Angular apps often define custom error classes
  • HttpHeaders or HttpParams
  • new HttpHeaders().set('Authorization', 'Bearer')
  • Used to configure HTTP requests
  • Creating Observables
  • new Observable(observer => {...})
  • Sometimes used to create custom observables
  • Using new in RxJS operators
  • new Subject() or new BehaviorSubject()
  • Common in services or state management
  • Dependency Injection (rare)
  • new SomeService() (not recommended)
  • Not recommended; use Angular DI instead

๐Ÿ”ธ Angular-Specific Classes Often Instantiated with new

These are common classes you might instantiate with new:

  • FormControl

  • FormGroup

  • FormArray

  • HttpHeaders

  • HttpParams

  • DatePipe, CurrencyPipe, etc. (though usually injected, sometimes instantiated manually)

  • BehaviorSubject, Subject, ReplaySubject (from RxJS)

  • Custom model classes (e.g., new UserModel())

  • Custom error classes


✅  Common Angular Classes You Instantiate with new

These are safe and common classes that you can instantiate with new in your Angular application:

๐Ÿ”น Frequently Used with new

๐Ÿ“ฆ Forms (@angular/forms)

  • FormControl

  • FormGroup

  • FormArray


const name = new FormControl('John'); const form = new FormGroup({ name: name });

๐ŸŒ HTTP (@angular/common/http)

  • HttpHeaders

  • HttpParams


const headers = new HttpHeaders().set('Authorization', 'Bearer token');

๐Ÿ“Š RxJS

  • Subject

  • BehaviorSubject

  • ReplaySubject


const subject = new BehaviorSubject<number>(0);

๐Ÿ“† Date & Utilities

  • Date

  • Custom class instances


const date = new Date(); const user = new UserModel();

❗ Error Classes

  • HttpErrorResponse (sometimes)

  • Custom error classes

  • -n shows line numbers

  • -w matches the whole word

 Internal Usages (some examples)

Module/AreaUsed with newPurpose
  • @angular/forms
  • new FormControl(), new FormGroup()
  • Used in reactive forms
  • @angular/common/http
  • new HttpHeaders(), new HttpParams()
  • Used to configure HTTP requests
  • @angular/core/testing
  • new TestBed() (indirectly)
  • Internally during unit testing

  • RxJS (used in Angular)
  • new Subject(), new BehaviorSubject()
  • Angular uses these for observable patterns

Final web.config for Angular on IIS (with redirect on double slashes)

 <?xml version="1.0" encoding="utf-8"?>

<configuration>

  <system.webServer>

    <rewrite>

      <rules>

        <!-- Redirect if path starts with double slashes -->

        <rule name="RedirectLeadingDoubleSlashes" stopProcessing="true">

          <match url="^(//+)(.*)" />

          <conditions>

            <!-- Skip redirect if Radware WAF handled it -->

            <add input="{HTTP_X_RADWARE_WAF}" pattern=".*" negate="true" />

          </conditions>

          <action type="Redirect" url="https://{HTTP_HOST}/{R:2}" redirectType="Permanent" />

        </rule>


        <!-- Angular rewrite fallback for all other routes -->

        <rule name="Angular Routes" stopProcessing="true">

          <match url=".*" />

          <conditions logicalGrouping="MatchAll">

            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />

            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

          </conditions>

          <action type="Rewrite" url="/index.html" />

        </rule>

      </rules>

    </rewrite>

    <staticContent>

      <mimeMap fileExtension=".json" mimeType="application/json" />

    </staticContent>

  </system.webServer>

</configuration>


Steps:

Open IIS Manager.


Select your website.


Click on Logging.


Click "Select Fields...".


Click Add Field:


Field Name: X-Radware-WAF


Source Type: Request Header


Source: X-Radware-WAF


Save and apply


 3 Ways to Check if the Header Reaches IIS


๐Ÿ” Option 1: Use Browser DevTools (Simple Check)

  1. Open your Angular app publicly (through the WAF).

  2. Press F12 → Open Network tab.

  3. Refresh the page.

  4. Click the first request (should be https://anchor.com/).

  5. Look under Request Headers (not Response Headers).

  6. See if X-Radware-WAF is listed.

✅ If it’s there → WAF is forwarding the header.


๐Ÿงช Option 2: Use curl to Simulate Traffic

1. Test via public URL (goes through WAF):

bash

curl -I https://anchor.com////about

Then test the same with a header to simulate WAF:

bash

curl -I https://anchor.com////about -H "X-Radware-WAF: active"

Observe:

  • If the header affects redirect behavior, then your web.config is working and the header is being respected by IIS.


๐Ÿ“‚ Option 3: Log the Header in IIS Logs

Step-by-Step:

  1. Open IIS Manager.

  2. Select your site.

  3. In Features View, open Logging.

  4. On the right → click "Select Fields..."

  5. Click "Add Field":

    • Field Name: X-Radware-WAF

    • Source Type: Request Header

    • Source: X-Radware-WAF

  6. Click OK, Apply.

Now:

  • Make a request through the WAF.

  • Go to the IIS logs folder:
    C:\inetpub\logs\LogFiles\W3SVC<your-site-id>\

  • Open the latest log file.

  • See if X-Radware-WAF shows a value.

✅ If you see the header in the logs, WAF is forwarding it.


❌ If the Header is NOT Reaching IIS

If none of the methods show X-Radware-WAF, then:

๐Ÿ”’ Radware WAF is probably:

  • Normalizing the request (removing bad slashes)

  • But not sending a custom header to IIS


✅ Solution: Add a Custom Header in Radware

Ask your security/WAF admin to add a rule in Radware AppWall or Cloud WAF to:

"Inject a custom header (e.g. X-Radware-WAF: true) into all incoming requests after WAF inspection."

This is usually done in:

  • AppWall GUI → Security Policies → Header Injection

  • Or via a custom rule in Radware WAF configuration

Once that's added, IIS will receive the header and your rule will behave properly.


✅ TL;DR — What You Should Do

TaskHow-To
Check if header is passedUse browser DevTools or curl
Log it in IISAdd a custom field in IIS Logging
Header missing?Ask WAF team to inject X-Radware-WAF: true after inspection



<configuration>
  <system.webServer>
    <rewrite>
      <rules>

        <!-- Rule 1: Normalize multiple slashes -->
        <rule name="Remove Double Slashes" stopProcessing="true">
          <match url="(.*//.*)" />
          <conditions>
            <add input="{REQUEST_URI}" pattern="(.*//.*)" />
          </conditions>
          <action type="Redirect" url="{R:1}" redirectType="Permanent" />
        </rule>

        <!-- Rule 2: Angular fallback routing -->
        <rule name="Angular Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>

      </rules>
    </rewrite>
    <staticContent>
      <mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
    </staticContent>
  </system.webServer>
</configuration>


<rule name="Remove Double Slashes" stopProcessing="true">
  <match url="(.*//.*)" />
  <conditions>
    <add input="{REQUEST_URI}" pattern="(.*//.*)" />
  </conditions>
  <action type="Redirect" url="{R:1}" redirectType="Permanent" />
</rule>


IIS servers exposed to public networks for 301 Moved Permanently

 <rule name="PublicNetworkSlashNormalization" stopProcessing="true">

  <match url=".*" />

  <conditions logicalGrouping="MatchAny">

    

    <!-- Detect raw double slashes in direct requests -->

    <add input="{UNENCODED_URL}" pattern="//" />


    <!-- Detect double slashes in proxy-passed headers -->

    <!-- Azure App Gateway / IIS ARR -->

    <add input="{HTTP_X_ORIGINAL_URL}" pattern="//" />

    

    <!-- NGINX or custom reverse proxies -->

    <add input="{HTTP_X_ORIGINAL_URI}" pattern="//" />


    <!-- Other common proxy headers -->

    <add input="{HTTP_X_REWRITE_URL}" pattern="//" />

    

  </conditions>


  <!-- Canonical redirect with lowercase domain and cleaned path -->

  <action type="Redirect" 

          url="https://{ToLower:{HTTP_HOST}}{UNENCODED_URL}" 

          redirectType="Permanent" 

          appendQueryString="true" />

</rule>



ChangeWhy it was made
HTTP_X_ORIGINAL_URLUsed by IIS ARR and Azure App Gateway
HTTP_X_ORIGINAL_URIUsed by NGINX and some custom reverse proxies
HTTP_X_REWRITE_URLUsed by IIS URL Rewrite module itself when rewriting
ToLower:{HTTP_HOST}Forces lowercase domain (for SEO, canonical URLs)
appendQueryString="true"Preserves query string parameters (safer for real URLs)

Advanced Angular Methods & Real-World Scenarios

 

1. ViewChild / ViewChildren

Purpose: Access DOM elements or child components programmatically.
Scenario: Video player controls in a media dashboard.

typescript
@Component({
  template: `
    <video #player></video>
    <button (click)="toggleFullscreen()">Fullscreen</button>
  `
})
export class VideoPlayerComponent implements AfterViewInit {
  @ViewChild('player', { static: false }) video!: ElementRef<HTMLVideoElement>;
  
  ngAfterViewInit() {
    this.video.nativeElement.addEventListener('timeupdate', this.handleProgress);
  }

  toggleFullscreen() {
    if (this.video.nativeElement.requestFullscreen) {
      this.video.nativeElement.requestFullscreen();
    }
  }
}

Key Use:

  • Direct DOM manipulation when 3rd party libraries require native elements

  • Accessing component APIs (e.g., playerComponent.play())


2. ContentChild / ContentChildren

Purpose: Project content manipulation (ng-content).
Scenario: Tab system with dynamic headers.

typescript
@Component({
  selector: 'app-tab',
  template: `<ng-content></ng-content>`
})
export class TabComponent {
  @ContentChild(TabHeaderComponent) header!: TabHeaderComponent;
}

@Component({
  template: `
    <app-tab>
      <app-tab-header #header></app-tab-header>
      <div>Tab Content</div>
    </app-tab>
  `
})
export class TabGroupComponent {
  @ViewChild(TabComponent) tab!: TabComponent;
  
  ngAfterViewInit() {
    console.log(this.tab.header); // Access projected header
  }
}

Key Use:

  • Creating component libraries with flexible content projection

  • Accessing projected components' APIs


3. @HostBinding & @HostListener

Purpose: Dynamic host element manipulation.
Scenario: Theme switcher directive.

typescript
@Directive({ selector: '[appTheme]' })
export class ThemeDirective {
  @HostBinding('class.dark-theme') isDark = false;
  @HostBinding('attr.data-theme') themeName = 'light';

  @HostListener('document:theme-change', ['$event'])
  onThemeChange(e: CustomEvent) {
    this.isDark = e.detail.dark;
    this.themeName = e.detail.name;
  }
}

Key Use:

  • Creating attribute-driven UI components

  • Responding to global events without service injection


4. Renderer2

Purpose: Safe DOM manipulation.
Scenario: Dynamic SVG chart rendering.

typescript
@Component({
  selector: 'app-chart',
  template: `<div #chartContainer></div>`
})
export class ChartComponent implements OnInit {
  @ViewChild('chartContainer', { static: true }) container!: ElementRef;

  constructor(private renderer: Renderer2) {}

  ngOnInit() {
    const svg = this.renderer.createElement('svg', 'http://www.w3.org/2000/svg');
    this.renderer.setAttribute(svg, 'width', '100%');
    this.renderer.appendChild(this.container.nativeElement, svg);
    
    // Add path element
    const path = this.renderer.createElement('path', 'http://www.w3.org/2000/svg');
    this.renderer.setAttribute(path, 'd', 'M10 10 H 90 V 90 H 10 Z');
    this.renderer.appendChild(svg, path);
  }
}

Key Use:

  • Server-side rendering (SSR) compatibility

  • Working in environments without direct DOM access


5. ChangeDetectorRef

Purpose: Manual change detection control.
Scenario: Integrating non-Angular visualization libraries.

typescript
@Component({
  template: `<div #d3Chart></div>`
})
export class D3WrapperComponent implements OnDestroy {
  @ViewChild('d3Chart') container!: ElementRef;
  private chart: any;

  constructor(private cdr: ChangeDetectorRef) {}

  ngOnInit() {
    this.chart = new ThirdPartyChart(this.container.nativeElement);
    this.chart.on('update', () => {
      // Manually trigger CD when library updates data
      this.cdr.detectChanges();
    });
  }

  ngOnDestroy() {
    this.chart.destroy();
  }
}

Key Use:

  • Optimizing performance with external JS libraries

  • OnPush components with async external events


6. NgZone

Purpose: Control Angular's execution context.
Scenario: High-frequency WebSocket data stream.

typescript
@Component({...})
export class CryptoPriceComponent {
  prices: any[] = [];

  constructor(private zone: NgZone) {
    const socket = new WebSocket('wss://crypto-stream.com');
    
    socket.onmessage = (event) => {
      // Run outside Angular to avoid excessive CD
      this.zone.runOutsideAngular(() => {
        this.processData(JSON.parse(event.data));
      });
    };
  }

  processData(data: any) {
    // Heavy data processing
    const filtered = this.filterPrices(data);
    
    // Re-enter Angular zone for UI update
    this.zone.run(() => {
      this.prices = filtered;
    });
  }
}

Key Use:

  • Optimizing performance for real-time data streams

  • Integrating non-Angular event systems


7. ViewContainerRef

Purpose: Dynamic component rendering.
Scenario: Plugin-based dashboard system.

typescript
@Component({
  template: `<ng-template #pluginHost></ng-template>`
})
export class DashboardComponent implements AfterViewInit {
  @ViewChild('pluginHost', { read: ViewContainerRef }) host!: ViewContainerRef;

  constructor(private injector: Injector) {}

  async loadPlugin(pluginId: string) {
    const { PluginComponent } = await import(`./plugins/${pluginId}.ts`);
    this.host.clear();
    const componentRef = this.host.createComponent(PluginComponent, {
      injector: this.createPluginInjector(pluginId)
    });
    componentRef.instance.config = this.getPluginConfig(pluginId);
  }

  private createPluginInjector(pluginId: string) {
    return Injector.create({
      providers: [{ provide: PLUGIN_TOKEN, useValue: pluginId }],
      parent: this.injector
    });
  }
}

Key Use:

  • Micro-frontend architectures

  • Dynamic module federation


8. Custom Pipes with Memoization

Purpose: Optimized data transformation.
Scenario: Large dataset filtering.

typescript
@Pipe({ name: 'advancedFilter', pure: true })
export class AdvancedFilterPipe implements PipeTransform {
  private cache = new Map<string, any>();

  transform(items: any[], filters: FilterOptions): any[] {
    const cacheKey = JSON.stringify(filters);
    
    if (this.cache.has(cacheKey)) {
      return this.cache.get(cacheKey);
    }

    const result = items.filter(item => {
      return Object.keys(filters).every(key => 
        item[key].includes(filters[key])
      );
    });

    this.cache.set(cacheKey, result);
    return result;
  }
}

Key Use:

  • Preventing recalculations in large lists

  • Complex filtering with multiple parameters


Advanced Scenario: Enterprise Admin Dashboard

Challenge:

  • 50+ dynamic widgets

  • Real-time data updates

  • Role-based access control

  • Cross-widget communication

Solution Architecture:

typescript
// 1. Widget Container (Dynamic Loading)
<ng-container *ngFor="let widget of widgets">
  <ng-template [appWidgetHost]="widget.type"></ng-template>
</ng-container>

// 2. Custom Directive for Dynamic Loading
@Directive({ selector: '[appWidgetHost]' })
export class WidgetDirective implements OnChanges {
  @Input() widgetType!: string;
  
  constructor(public vcr: ViewContainerRef) {}

  ngOnChanges() {
    this.loadWidget();
  }

  private async loadWidget() {
    const { component } = await this.widgetLoader.load(this.widgetType);
    this.vcr.createComponent(component);
  }
}

// 3. State Management with NgRx
this.store.dispatch(loadDashboard({ user }));

// 4. Real-time Updates
merge(
  this.dataService.liveUpdates$,
  this.refreshTrigger$
).pipe(
  throttleTime(300),
  switchMap(() => this.fetchData())
).subscribe(data => {
  this.zone.runOutsideAngular(() => this.processData(data));
});

// 5. Security Directive
<finance-widget *appHasRole="'FINANCE_ADMIN'"></finance-widget>

Key Methods Used:

  • ViewContainerRef.createComponent() for dynamic widgets

  • NgZone.runOutsideAngular() for data processing

  • Custom HasRoleDirective with TemplateRef

  • NgRx selectors with memoized dashboard state

  • RxJS operators for real-time optimization


Pro Interview Tips:

  1. Contextualize Answers:
    "We used Renderer2 instead of native DOM methods because our app required SSR support for SEO optimization."

  2. Compare Alternatives:
    "I chose ViewContainerRef over deprecated ComponentFactoryResolver for future-proofing our dynamic module loader."

  3. Performance Metrics:
    "Implementing ChangeDetectorRef.detach() for our grid component reduced CPU usage by 40% during scrolling."

  4. Error Handling:
    "We wrap ViewContainerRef.createComponent() with try/catch to handle missing widget modules gracefully."

  5. Evolution Patterns:
    *"Initially we used pure pipes for filtering, but migrated to memoized selectors when dealing with 10k+ records.

starter ASP.NET Core Web API project with example

Starter ASP.NET Core Web API project that follows all the best practices listed above. ๐Ÿ› ️ Starter Project Overview We’ll build a Produc...

Best for you