从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 属性?