Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungKI half beim Finden: iOS 27 schließt mehr als 100 Sicherheitslücken(21.09.2026 um 06:00 Uhr)
Sichere ProgrammierungWhat Is Rowhammer? How Can Repeated Memory Access Flip Bits in RAM?(21.09.2026 um 07:12 Uhr)
Sichere Programmierungnpm publish Ignores .gitignore: The .npmignore Override Rule(21.09.2026 um 07:15 Uhr)
Sichere ProgrammierungAphelion Editor - A free node-based video / VFX editor(21.09.2026 um 07:21 Uhr)
Sichere ProgrammierungGovernance Attack Surface Review: OKX(21.09.2026 um 07:31 Uhr)
Sichere ProgrammierungJSM Portal Request Create Property Panel Submit(21.09.2026 um 07:34 Uhr)
Reverse Engineeringsearch instructions assembly easy (X86,RISCV,AARCH64,etc)(20.09.2026 um 15:44 Uhr)
Sichere ProgrammierungKI half beim Finden: iOS 27 schließt mehr als 100 Sicherheitslücken(21.09.2026 um 06:00 Uhr)
Sichere ProgrammierungWhat Is Rowhammer? How Can Repeated Memory Access Flip Bits in RAM?(21.09.2026 um 07:12 Uhr)
Sichere Programmierungnpm publish Ignores .gitignore: The .npmignore Override Rule(21.09.2026 um 07:15 Uhr)
Sichere ProgrammierungAphelion Editor - A free node-based video / VFX editor(21.09.2026 um 07:21 Uhr)
Sichere ProgrammierungGovernance Attack Surface Review: OKX(21.09.2026 um 07:31 Uhr)
Sichere ProgrammierungJSM Portal Request Create Property Panel Submit(21.09.2026 um 07:34 Uhr)
Reverse Engineeringsearch instructions assembly easy (X86,RISCV,AARCH64,etc)(20.09.2026 um 15:44 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

RxJS in Angular — Chapter 8 | RxJS + Angular Reactive Forms — Live Validation ও Dynamic Forms

Reagiere als Erste:r — dein Feedback zählt!

"RxJS + Angular Reactive Forms — Live Validation & Dynamic Forms"

👋 Welcome to Chapter 8!

Forms are EVERYWHERE in web apps — login, registration, checkout, search, settings.

Angular's Reactive Forms are powered by RxJS under the hood. Every FormControl has streams you can subscribe to — valueChanges, statusChanges. This unlocks incredibly powerful form behavior that would be painfully difficult to build any other way.

Today we build real, production-quality forms with RxJS superpowers!

🎛️ The Reactive Forms Quick Setup

First, let's make sure we have the right setup:

app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [ReactiveFormsModule]
})
export class AppModule {}

💡 The Key Streams on Every FormControl

Every FormControl, FormGroup, and FormArray has two key Observable streams:

valueChanges — emits every time the value changes
statusChanges — emits every time the validation status changes ('VALID', 'INVALID', 'PENDING', 'DISABLED')

const emailControl = new FormControl('');

// Watch the value
emailControl.valueChanges.subscribe(value => {
  console.log('Email is now:', value);
});

// Watch the validation status
emailControl.statusChanges.subscribe(status => {
  console.log('Status:', status); // 'VALID', 'INVALID', 'PENDING', 'DISABLED'
});

🔍 Real Example 1 — Live Username Availability Check

This is extremely common: as the user types a username, check if it's available.

// register.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormBuilder, FormGroup, Validators, AbstractControl } from '@angular/forms';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-register',
  template: `
    <form [formGroup]="registerForm" (ngSubmit)="onSubmit()">

      <div class="field">
        <label>Username</label>
        <input formControlName="username" placeholder="Choose a username" />

        <!-- Checking availability -->
        <span *ngIf="isCheckingUsername" class="checking">
          Checking availability... ⏳
        </span>

        <!-- Available -->
        <span *ngIf="usernameAvailable === true" class="available">
          ✅ Username is available!
        </span>

        <!-- Taken -->
        <span *ngIf="usernameAvailable === false" class="taken">
          ❌ Username is already taken
        </span>

        <!-- Validation errors -->
        <span *ngIf="registerForm.get('username')?.errors?.['required'] &&
                     registerForm.get('username')?.touched">
          Username is required
        </span>
        <span *ngIf="registerForm.get('username')?.errors?.['minlength']">
          At least 3 characters required
        </span>
      </div>

      <div class="field">
        <label>Email</label>
        <input formControlName="email" type="email" placeholder="Enter email" />
        <span *ngIf="registerForm.get('email')?.errors?.['email'] &&
                     registerForm.get('email')?.touched">
          Invalid email address
        </span>
      </div>

      <div class="field">
        <label>Password</label>
        <input formControlName="password" type="password" placeholder="Password" />
        <div class="password-strength" [class]="passwordStrength">
          {{ passwordStrengthLabel }}
        </div>
      </div>

      <div class="field">
        <label>Confirm Password</label>
        <input formControlName="confirmPassword" type="password" />
        <span *ngIf="registerForm.errors?.['passwordMismatch'] &&
                     registerForm.get('confirmPassword')?.touched">
          Passwords do not match
        </span>
      </div>

      <button type="submit" [disabled]="registerForm.invalid || isCheckingUsername">
        Create Account
      </button>

    </form>
  `
})
export class RegisterComponent implements OnInit, OnDestroy {

