【问题标题】:Two Way Binding on an Angular 2+ ComponentAngular 2+ 组件上的两种方式绑定
【发布时间】:2018-03-16 21:58:28
【问题描述】:

我有一个 Ionic 应用程序,我在其中创建了一个组件来显示对象的一些数据。我的问题是,当我更新托管组件的父级中的数据时,组件内的数据不会更新:

my-card.component.ts

@Component({
    selector: 'my-card',
    templateUrl: './my-card.html'
})
export class MyCard {
    @Input('item') public item: any;
    @Output() itemChange = new EventEmitter();
    constructor() {

    }

    ngOnInit() {
        // I do an ajax call here and populate more fields in the item.
        this.getMoreData().subscribe(data => {
            if (data.item){
                this.item = data.item;
            }
            this.itemChange.emit(this.item);
        });
    }
}

我的卡片.html

<div class="comment-wrapper" *ngFor="let subitem of item.subitems">
    {{subitem.title}}
</div>

在父级中我使用这样的组件:

<my-card [(item)]="item"></my-card>

还有父级的 ts 文件:

@IonicPage()
@Component({
    selector: 'page-one',
    templateUrl: 'one.html',
})
export class OnePage {
    public item = null;
    constructor(public navCtrl: NavController, public navParams: NavParams) {
        this.item = {id:1, subitems:[]};
    }

    addSubItem():void{
        // AJAX call to save the new item to DB and return the new subitem.
        this.addNewSubItem().subscribe(data => {
            let newSubItem = data.item;
            this.item.subitems.push(newSubItem);
        }
    }
}

所以当我调用 addSubItem() 函数时,它不会更新组件并且 ngFor 循环仍然不显示任何内容。

【问题讨论】:

  • 这对我来说毫无意义,你正在传递输入,但没有在子组件中使用它。
  • 您好,抱歉,如果我的代码不是很清楚,我不得不剥离一些代码。我基本上传入了一个仅包含 Id 的项目对象,然后在加载卡片组件时,我执行了一个 ajax 调用来补充其余的项目字段。
  • 好的,我现在明白了。因此,您谈论双向绑定,因此父项需要与子项具有相同的值(在 api 请求之后),或者您在父项中所做的事情足以反映在子项中。我正在考虑解决方案,所以这很重要:)
  • 好的,这样父级会将 id 传递给子级,而子级会将 AJAX 的结果混合起来。然后用户将与创建新子项的父元素进行交互,然后我需要在 clild 视图中显示该新子项。这有意义吗?

标签: javascript angular typescript ionic3 angular2-components


【解决方案1】:

您在发出 api 请求时破坏了对象引用。您正在分配新值,即覆盖您从父级获得的输入值,并且对象不再指向同一个对象,但您的子级中的 item 是一个完全不同的对象。如果你想要双向绑定,我们可以使用Output

孩子:

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

// ..

@Input() item: any;
@Output() itemChange = new EventEmitter();

ngOnInit() {
  // I do an ajax call here and populate more fields in the item.
  this.getMoreData(item.id).subscribe(data => {
    this.item = data;
    // 'recreate' the object reference
    this.itemChange.emit(this.item)
  });
}

现在我们再次拥有相同的对象引用,并且您在父级中所做的任何事情都会反映在子级中。

【讨论】:

  • 您好,我已经按照您的建议更新了我的代码,但是当我调用 addSubItem() mentod 时,它仍然没有更新视图中的项目列表。
  • 我现在可以工作了,这是因为从 addNewSubItem 请求传回的数据不正确。谢谢
【解决方案2】:

如果getMoreData方法返回一个observable,这段代码需要如下所示:

ngOnInit() {
    // I do an ajax call here and populate more fields in the item.
    this.getMoreData().subscribe(
        updatedItem => this.item = updatedItem
    );
}

订阅导致异步操作执行并返回一个 observable。当数据从异步操作返回时,它会执行提供的回调函数并将项目分配给返回的项目。

【讨论】:

    【解决方案3】:

    您使用 @Input() 装饰器将项目声明为:

     @Input('item') public item: any;
    

    但是你使用双向绑定就可以了:

    <my-card [(item)]="item"></my-card>
    

    如果只是输入,应该是

    <my-card [item]="item"></my-card>
    

    现在,如果您调用 addSubItem(),它应该会显示新添加的项目。

        this.item = this.getMoreData();
    

    如果你想使用通过@Input() 传递的项目,将getMoreData() 放在你的卡片组件中是没有意义的

    【讨论】:

    • 我试过去掉 () 还是不行。此外,我只传递了项目的 id,卡片组件用于通过 AJAX 请求从服务器获取其余项目数据。
    【解决方案4】:

    您的组件交互有点偏离。查看 Angular 文档 (https://angular.io/guide/component-interaction) 上的指南。具体来说,使用 ngOnChanges (https://angular.io/guide/component-interaction#intercept-input-property-changes-with-ngonchanges) 或使用服务来订阅和监视父子节点之间的更改 (https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 1970-01-01
      • 2020-07-07
      • 2018-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多