简体   繁体   中英

Angular 10 - View doesn't update when model is modified

Angular 10.1.6, TypeScript 4.0.5

Hello

Context

In my webapp, I have 3 components.

Component A stores an Array<Image>

export class ComponentParentA implements OnInit {
  images: Array <Image> ;

  addImageToList(newImage: Image) {
    this.images.push(newImage)
  }
}

The Component C displays the list of images.

export class ComponentChildC implements OnInit {

  @Input() images: Array <Image>;
}

The component C is called from the Component A html template like this:

<ComponentChildC [images]="images"></ComponentChildC>

Component B is in charge to contact my API, add an image which has been selected previously. The API return an Image object, which correspond to my model. The component emit the Image so the ComponentA add the returned image to its Array (Calling addImageToList)
addImage is an Observable return by this.http.post ( HttpClient )

export class ComponentChildB implements OnInit, AfterViewInit {
  @Output() eventCreateImage : EventEmitter<Image>;

  addImage(data) {
    this.service.addImage(data).subscribe((image) => {
        this.eventCreateImage.emit(image)
      })
  }

}

Component A calls Component B like this:

<ComponentChildB (eventCreateImage)="addImageToList($event)"></ComponentChildB>

Problem

The Component B add an image when I click on a button. This click trigger the addImage function. All the component work correctly and the image is save on my server. The API returns the image and the latter is correctly stored in the Array in Component A. However, the view of the component C is not updated and the newly created image doesn't appear. If I click a second time on the button, a new image is stored. This time, the previous image, which I couldn't see previously, appears correctly. The new image don't.

I would like the image to appear directly.

What I already did

I saw similar issues on the web.

  • First , I tried to replace this.images.push(newImage) by this.images = this.images.concat(newImage) in addImageToList function. It doesn't work.
  • Next, I saw that, because images is an array, Angular doesn't detect any change when I add a new Image in my array. I made my Component C implements the OnChange interface. Effectively, the ngOnChange function is not called.
  • I saw here that I could try to reload my component manually So I made my Component C implement DoCheck. Something strange appeared. When I click on the button and I do console.log(this.images) in ngDoCheck in component C, I see that the list is correctly updated. But the image still doesn't appear. So I try to call ChangeDetectorRef methods like markForCheck and detectChanges to notify the component of the change, but it didn't work.

If you have any idea where my problem may be coming from, I would be grateful if you could help me

I didn't test but i think it's cause strategy detection. You can try 3 differents solutions (I can't test now but normaly it will be work).

PS: sorry for my english

1/ in your object @Component add changeDetection in your components

@Component({
  selector: 'app-component',
  template: `...`,
  changeDetection: ChangeDetectionStrategy.OnPush
})

then in your function addImageToList() replace your code by

addImageToList(newImage) {
   this.images = [...this.images, newImage]
}

2/ in your component C replace your @Input by

@Input() set images(value: Array <Image>) {
      myImages = value
 }

the properties binding in html will be myImages in this context

3/ You can change manualy the strategy detection with the service ChangeDetectorRef. Add this service in your constructor component A then in your function add:

constructor(
     private cd: ChangeDetectorRef
   ){}

  addImageToList(newImage: Image) {
    this.images = [...this.images, newImages];
    this.cd.markForCheck();
  }

If this solutions don't work look the documentation of detection strategy in Angular or try to mix 1 and 2 together

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