  registerForm!: FormGroup;
  isCheckingUsername = false;
  usernameAvailable: boolean | null = null;
  passwordStrength = 'weak';
  passwordStrengthLabel = '';

  private destroy$ = new Subject<void>();

  constructor(
    private fb: FormBuilder,
    private authService: AuthService
  ) {}

  ngOnInit(): void {
    this.registerForm = this.fb.group({
      username: ['', [Validators.required, Validators.minLength(3)]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required, Validators.minLength(8)]],
      confirmPassword: ['', Validators.required]
    }, {
      validators: this.passwordMatchValidator
    });

    // --- RxJS Magic: Username availability check ---
    this.registerForm.get('username')!.valueChanges
      .pipe(
        debounceTime(500),                   // Wait 500ms after typing
        distinctUntilChanged(),              // Don't check if same value
        takeUntil(this.destroy$)
      )
      .subscribe(username => {
        if (username && username.length >= 3) {
          this.isCheckingUsername = true;
          this.usernameAvailable = null;

          this.authService.checkUsername(username)
            .pipe(takeUntil(this.destroy$))
            .subscribe({
              next: (isAvailable) => {
                this.usernameAvailable = isAvailable;
                this.isCheckingUsername = false;
              },
              error: () => {
                this.isCheckingUsername = false;
              }
            });
        } else {
          this.usernameAvailable = null;
        }
      });

