最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular @Input() Not Updating UI in Child - Stack Overflow

programmeradmin2浏览0评论

I've implemented a child component to render a table based on a list provided via @Input(). The data is loaded via http, however the UI (child component) is not updated unless I wave my mouse over the screen. I've seen people post about implementing ngOnChanges() in my child, but I thought Angular was supposed to do this by default? Am I missing something? Why would the UI not update with this?

Child code looks something like this:

childponent.ts

@Component({
  selector: 'child',
  templateUrl: './childponent.html',
  styleUrls: ['./childponent.scss'],
})
export class ChildComponent implements {
  @Input() data: any[] = [];
  constructor() {}
}

childponent.html

<table>
  <tr *ngFor="let item of data"><td>{{ item }}</td></tr>
</table>

Parent code that uses the component looks something like this:

parentponent.ts

@Component({
  selector: 'parent',
  templateUrl: './parentponent.html',
  styleUrls: ['./parentponent.scss'],
})
export class ParentComponent implements OnInit {
  data: string[] = [];

  constructor(private endpointService: EndpointService) {}

  ngOnInit() {
    // response is a string array like: ['hello', 'world']
    this.endpointService.loadData().subscribe((response) => {
      this.data = response;
    });
  }
}

parentponent.html

<child [data]="data"></child>

============================= EDIT ==================================

I verified that it only fails to load when updating inside of the subscribe callback (if I set a static array, it loads just fine).

So it looks like I'm able to resolve this by running changeDetectorRef.detectChanges() in the parent component, but this feels hackish like I shouldn't have to do this. Is this a good way to resolve this? Or does this indicate something wrong with my implementation?

parentponent.ts

@Component({
  selector: 'parent',
  templateUrl: './parentponent.html',
  styleUrls: ['./parentponent.scss'],
})
export class ParentComponent implements OnInit {
  data: string[] = [];

  constructor(private endpointService: EndpointService,
              private changeDetectorRef: ChangeDetectorRef) {}

  ngOnInit() {
    // response is a string array like: ['hello', 'world']
    this.endpointService.loadData().subscribe((response) => {
      this.data = response;
      this.changeDetectorRef.detectChanges();
    });
  }
}

I've implemented a child component to render a table based on a list provided via @Input(). The data is loaded via http, however the UI (child component) is not updated unless I wave my mouse over the screen. I've seen people post about implementing ngOnChanges() in my child, but I thought Angular was supposed to do this by default? Am I missing something? Why would the UI not update with this?

Child code looks something like this:

child.component.ts

@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss'],
})
export class ChildComponent implements {
  @Input() data: any[] = [];
  constructor() {}
}

child.component.html

<table>
  <tr *ngFor="let item of data"><td>{{ item }}</td></tr>
</table>

Parent code that uses the component looks something like this:

parent.component.ts

@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss'],
})
export class ParentComponent implements OnInit {
  data: string[] = [];

  constructor(private endpointService: EndpointService) {}

  ngOnInit() {
    // response is a string array like: ['hello', 'world']
    this.endpointService.loadData().subscribe((response) => {
      this.data = response;
    });
  }
}

parent.component.html

<child [data]="data"></child>

============================= EDIT ==================================

I verified that it only fails to load when updating inside of the subscribe callback (if I set a static array, it loads just fine).

So it looks like I'm able to resolve this by running changeDetectorRef.detectChanges() in the parent component, but this feels hackish like I shouldn't have to do this. Is this a good way to resolve this? Or does this indicate something wrong with my implementation?

parent.component.ts

@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss'],
})
export class ParentComponent implements OnInit {
  data: string[] = [];

  constructor(private endpointService: EndpointService,
              private changeDetectorRef: ChangeDetectorRef) {}

  ngOnInit() {
    // response is a string array like: ['hello', 'world']
    this.endpointService.loadData().subscribe((response) => {
      this.data = response;
      this.changeDetectorRef.detectChanges();
    });
  }
}
Share Improve this question edited Dec 8, 2020 at 19:09 ossys asked Dec 8, 2020 at 18:11 ossysossys 4,2175 gold badges34 silver badges36 bronze badges 1
  • You can create a boolean variable on child component and use ngIf om table. This would make sure table is not loaded until the Input is received. – Rajat Commented Dec 8, 2020 at 21:25
Add a comment  | 

5 Answers 5

Reset to default 9

You can also try to force change detection by forcing the value reference update via, for example, the spread operator:

this.endpointService.loadData().subscribe((response) => {
  this.data = [...response];
});

I replaced the service with a static string array and it worked well. I think there is problem with the observable subscription.

child.component.ts

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

@Component({
  selector: 'child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Input() data: any[] = [];
  constructor() { }

  ngOnInit() {
  }

}

parent.component.ts

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

@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
  data: string[] = [];

  constructor() {}

  ngOnInit() {
    
      this.data = ['hello', 'world','aaa','ddd'];
    
  }
}

I have fixed this problem updating the attribute passed on child input instead of re-assign it. I think that Angular passes input as copy. So, in subscribe body you should use

resultOfSubscribe.forEach((v) => varPassedByInput.push(v)); 

hummm well .. when the component is rendered as first time it will show with the empty array becouse the api call stills happening and needs the onchanges method in child component in order to listen the complete api call and the list will re render

Seems that you have some other errors in template expressions which force the whole template to fail. Here's a stackblitz I've created and everything works: https://stackblitz.com/edit/angular-ivy-w2ptbb?file=src%2Fapp%2Fhello.component.ts

Do you have maybe some errors in console?

发布评论

评论列表(0)

  1. 暂无评论