Clifford Eby
Clifford Eby

Reputation: 41

Dependent Function Using Angular Forms with Async Data

The function below needs the values of some user properties. Parameter scores is dependent on user and is provided by this.form.get('scores').valueChanges.subscribe((value). The console.log correctly shows scores as an array and this.user as an Observable.

How do I access the property values of user needed to return a value.

Full StackBlitz here. When I change a value of scores, I want stp => Score to Post1 to contain new values.

Thanks to Cory Rylan for the template.

  ESA(scores) {
    let stp = [];
    console.log('ESA', scores, this.user);
    scores.map((item: number, index) => {
      stp[index] = this.user.pipe(
        tap((user) => user.scores[index] + 100)
      );
      console.log('stp', stp, item, this.user);
    });
    return stp;
  }

Upvotes: 0

Views: 81

Answers (2)

Clifford Eby
Clifford Eby

Reputation: 41

As suggested by @Dimanoid, I had to subscribe to the this.user -- once as a side effect and once in the html using the async pipe. A revised StackBlitz is here.

Data are obtained through a service and provided to the form. shareReplay allows for multiple subscriptions to this.user.

 this.user = this.userService.loadUser().pipe(
      tap((user) => this.form.patchValue(user)),
      shareReplay()
    );

this.user is subscribed to in function userProp() and property fields are accessed.

userProp() {
    let parsArray = [];
    let hCapsArray = [];
    let ci
    this.user.subscribe((user) => {
      parsArray = user.pars;
      hCapsArray = user.hCaps;
      ci = user.ci;
    });
    return [parsArray, hCapsArray, ci] as const;
  }

Finally the ESA function is called. It takes an array of scores and returns adjustments to those scores.

 ESA(value) {
    const data = this.userProp(); //First Subcription to User
    const pars = data[0];
    const hCaps = data[1];
    const ci = data[2];
    const value1 = [];
    value
      .forEach((x, index) =>
        x - pars[index] > 3
          ? (value1[index] = pars[index] + 3)
          : x - pars[index] > 2 && hCaps[index] >= ci
          ? (value1[index] = pars[index] + 2)
          : (value1[index] = x)
      );
    console.log('values', value1, value, pars, ci);
    return value1;
  }

Comments in the code ask two questions. First, should I unsubscribe from this.user? Does the async pipe and shareReplay automatically unsubscribe all this.user subscriptions? Second, can I use .map instead of the for loop in loadScoreControls(item)

Upvotes: 0

Dimanoid
Dimanoid

Reputation: 7289

No idea what you trying to achieve but this.user.pipe(...) will not produce any data until you subscribe to it. So i'd recommend either define user in the service as BehaviorSubject<User> and get it's value by this.userService.user.getValue() or subscribe to userService.loadUser() in component and update local variable in subscription.

constructor(...) {
  this.userService.loadUser().subscribe(user => this.user = user);
...
}

Upvotes: 1

Related Questions