Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TypeError: Cannot read properties of undefined (reading 'filter') in Angular RxJS subscription

I’m encountering a TypeError in my Angular component with RxJS observables. The error message "TypeError: Cannot read properties of undefined (reading ‘filter’)" is pointing to my usage of filter on an array.

The error specifically happens within the userService.users$ subscription when attempting to filter this.users. The intention is to exclude the logged-in user from the list.

What should I do differently?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here is a simplified version of the relevant code:

user-list.component.ts

export class UserListComponent implements OnInit, OnDestroy {
  protected readonly Object = Object;
  users!: User[];
  usersSubscription!: Subscription;
  loggedUser!: User;
  loggedUserSubscription!: Subscription;
  groupedAndSortedUsers!: { [key: string]: User[] };

  constructor(public userService:UserService) {
  }

  ngOnInit() {

    this.loggedUserSubscription = this.userService.loggedUser$.subscribe(user => {
      this.loggedUser = user;
    })

    this.userService.users$.subscribe(users => {
        this.users = users.filter(user => user?.id !== this.loggedUser.id);
        // Remove the current logged-in user
        const filteredUsers = this.users.filter(user => user?.id !== this.loggedUser.id);
        this.groupedAndSortedUsers = this.userService.groupAndSortUsers(filteredUsers);
    });
  }

  ngOnDestroy() {
    this.usersSubscription.unsubscribe();
    this.loggedUserSubscription.unsubscribe();
  }
}

user.service.ts

export class UserService {
  private _users$: BehaviorSubject<User[] | undefined> = new BehaviorSubject<User[] | undefined>(undefined);
  private _loggedUser$: BehaviorSubject<User | undefined> = new BehaviorSubject<User | undefined>(undefined);

  constructor(private userHttpService: UserHttpService, private router: Router, private dtoMapperService: DtoMapperService, private matSnackBar: MatSnackBar,) {
    this.fetchUsers();
    this.fetchLoggedUser();
  }

  public get users$(): Observable<User[]> {
    return this._users$.asObservable() as Observable<User[]>;
  }

  public get users(): User[] {
    return this._users$.getValue() as User[];
  }

  public get loggedUser$(): Observable<User> {
    return this._loggedUser$.asObservable() as Observable<User>;
  }

  public get loggedUser(): User {
    return this._loggedUser$.getValue() as User;
  }

  public set users(users: User[]) {
    this._users$.next(users);
  }

  public set loggedUser(user: User) {
    this._loggedUser$.next(user);
  }

  public fetchUsers() {
    this.userHttpService.fetchUsers().subscribe({
      next: (usersDtos: UserDto[]) => {
        const users = usersDtos.map(userDto => this.dtoMapperService.mapUserDtoToUser(userDto));
        this._users$.next(users);
      }
    });
  }

  public fetchLoggedUser() {
    this.userHttpService.fetchLoggedUser().subscribe({
      next: (userDto: UserDto) => {
        this._loggedUser$.next(this.dtoMapperService.mapUserDtoToUser(userDto))
      }
    })
  }

  public groupAndSortUsers(users: User[]): { [key: string]: User[] } {
    const sortedUsers: { [key: string]: User[] } = {};

    users.forEach(user => {
      const firstLetter = user.name.charAt(0).toUpperCase();
      if (!sortedUsers[firstLetter]) {
        sortedUsers[firstLetter] = [];
      }
      sortedUsers[firstLetter].push(user);
    });

    const sortedKeys = Object.keys(sortedUsers).sort();

    sortedKeys.forEach(letter => {
      sortedUsers[letter].sort((a, b) => a.name.localeCompare(b.name));
    });

    const sortedUsersResult: { [key: string]: User[] } = {};
    sortedKeys.forEach(letter => {
      sortedUsersResult[letter] = sortedUsers[letter];
    });

    return sortedUsersResult;
  }
}

user-list.component.ts

<div class="user-list-box">
    <mat-list-item role="listitem">ME</mat-list-item>
    <mat-divider></mat-divider>
    <app-user [user]="userService.loggedUser"></app-user>
    
    <mat-list role="list">
      @for (letter of Object.keys(groupedAndSortedUsers); track letter) {
        <mat-list-item role="listitem">{{ letter }}</mat-list-item>
        <mat-divider></mat-divider>
        @for (user of groupedAndSortedUsers[letter]; track user.id) {
          <app-user [user]="user"></app-user>
        }
     }
    </mat-list>
</div>

>Solution :

You need check if users is an array in subscribe function

e.g. you can use (users || []), so if users are "undefined" get the value of an empty array.

this.userService.users$.subscribe((users:any[]) => {
   //you can check the value of users
   console.log(users)
   this.users = (users || []).filter(user => user?.id !== this.loggedUser.id);
   ...
})
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading