Search code examples
angularrxjs-observablesformgroups

Unexpected page refresh when calling methods and managing state with Observable


I'm developing an Angular application where I manage a User Profile page. This page displays user information and the user's wishlist, among other things.

The user can add, delete, or update wishes. Whenever these operations are performed, they are followed by fetching the updated user profile from the server using an Observable (userProfile$), which is supposed to update the UI.

But the problem is that everytime i'm passing a update, delete method, the full page is reloading and i can't find why.

Do anyone have an idea of why it's not working well ?

The get user profile method is fetching the whole user element, could this be related ?

Here's my code of how I'm doing this:


  //User informations and password handling variables
  profileForm!: FormGroup;
  public userProfile$?: Observable<any>;
  passwordUpdateSuccess = false;
  profileUpdateSuccess = false;
  public groupDetails?: any;

  //Wish handling variables and functions

  wishes: any[] = [];
  public showUpdateForm: boolean = false;
  updateWishForm!: FormGroup;
  showUpdateFormFor: string | null = null;

  //Handling wish filtering

  public originalWishes: any[] = [];
  public filterForm!: FormGroup;

  ngOnInit(): void {

    //Handling wishes
    this.wishListService.secretSantaService.wishesSubject.subscribe(wishes => {
      this.wishes = wishes;
    });

    this.updateWishForm = this.formBuilder.group({
      title: ['', Validators.required],
      url: ['', Validators.required],
      description: ['', Validators.required],
      price: ['', Validators.required],
    });

    // Fetch the user profile and update the relevant fields
    this.userProfile$ = this.userService.getUserProfile();

    // Update form and wishes when userProfile$ emits a new value
    this.userProfile$.pipe(
      tap(userProfile => {
        this.profileForm.patchValue(userProfile);
        this.wishes = userProfile.wishList;
        this.originalWishes = userProfile.wishList;
      })
    ).subscribe();

    //Initialize the filter form control
    this.filterForm = this.formBuilder.group({
      minPrice: [''],
      maxPrice: ['']
    });

    //Adding a time between each key put in the filter form to avoid too many requests
    this.filterForm.valueChanges
      .pipe(debounceTime(500))
      .subscribe((filterValues) => this.filterWishes(filterValues));


  }


  addWish(wish: any) {
    this.wishListService.addWishToUserWishList(wish).subscribe({
      next: (newWish) => {
        this.updateWishForm.reset();
        this.showUpdateFormFor = null;
        if (this.userProfile$)
          this.userProfile$.subscribe(userProfile => {
            this.updateAndFilterWishes(userProfile.wishList);
          });
      },
      error: error => {
        console.error(error);
      }
    });
  }

  submitUpdate(wishId: string) {
    const updatedWish = this.updateWishForm.value;
    this.wishListService.updateWishFromUserWishlist(wishId, updatedWish).subscribe({
      next: updatedWish => {
        this.showUpdateFormFor = null;
        if (this.userProfile$)
          this.userProfile$.subscribe(userProfile => {
            this.updateAndFilterWishes(userProfile.wishList);
          });
      },
      error: error => {
        console.error(error);
      }
    });
  }

  deleteWish(wishId: string) {
    this.wishListService.deleteWishFromUserWishlist(wishId).subscribe({
      next: _ => {
        this.showUpdateFormFor = null;
        if (this.userProfile$)
          this.userProfile$.subscribe(userProfile => {
            this.updateAndFilterWishes(userProfile.wishList);
          });
      },
      error: error => {
        console.error(error);
      }
    });
  }

  getUserProfile(): void {
    this.userService.getUserProfile().subscribe({
      next: data => {
        this.ngZone.run(() => {
          if (this.profileForm)
            this.profileForm.patchValue({
              firstName: data.firstName,
              lastName: data.lastName,
              email: data.email,
              dateOfBirth: data.dateOfBirth
            });
        });
        console.log("data: ", data);
      },
      error: error => {
        console.error(error);
        return throwError(error);
      }
    });
  }

Also, here the html :

  <button mat-raised-button color="primary" (click)="openAddWishDialog()">Add Wish</button>

  <!-- Update wishlist -->
  <div class="flex items-center justify-center " *ngIf="userProfile$ | async as userProfile">
    <div class="col-span-12">
      <div class="overflow-auto lg:overflow-visible ">
        <h3 class="text-2xl font-medium text-gray-700">
          Your wish list
        </h3>
        <form [formGroup]="filterForm">
          <input formControlName="minPrice" placeholder="Minimum price">
          <input formControlName="maxPrice" placeholder="Maximum price">
        </form>

        <table class="table text-gray-400 border-separate space-y-6 text-sm">
          <thead class="text-gray-500">
          <tr>
            <th class="p-3">Name</th>
            <th class="p-3 text-left">Link</th>
            <th class="p-3 text-left">Price</th>
            <th class="p-3 text-left">Title</th>
            <th class="p-3 text-left">Actions</th>
          </tr>
          </thead>
          <tbody *ngFor="let wish of wishes">
          <tr class="bg-gray-100 lg:h-32">
            <td class="p-3">
              <div class="flex align-items-center">
                <div class="ml-3">
                  <div class="">{{wish.title}}</div>
                </div>
              </div>
            </td>
            <td class="p-3">
              {{wish.url}}
            </td>
            <td class="p-3 font-bold">
              {{wish.price}}
            </td>
            <td class="p-3">
              {{wish.description}}
            </td>
            <td class="p-3">
              <button type="submit" class="text-indigo-500 py-2 px-4 font-medium" (click)="toggleUpdateForm(wish.id)">
                <i class="material-icons-outlined text-base"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
                  <path d="M180-180h44l443-443-44-44-443 443v44Zm614-486L666-794l42-42q17-17 42-17t42 17l44 44q17 17 17 42t-17 42l-42 42Zm-42 42L248-120H120v-128l504-504 128 128Zm-107-21-22-22 44 44-22-22Z"/></svg></i>
              </button>
              <button type="submit" class="text-gray-400 hover:text-gray-100 ml-2" (click)="deleteWish(wish.id)">
                <i class="material-icons-round text-base"><svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
                  <path d="M261-120q-24.75 0-42.375-17.625T201-180v-570h-41v-60h188v-30h264v30h188v60h-41v570q0 24-18 42t-42 18H261Zm438-630H261v570h438v-570ZM367-266h60v-399h-60v399Zm166 0h60v-399h-60v399ZM261-750v570-570Z"/></svg></i>
              </button>
            </td>
          </tr>
          <tr class="bg-gray-800" *ngIf="showUpdateFormFor === wish.id">
            <td colspan="6" class="p-3">
              <form [formGroup]="updateWishForm" (ngSubmit)="submitUpdate(wish.id)">
                <input formControlName="title" placeholder="Wish Name">
                <input formControlName="url" placeholder="Wish Link">
                <textarea formControlName="description" placeholder="Wish Description"></textarea>
                <button type="submit">Update</button>
              </form>
            </td>
          </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>

Solution

  • Alright, i found the problem.

    Solution :

    I had a controller that was used to call every elements from a user, and i linked my wishlist to the exact same observable, which was causing this ... interaction

    Other :

    So, i've decided to make my code more maintainable (thanks @akop !) and to have a separation of needs. Which led to a brand new component, not bothered by the other, keep it simple !