1

I have an update method in a component which calls another function for some validation and then executes the updates if validation is successful. However the validation logic itself depends on a some values that are fetched using http.get. My issue is that validate logic completes before the subscription returns and the update happen before the errors get a chance to be populated.

I have simulated this in the following Stackblitz: https://stackblitz.com/edit/angular-jwnq3h?file=src/app/hello.component.ts

How do I ensure that the validation methods waits for subscription to complete before returning its own Observable? I feel like this should be simple in the rxjs world, but coming from a Java background, it all seems like magic.

Component code for reference from the above Stackblitz:

import { Component, Input } from "@angular/core";
import { Observable, of, from } from "rxjs";

@Component({
  selector: "hello",
  template: `
    <h1>Demo</h1>
    <p><button (click)="updateValues()">Update</button></p>
    <p><button (click)="updateValues(true)">Invalid Update</button></p>
    <p>{{ updateMessage }}</p>
  `,
  styles: [
    `
      h1 {
        font-family: Lato;
      }
    `
  ]
})
export class HelloComponent {
  @Input() name: string;

  updateMessage: string = "Not updated";

  updateValues(withErrors: boolean) {
    this.validate(withErrors).subscribe(validation => {
      if (validation.isValid) {
        let confirmation = confirm("Confirm update");
        if (confirmation) {
          this.doUpdate();
        }
      } else {
        alert(
          "Invalid: \n" +
            validation.errors.reduce((message, error) => message + "\n" + error)
        );
      }
    });
  }

  validate(withErrors: boolean): Observable<any> {
    let validation: any = {};
    validation.isValid = true;
    validation.errors = [];

    let showError3: boolean = false;
    if (withErrors) {
      validation.errors.push("Error 1");
      validation.errors.push("Error 2");

      this.fetchValues().subscribe(values => {
        setTimeout(function() {
          console.log("Execute after delay");
          let confirmation = confirm("values fetched" + values);
          if (confirmation) {
            showError3 = true;
          } else {
            showError3 = false;
          }

          if (showError3) {
            validation.errors.push("Error 3");
          }
        }, 5000);
      });
    }

    validation.isValid = validation.errors.length == 0;

    return of(validation);
  }

  doUpdate() {
    this.updateMessage = "Updated";
  }

  fetchValues(): Observable<any> {
    let values = Array.from(Array(20), (e, i) => i + 1);
    return of(values);
  }
}
vaisakh
  • 1,041
  • 9
  • 19
  • 1
    Does this answer your question? [How do I return the response from an Observable/http/async call in angular?](https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular) – R. Richards Oct 16 '20 at 17:37
  • I got the basic concept mentioned in that and numerous other posts -> do everything that depends on the observable inside the subscription. Maybe I'll try executing the inner http.get first and on its subscribe execute the validate method. This is like a reverse flow which felt counter-intuitive to me. Thanks for the link! – vaisakh Oct 16 '20 at 18:09

0 Answers0