简体   繁体   中英

Refreshing data in two parts of the same Angular component

Within a component, I have a property that's an array with some info displayed in a summary as well as an area for making changes. Trying to get the summary data to update as changes are made.

Here's a simplified example...

// discovery.component.ts

@Component({
  selector: 'app-discovery',
  templateUrl: './discovery.component.html',
  styleUrls: ['./discovery.component.scss']
})
export class DiscoveryComponent implements OnInit {
  levels = [
    { title: 'title1', rating: 0 },
    { title: 'title2', rating: 3 },
    { title: 'title3', rating: 5 },
  ]
}
<!--discovery.component.html-->

<!--Summary info-->
<div *ngFor="let level of levels">
  {{ level.title }}
  {{ level.rating }} <!--Updates when the range slider changes ->
  <app-level-display [level]="level.rating"></app-level-display>
</div>

<!--Editing area-->
<div *ngFor="let level of levels; let i = index">
  {{ level.title }}
  <input type="range" class="form-range" min="0" max="5" name="level{{i}}" [(ngModel)]="level.rating" [value]="level.rating">
  {{ level.rating }}
</div>
<!--level-display.component.html-->
<ng-container *ngFor="let level of this.levels">
  
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#0D4967" class="bi bi-caret-right-fill" viewBox="0 0 16 16">
    <defs>
      <linearGradient id="gradient1">
        <stop class="stop1" offset="0%" stop-color="#74FF87"/>
        <stop class="stop2" offset="15%" stop-color="#74FF87"/>
        <stop class="stop3" offset="100%" stop-color="#0D4967"/>
      </linearGradient>
    </defs>
    <path d="m7.14,8.753l-5.482,4.796c-0.646,0.566 -1.658,0.106 -1.658,-0.753l0,-9.592a1,1 0 0 1 1.659,-0.753l5.48,4.796a1,1 0 0 1 0,1.506l0.001,0z" fill="url(#gradient1)"/>
  </svg>
</ng-container>
// level-display.component.ts
import { Component, OnInit, Input } from '@angular/core'

@Component({
  selector: 'app-level-display',
  templateUrl: './level-display.component.html',
  styleUrls: ['./level-display.component.scss']
})
export class LevelDisplayComponent implements OnInit {
  @Input() level: number = 0
  levels: number[] = []

  constructor() {
  }

  ngOnInit(): void {
    this.levels = Array(this.level).fill(1)
  }

}

If I change the slider (input type=range), the summary info updates the reference to {{ level.rating }} but the component app-rating-viewer does not.

UPDATE: Looks like all of this stemmed from my establishing the array for app-level-display in ngOnInit(). Changing the component to:

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-level-display',
  templateUrl: './level-display.component.html',
  styleUrls: ['./level-display.component.scss']
})
export class LevelDisplayComponent implements OnInit {
  @Input() level: number = 0

  constructor() {
  }

  iterate(n: number): Array<number> {
    return Array(n)
  }

  ngOnInit(): void {
  }

}

fixed the issue.

The best approach I can think of is using ReactiveForms with the FormArray clause.

In your component declare the value as a form array, I use FormControl as the value of rating because you need to update it dynamically:

    this.ratingsForm = this.formBuilder.array([
        { title: 'title1', rating: new FormControl(0) },
        { title: 'title2', rating: new FormControl(3) },
        { title: 'title3', rating: new FormControl(5) },
    ]);

Then in your HTML loop through it as controls

  <div *ngFor="let level of this.ratingsForm.controls">
    {{ level.value.title }} {{ level.value.rating.value }}
  </div>

  <!--Editing area-->
  <div *ngFor="let level of this.ratingsForm.controls; let i = index">
    {{ level.value.title }}
    <input type="range" class="form-range" min="0" max="5" name="level{{i}}" [formControl]="level.value.rating">
    {{ level.value.rating.value }}
  </div>

The formBuilder comes from a DI on the constructor:

contructor(private formBuilder: FormBuilder)

This is a very simple example, you can refactor it to look better.

Generally speaking, its better to use ReactiveForms instead of the old ngModel .

please remove the value attributes

<input type="range" class="form-range" min="0" max="5" name="level{{i}}" [(ngModel)]="level.rating" >

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM