angularrxjs

Angular rx js Behaviour subject not working properly


I am facing issue in the Behaviour Subject not picking the value from selected option.

private selectedCustomerSubject = new BehaviorSubject<number>(0);
  
  selectedCustomerAction$ = this.selectedCustomerSubject.asObservable();  
    
getFilteredProjects(): Observable<project[]> {
    return combineLatest([this.projects$, this.selectedCustomerAction$ ]).pipe(
      map(([projects, selectedCustomerId]) => {
        return selectedCustomerId 
          ? projects.filter(project => project.id === selectedCustomerId) 
          : projects;
      })
    );
  }
  projectWithFilter$ = this.getFilteredProjects();

    <div class="container">
  <h2>Customer Projects filter dropdown</h2>

  <!-- Customer Dropdown -->
  <mat-form-field appearance="fill" class="customer-dropdown">
    <mat-label>Select Customer</mat-label>
    <mat-select (selectionChange)="onCustomerChange($event.value)">
      <mat-option *ngFor="let customer of customers$ | async as customers" [value]="customer.id">
        {{ customer.first_name }}
      </mat-option>
    </mat-select>
  </mat-form-field>

<h2>Projects filter Information </h2>
<div *ngIf="projectWithFilter$ | async as custprojects">
<mat-list>
<mat-list-item *ngFor="let custproject of custprojects ">
  {{ custproject.id }}
  {{ custproject.projectName }}
  {{ custproject.first_name }}
</mat-list-item>
</mat-list>
</div>

the project page is displaying all the projects rather than just with filter


Solution

  • Issue: Your BehaviorSubject is not updating when a new option is selected from the dropdown. As a result, selectedCustomerSubject is always 0, and the filtering logic in getFilteredProjects() does not work as expected.

    Root Cause: The BehaviorSubject(0) is initialized with 0, but it is not updated when a user selects a customer from the dropdown. The onCustomerChange() method is missing, so the value of selectedCustomerSubject never changes.

    Solution: You need to define the onCustomerChange() method and update selectedCustomerSubject when the user selects a new customer.

    Updated Code:

    import { Component } from '@angular/core';
    import { BehaviorSubject, Observable, combineLatest } from 'rxjs';
    import { map } from 'rxjs/operators';
    
    interface Project {
      id: number;
      projectName: string;
      first_name: string;
    }
    
    interface Customer {
      id: number;
      first_name: string;
    }
    
    @Component({
      selector: 'app-projects',
      templateUrl: './projects.component.html',
      styleUrls: ['./projects.component.css']
    })
    export class ProjectsComponent {
      // Mock customers observable
      customers$ = new BehaviorSubject<Customer[]>([
        { id: 1, first_name: 'John' },
        { id: 2, first_name: 'Alice' },
        { id: 3, first_name: 'Bob' }
      ]);
    
      // Mock projects observable
      projects$ = new BehaviorSubject<Project[]>([
        { id: 1, projectName: 'Project A', first_name: 'John' },
        { id: 2, projectName: 'Project B', first_name: 'Alice' },
        { id: 3, projectName: 'Project C', first_name: 'Bob' },
        { id: 1, projectName: 'Project D', first_name: 'John' }
      ]);
    
      // BehaviorSubject to store the selected customer ID
      private selectedCustomerSubject = new BehaviorSubject<number | null>(null);
      selectedCustomerAction$ = this.selectedCustomerSubject.asObservable();
    
      // Function to update the selected customer
      onCustomerChange(selectedCustomerId: number) {
        this.selectedCustomerSubject.next(selectedCustomerId);
      }
    
      // Filtering projects based on selected customer
      getFilteredProjects(): Observable<Project[]> {
        return combineLatest([this.projects$, this.selectedCustomerAction$]).pipe(
          map(([projects, selectedCustomerId]) =>
            selectedCustomerId ? projects.filter(project => project.id === selectedCustomerId) : projects
          )
        );
      }
    
      // Assign the filtered projects observable
      projectWithFilter$ = this.getFilteredProjects();
    }
    
    
    <div class="container">
      <h2>Customer Projects Filter Dropdown</h2>
    
      <!-- Customer Dropdown -->
      <mat-form-field appearance="fill" class="customer-dropdown">
        <mat-label>Select Customer</mat-label>
        <mat-select (selectionChange)="onCustomerChange($event.value)">
          <mat-option *ngFor="let customer of customers$ | async" [value]="customer.id">
            {{ customer.first_name }}
          </mat-option>
        </mat-select>
      </mat-form-field>
    
      <h2>Projects Filtered Information</h2>
      <div *ngIf="projectWithFilter$ | async as filteredProjects">
        <mat-list>
          <mat-list-item *ngFor="let project of filteredProjects">
            {{ project.id }} - {{ project.projectName }} - {{ project.first_name }}
          </mat-list-item>
        </mat-list>
      </div>
    </div>