    // --- RxJS Magic: Password strength meter ---
    this.registerForm.get('password')!.valueChanges
      .pipe(takeUntil(this.destroy$))
      .subscribe(password => {
        this.updatePasswordStrength(password || '');
      });
  }

  private updatePasswordStrength(password: string): void {
    let score = 0;
    if (password.length >= 8) score++;
    if (/[A-Z]/.test(password)) score++;
    if (/[0-9]/.test(password)) score++;
    if (/[^A-Za-z0-9]/.test(password)) score++;

    if (score <= 1) {
      this.passwordStrength = 'weak';
      this.passwordStrengthLabel = '🔴 Weak';
    } else if (score === 2) {
      this.passwordStrength = 'fair';
      this.passwordStrengthLabel = '🟡 Fair';
    } else if (score === 3) {
      this.passwordStrength = 'good';
      this.passwordStrengthLabel = '🟢 Good';
    } else {
      this.passwordStrength = 'strong';
      this.passwordStrengthLabel = '💪 Strong';
    }
  }

  private passwordMatchValidator(group: AbstractControl) {
    const password = group.get('password')?.value;
    const confirm = group.get('confirmPassword')?.value;
    return password === confirm ? null : { passwordMismatch: true };
  }

  onSubmit(): void {
    if (this.registerForm.valid && this.usernameAvailable) {
      console.log('Register:', this.registerForm.value);
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

🏙️ Real Example 2 — Dependent Dropdowns (Country → City)

When selecting a country should dynamically load cities for that country:

@Component({
  template: `
    <form [formGroup]="addressForm">

      <select formControlName="country">
        <option value="">Select Country</option>
        <option *ngFor="let c of countries" [value]="c.code">
          {{ c.name }}
        </option>
      </select>

      <select formControlName="city">
        <option value="">
          {{ isLoadingCities ? 'Loading cities...' : 'Select City' }}
        </option>
        <option *ngFor="let city of cities" [value]="city.id">
          {{ city.name }}
        </option>
      </select>

    </form>
  `
})
export class AddressFormComponent implements OnInit, OnDestroy {

  addressForm = this.fb.group({
    country: [''],
    city: [{ value: '', disabled: true }]
  });

  countries = [
    { code: 'BD', name: 'Bangladesh' },
    { code: 'IN', name: 'India' },
    { code: 'US', name: 'USA' }
  ];

  cities: any[] = [];
  isLoadingCities = false;

  private destroy$ = new Subject<void>();

  constructor(
    private fb: FormBuilder,
    private locationService: LocationService
  ) {}

  ngOnInit(): void {

    // When country changes — load its cities
    this.addressForm.get('country')!.valueChanges
      .pipe(
        takeUntil(this.destroy$),
        tap(() => {
          // Reset city when country changes
          this.cities = [];
          this.addressForm.get('city')!.disable();
          this.addressForm.get('city')!.setValue('');
          this.isLoadingCities = true;
        }),
        switchMap(countryCode => {
          if (!countryCode) return of([]);
          return this.locationService.getCitiesByCountry(countryCode)
            .pipe(catchError(() => of([])));
        })
      )
      .subscribe(cities => {
        this.cities = cities;
        this.isLoadingCities = false;
        if (cities.length > 0) {
          this.addressForm.get('city')!.enable();
        }
      });
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

When the country changes, the city dropdown automatically:

  1. Resets to empty
  2. Shows "Loading cities..."
  3. Disables itself
  4. Loads new cities from API
  5. Re-enables with new options

All powered by valueChanges + switchMap!

💰 Real Example 3 — Live Price Calculator

A checkout form where the price updates as you change quantity and select options:

@Component({
  template: `
    <form [formGroup]="orderForm">
      <label>Quantity</label>
      <input type="number" formControlName="quantity" min="1">

      <label>Size</label>
      <select formControlName="size">
        <option value="small">Small</option>
        <option value="medium">Medium (+৳200)</option>
        <option value="large">Large (+৳400)</option>
      </select>

      <label>
        <input type="checkbox" formControlName="giftWrap">
        Gift Wrap (+৳50)
      </label>

      <div class="price-summary">
        <p>Base price: ৳{{ basePrice }}</p>
        <p>Total: <strong>৳{{ liveTotal$ | async }}</strong></p>
      </div>
    </form>
  `
})
export class OrderFormComponent implements OnInit {

  basePrice = 500;

  orderForm = this.fb.group({
    quantity: [1],
    size: ['small'],
    giftWrap: [false]
  });

  liveTotal$!: Observable<number>;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    const sizeAddon: Record<string, number> = {
      small: 0,
      medium: 200,
      large: 400
    };

    // Calculate total every time ANY field changes
    this.liveTotal$ = this.orderForm.valueChanges.pipe(
      startWith(this.orderForm.value),
      map(values => {
        const qty = values.quantity || 1;
        const sizeExtra = sizeAddon[values.size] || 0;
        const giftExtra = values.giftWrap ? 50 : 0;
        return (this.basePrice + sizeExtra + giftExtra) * qty;
      })
    );
  }
}

The total updates instantly as the user changes any field — no button, no event handlers, just pure reactive magic!

🔧 Using statusChanges for Async Validators

ngOnInit(): void {
  // React to form validity changes
  this.registerForm.statusChanges
    .pipe(
      distinctUntilChanged(),
      takeUntil(this.destroy$)
    )
    .subscribe(status => {
      // 'VALID', 'INVALID', 'PENDING', 'DISABLED'
      if (status === 'VALID') {
        this.canSubmit = true;
        this.showSuccessHint = true;
      } else {
        this.canSubmit = false;
        this.showSuccessHint = false;
      }
    });
}

🧠 Chapter 8 Summary — What You Learned

  • FormControl.valueChanges is an Observable — you can use all RxJS operators on it
  • FormControl.statusChanges tells you when validity changes
  • Use debounceTime + switchMap for async validation (username check, email uniqueness)
  • Use valueChanges + switchMap for dependent dropdowns (country → city)
  • Use valueChanges + map + startWith for live price calculators and previews
  • Always clean up form subscriptions with takeUntil or async pipe

📚 Coming Up in Chapter 9...

Chapter 9 covers debounceTime, throttleTime, distinctUntilChanged — the timing operators.

These are essential for search boxes, scroll events, resize events, and any situation where you need to control HOW OFTEN your code runs.

See you in Chapter 9! 🚀

💌 RxJS Deep Dive Newsletter Series | Chapter 8 of 10
Follow me on : Github Linkedin Threads Youtube Channel

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten RxJS in Angular — Chapter 8 | RxJS + Angular Reactive Forms — Live Validation ও Dynamic Forms

Thematisch verwandte Begriffe: RxJS, Angular, Chapter, Reactive · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94109 | openEQUELLA versions before 2026.1.0 contain a remote code execution vul…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick