【问题标题】:How to make child component detects object (@Input()) from parent component has changed in Angular如何让子组件检测来自父组件的对象(@Input())在Angular中发生了变化
【发布时间】:2019-09-06 11:00:49
【问题描述】:

我有一个来自父组件的对象,也收到类似这样的子组件:

{
  attribute: 'aaaa',
  attribute2: [
    {
      value
    },
    {
      value
    },
    {
      value
    },
  ]
}

此对象是来自父组件的@Input。当我对 attribute2 数组中的对象进行更改时,我希望子组件检测到已进行更改然后进行更新。由于这是一个对象,我无法让它工作,所以我将整个对象 (this.objet = _.cloneDeep(this.object) 克隆到父组件中,以便子组件检测到发生了更改。

有没有其他方法可以不克隆整个对象?提前致谢

编辑:

子组件

export class ChildComponent implements OnInit, OnChanges {
  @Input() public object: any;
}

html

<div>
   <span>{{object.attribute}}</span>
   <div *ngFor="let items of object.attribute2">{{item.value}}</div>
</div>

父组件

export class ParentComponent implements OnInit {
  public object: any;

  updateObject() {
      this.object.attribute2[1] = 'Changed value';
      this.object = _.cloneDeep(this.object);
  }
}

html

<div>
   <child-component [object]="object"></child-component>
</div>

【问题讨论】:

  • 你能展示你的模板吗?你是怎么使用的?
  • @legin 使用它来获得更改的价值@Input() set Inputname(value: number) { console.log(value); }
  • 您提供的代码 sn-ps 并不能真正使用。例如您的示例对象有一个没有有效语法的对象数组,而您的 updateObject-function 用字符串替换了这些对象。并且您的 ngfor 创建了一个名为 items 的变量,但您尝试读取 item 的值 - 如果您将包含该值的对象替换为字符串,则作为没有 @987654335 的原始类型@-property 也可以。请提供一个最小的、可重现的示例来展示错误,例如StackBlitz。

标签: javascript angular typescript


【解决方案1】:

一种有效的方法是使用 EventEmitter 和服务通信来 触发子组件的变化。

@Tony 提到的方法是使用 ngOnChanges()。它是检测绑定属性更改的一个很好的快捷方式,但是随着您添加越来越多的绑定,从长远来看,使用此钩子会影响您的应用程序,因为无论您是否希望所有绑定属性发生更改,它都会在每次绑定属性更改时运行来电。

所以对于基于服务的通信,我在

上创建了一个示例

在此示例中,我使用 @Input() 将一个数组绑定到子组件,并添加新数据,该数组由父组件更新,最新值传递给服务,然后发出该值。子组件订阅该值并执行相关代码。

服务:

import { Injectable, EventEmitter } from '@angular/core';

@Injectable({
    providedIn: "root"
})
export class DataService {

  dataUpdated:EventEmitter<any> = new EventEmitter();

  constructor() { }

  setLatestData(data) {
    this.dataUpdated.emit(data);
  }

}

子组件 TS

import { Component, OnInit, Input } from '@angular/core';
import { DataService } from '../data-service.service';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {

  @Input() allData: [];
  latestData: any;

  constructor(private dataService: DataService) { }

  ngOnInit() {
    this.dataService.dataUpdated.subscribe((data) => {
      this.latestData = data;
    });
  }

}

子组件 HTML

<p>
Latest Data: {{ latestData }}
</p>
<h3>List:</h3>
<li *ngFor="let data of allData">
  {{ data }}
</li>

父组件 TS

import { Component } from '@angular/core';
import { DataService } from './data-service.service'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  dataArr = [];

  constructor(private dataService: DataService){}

  onAddTimestamp() {
    let timestamp = new Date();
    this.dataArr.push(timestamp);
    this.dataService.setLatestData(timestamp);
  }

}

父组件 HTML

<hello name="{{ name }}"></hello>
<p>
  Start editing to see some magic happen :)
</p>
<button
(click)="onAddTimestamp()"
>
  Add Timestamp
</button>
<app-child
[allData] = "dataArr"
></app-child>

【讨论】:

    【解决方案2】:

    在您的组件中使用 ngOnChanges() 生命周期方法。

    ngOnChanges 在数据绑定属性被调用后立即调用 检查并在查看和内容子项之前检查是否至少 其中一个发生了变化。

    有些是这样的

    @Input() object: string;
    
    ngOnChanges(changes: SimpleChanges) {
        console.log(changes.object.currentValue);
        // You can also use object.previousValue and 
        // object.firstChange for comparing old and new values
    }
    

    【讨论】:

      猜你喜欢
      • 2017-06-04
      • 1970-01-01
      • 2016-11-29
      • 2018-06-14
      • 2021-05-29
      • 2019-07-29
      • 2017-08-15
      • 2022-11-26
      相关资源
      最近更新 更多