0

I use firebase and angular 2+. In my app I have a login page. When I click 'sign in' button, the spinner is loading and after success, it should be false, but it doesn't update. Why?

Template

<div class="sign-in-form-buttons-section">
  <div>{{isLoadingInProgress}}</div>
  <button
    *ngIf="!isLoadingInProgress; else loading"
    mat-raised-button
    color="primary"
    (click)="onSignInClicked()"
  >
    Sign In
  </button>
  <ng-template #loading>
    <mat-spinner></mat-spinner>
  </ng-template>
</div>

Controller

public signInFormGroup: FormGroup;
public isLoadingInProgress: boolean = false;

constructor() {
  this.signInFormGroup = new FormGroup({
    email: new FormControl(''),
    password: new FormControl(''),
  });
}

public onSignInClicked(): void {
  this.isLoadingInProgress = true;

  const signInInfo: SignInInfo = {
    email: this.signInFormGroup.value.email,
    password: this.signInFormGroup.value.password
  };

  this.authService.signInWithEmailAndPassword(
    signInInfo.email,
    signInInfo.password,
  )
  .then(() => {
    this.isLoadingInProgress = false;
  })
  .catch(error => {
    this.snackBarService.showSnackBar(error.message);
    this.isLoadingInProgress = false;
  });
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
prolina
  • 185
  • 4
  • 14
  • put a debugger statement here this.isLoadingInProgress = false; do you see it called at run time? – JWP May 13 '20 at 13:41
  • I am not sure if a callback to `then` without an argument will get executed. Try `.then((response) => {...`. – ruth May 13 '20 at 13:53
  • While your code may update the variable correctly, you need to make Angular aware of that change so that it updates the views. See https://stackoverflow.com/questions/50519200/angular-6-view-is-not-updated-after-changing-a-variable-within-subscribe – Frank van Puffelen May 13 '20 at 14:34

2 Answers2

1

Yes, It happens because Angular Doesn't check every non-local variable for performance issues. For Http request, angular can't detect in one Process/Thread.

Solution: You can use the RxJS BehaviorSubject method.

For Example:

  • You can try with these below-mentioned files.

loader.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class LoaderService {
  public status: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  display(value: boolean) {
  console.log('LoaderService.display ' + value);
  this.status.next(value);
  }
}

loader.component.ts

import {Component, OnInit} from '@angular/core';
import {LoaderService} from './loader.service';

@Component({
    selector: 'app-loader',
    templateUrl: 'loader.component.html',
    providers: [LoaderService]
})

export class LoaderComponent implements OnInit {
    isLoading: boolean;

    constructor(private loaderService: LoaderService) {
    }

    ngOnInit() {
        this.loaderService.status.subscribe((val: boolean) => {
            this.isLoading = val;          // <--- Important Block
        });
    }

    submitData() {
        this.loader.display(true);      // <--- Loader true,BehaviorSubject True.
        this.http
          .post("http://localhost:3000/login", this.loginForm.value).then(data => {
            this.loader.display(false);
          })
          .catch(err => {
                console.log(err);
                this.loader.display(false); // <--- Loader Flase,BehaviorSubject False.
          });
          this.loader.display(false);
    }
}

loader.component.html

<div class="loader" *ngIf="isLoading"></div>

It worked for me as well as many angular developers use BehaviorSubject this way.I hope it will help you.

Rajan
  • 1,512
  • 2
  • 14
  • 18
  • I think, your solution is good, I tried it, but if I show `this.isLoadingInProgress` in component, the variable does not have the same result as I expect, it should be false, but it's true (in controller it's false) – prolina May 15 '20 at 12:13
0

From Promise.prototype.then() docs:

If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors.

Try passing an argument to the then callback function.

this.authService.signInWithEmailAndPassword(
  signInInfo.email,
  signInInfo.password,
)
.then((response) => {                   // <-- `response` argument
  this.isLoadingInProgress = false;
})
.catch(error => {
  this.snackBarService.showSnackBar(error.message);
  this.isLoadingInProgress = false;
});
ruth
  • 29,535
  • 4
  • 30
  • 57