从Angular 2中的子组件更新父组件属性

Posted

技术标签:

【中文标题】从Angular 2中的子组件更新父组件属性【英文标题】:Update parent component property from child component in Angular 2 【发布时间】:2017-05-18 19:20:50 【问题描述】:

我正在使用@input 接收来自父组件的属性,以便在其中一个子组件的元素中激活 CSS 类。

我能够从父级接收属性并激活类。但这仅适用于一次。我从父组件接收的属性是一个布尔数据类型,当我从子组件将它的状态设置为false 时,它在父组件中不会改变。

Plunkr:https://plnkr.co/edit/58xuZ1uzvTophptOING2?p=preview

app.ts

import Component, NgModule from '@angular/core'
import BrowserModule from '@angular/platform-browser'
import  HeaderComponent  from './header';
import  SearchComponent  from './header/search';

@Component(
  selector: 'my-app',
  template: `
    <app-header></app-header>
  `,
)
export class App 
  name:string;
  constructor() 
  


@NgModule(
  imports: [ BrowserModule ],
  declarations: [ App, HeaderComponent, SearchComponent ],
  bootstrap: [ App ]
)
export class AppModule 

header.ts

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

@Component(
  selector: 'app-header',
  template: `<header>
              <app-search [getSearchStatus]="isSearchActive"></app-search>
              <button (click)="handleSearch()">Open Search</button>
            </header>`
)
export class HeaderComponent implements OnInit 
  isSearchActive = false;

  handleSearch() 
    this.isSearchActive = true
    console.log(this.isSearchActive)
  

  constructor()  
  ngOnInit()  

header/search.ts

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

@Component(
  selector: 'app-search',
  template: `<div id="search" [class.toggled]="getSearchStatus">
              search 
              <button  (click)="getSearchStatus = false" class="close">Close Search</button>
            </div>`
)
export class SearchComponent implements OnInit 
  @Input() getSearchStatus: boolean;

  constructor()  

  ngOnInit() 

  

请检查上面给出的 plunker。开放式搜索功能只工作一次。关闭搜索后,不再触发。

@input 是否适合这种情况?请帮我解决这个问题。 (请更新插件)。

【问题讨论】:

handleSearch() 中设置为true 之后,你在哪里设置`this.isSearchActive = false;`? in header/search.ts ' 【参考方案1】:

您需要使用 2 路数据绑定。

@Input() 是一种数据绑定方式。 要启用 2 路数据绑定,您需要添加与属性对应的 @Output(),并带有“更改”后缀

@Input() getSearchStatus: boolean;
@Output() getSearchStatusChange = new EventEmitter<boolean>();

当您要将对您的属性所做的更改发布给父级时,您需要通知父级:

this.getSearchStatusChange.emit(newValue)

并且在父级中,您需要对该属性使用香蕉盒中的表示法:

[(getSearchStatus)]="myBoundProperty"

您还可以绑定到属性并在子项发生更改时触发回调:

[getSearchStatus]="myBoundProperty" (getSearchStatusChange)="myCrazyCallback($event)"

见plnkr

【讨论】:

感谢您的回复。你能更新我的 plunker 吗? 这将为与使用 @Output() 相同的行为增加额外的工作。这听起来像是重新设计***。 @RobertVangor 使用 ReactiveForms 时,即使我的子属性标记为 public,我也无法使用“香蕉盒”方法并得到错误,即它不是组件的已知属性...绑定不过,只有(propertyChanged)="setParentProp($event)" 工作得很好。 我无法回答您的问题,因为它应该有自己的帖子。您的问题是您在父母的更改检测周期之后立即发出更改。换句话说,您已经设法进行更改检测以触发一些 Angular 不允许的更改。 @manoj @Chandrakant 不,要使用香蕉盒语法,您必须使用更改后缀。对于自定义输出,您可以随意命名。 Banana box 只是一种非常愚蠢的语法糖,被许多人误用【参考方案2】:

稍微编辑了您的代码,它可以工作并且在 imo 中看起来更简单。喜欢就告诉我吧。

https://plnkr.co/edit/oJOjEZfAfx8iKZmzB3NY?p=preview

【讨论】:

谢谢。我想从搜索组件更新父属性。这是我的用例。 @Body 很好,但是你应该考虑使用我修改按钮和点击机制的方式,以及 n00dl3 解决方案。【参考方案3】:

另一种方法:使用 rxjs/BehaviorSubject 在不同组件之间传递状态。 这是plunkr。 我用后缀“Rxx”命名主题,因此 searchStatus 的 BehaviorSubject 将是 searchStatusRxx。

    searchStatusRxx = new BehaviorSubject(false);这样的父组件中初始化, 使用@Input 将其传递给子组件 在子模板中,您执行异步管道。 在父母和孩子中,您都可以通过searchStatusRxx.next(value) 更改最新值。

【讨论】:

【参考方案4】:

另一种方式。 Plunkr。我们想要的是单一的事实来源。这次我们可以把它放在孩子身上。

在孩子中初始化:searchStatus = false 在父模板中,以#as 或任何名称获取子实例。 使用#as.searchStatus 更改父级和子级this.searchStatus 中的searchStatus。

【讨论】:

这种方式更好更简单。这是一种有效的方法吗?为什么 Angular 不推广这种方法?一周以来,我一直在寻找解决方案,并且到处都找到了输入/输出案例。 我们称之为“模板引用变量”方式。这似乎很简单。但是测试起来可能有点困难,并且父/子组件耦合在一起,这可能不是一件好事。个人更喜欢 BehaviorSubject 的方式,更容易测试和解耦,可以设置为父子间传递的复杂对象的属性。旁注:angular 的 eventEmitter 是幕后的 Subject。

以上是关于从Angular 2中的子组件更新父组件属性的主要内容,如果未能解决你的问题,请参考以下文章

如何从Angular 2中的子组件事件触发父组件中的本地引用?

子组件中的 Angular 2 ngModel 更新父组件属性

Angular 2 @Input - 如何从父组件绑定子组件的 ID 属性?

从 Angular 中的 @Input 更新 ngOnChanges 视图

如何从 React 中的子组件更新父组件(功能)

如何使用从 React 中的子组件获取的数据更新父组件中的状态