Angular2:子组件访问父类变量/函数


72

我在父组件中有一个变量,子组件可能会更改它,而父组件将在视图中使用此变量,因此必须传播更改。

import {Component, View} from 'angular2/core';

@Component({selector: 'parent'})
@View({
    directives: [Child],
    template: `<childcomp></childcomp>`
})
class Parent {
    public sharedList = new Array();
    constructor() {
    }
}


@Component({selector: 'child'})
@View({template: `...`})
class Child {
    constructor() {
        //access 'sharedList' from parent and set values
        sharedList.push("1");
        sharedList.push("2");
        sharedList.push("3");
        sharedList.push("4");
    }
}

12
我想知道我们是否应该开始以不同的方式标记Angular2“ alpha”解决方案,以使开始使用Angular2的人们不会感到困惑。显然,此日期标有“ @View”。有想法吗?
Todd W Crone

1
对我来说很有意义。我一直对自己在SO上的答案感到困惑,并最终意识到它已经很久了
Saurabh Tiwari

Answers:


70

如果您将输入属性数据绑定与JavaScript引用类型(例如,对象,数组,日期等)一起使用,则父级和子级都将具有对同一对象/一个对象的引用。您对共享库所做的任何更改对父级和子级都可见。

在父母的模板中:

<child [aList]="sharedList"></child>

在孩子中:

@Input() aList;
...
updateList() {
    this.aList.push('child');
}

如果要在构造子项时将项目添加到列表中,请使用ngOnInit()钩子(而不是Constructor(),因为此时未绑定数据绑定的属性):

ngOnInit() {
    this.aList.push('child1')
}

Plunker显示了一个工作示例,在父组件和子组件中的按钮均修改了共享列表。

请注意,在孩子中,您不得重新分配参考。例如,不要在子级中执行此操作: this.aList = someNewArray; 如果这样做,则父级和子级组件将分别引用两个不同的数组。

如果要共享基本类型(例如,字符串,数字,布尔值),则可以将其放入数组或对象中(例如,将其放入引用类型中),也可以emit()在原始对象出现时从孩子那里获得一个事件值更改(即,让父级监听自定义事件,而子级则具有EventEmitteroutput属性。有关更多信息,请参见@kit的答案。)

2015年12月22日更新:《结构指令》指南中的heavy-loader示例使用了我上面介绍的技术。主/父组件具有绑定到子组件的array属性。子组件位于该阵列上,父组件显示该阵列。logspush()


我不知道这种方法,但是它不适用于例如。字符串。@ mark-rajcok您能检查一下我的矮人车吗
套件

1
@kit,您的链接似乎是指向我的朋克的链接。但是无论如何...在父级和子级之间共享这样的字符串将不起作用(在子级->父级方向上),因为子级具有本地基本类型,而不是本地引用类型。对于基本类型,父级和子级都有自己的副本(字符串的副本),这就是JavaScript的工作方式……我们无法创建对基本类型的引用。尽管父级会将新的字符串值强加给子级,但父级没有引用该子级的string属性,因此它不会注意到任何子级更改。
Mark Rajcok

明确说明:如果我想使用@Input在子组件和父组件之间共享字符串变量,则只需使用原始字符串new String(“ myValue”)的包装器,一切就可以正常进行。
约翰内斯

@ user59442,使用您的方法,如何更改子级中的字符串值,并将其反映在父级中?
Mark Rajcok '16

1
在模板HTML中使用<router-outlet>来基于当前路由指定子组件(页面)时,如何在父组件和子组件之间共享数据?
维尔恩·詹森,2016年

20

像NgModel这样的小技巧会如何处理NgForm?您必须将父母注册为提供者,然后将父母加载到孩子的构造函数中。

这样,您不必放下[sharedList]所有的孩子。

// Parent.ts
export var parentProvider = {
    provide: Parent,
    useExisting: forwardRef(function () { return Parent; })
};

@Component({
    moduleId: module.id,
    selector: 'parent',
    template: '<div><ng-content></ng-content></div>',
    providers: [parentProvider]
})
export class Parent {
    @Input()
    public sharedList = [];
}

// Child.ts
@Component({
    moduleId: module.id,
    selector: 'child',
    template: '<div>child</div>'
})
export class Child {
    constructor(private parent: Parent) {
        parent.sharedList.push('Me.');
    }
}

然后你的HTML

<parent [sharedList]="myArray">
    <child></child>
    <child></child>
</parent>

您可以在Angular文档中找到有关此主题的更多信息:https : //angular.io/guide/dependency-injection-in-action#find-a-parent-component-by-injection


是“笨拙”还是适合“角度做事”?我想我喜欢它(特别是如果将ParentProvider重命名为SharedListProvider并提供列表而不是组件)。当然,也许您需要整个组件,但是我正处于这种情况下,而我的子组件仅需要访问父级的“报告”属性
Simon_Weaver

我收到一个错误:声明前使用了“父类”。如果要将提供者移动到另一个文件,则它说:警告:检测到循环依赖关系
伊戈尔(Igor)

13

您可以在父组件中声明:

get self(): ParenComponentClass {
        return this;
    }

在子组件中,包括ParenComponentClass的导入后,声明:

private _parent: ParenComponentClass ;
@Input() set parent(value: ParenComponentClass ) {
    this._parent = value;
}

get parent(): ParenComponentClass {
    return this._parent;
}

然后在父模板中,您可以执行

<childselector [parent]="self"></childselector>

现在,您可以从孩子使用以下方法访问父项的公共属性和方法

this.parent

1
尽管公认的答案是更棱角分明的方式(并且更加精简),但有些人可能正在开发非常规应用程序并希望完全访问父上下文。我为此建议使用这种方法-尤其是在您的父组件具有大量要使用的成员变量和函数的情况下。
babycakes

我了解在某些情况下可能需要使用此方法,但是可以将其归类为反模式吗,或者这是Angular 2+中的常见做法?
Sharath

3

基本上,您不能直接从父级访问变量。您通过事件来执行此操作。组件的输出属性对此负责。我建议阅读https://angular.io/docs/ts/latest/guide/template-syntax.html#input-and-output-properties


1
尽管这不是官方文档,但我也发现此文章很有用:sitepoint.com/angular-2-components-inputs-outputs
user2428107

谢谢!只需要简单的提醒就可以查看ng2主站点上的Output:angular.io/docs/ts/latest/api/core/index/Output-var.html-非常简单。
卫理公会


您对此特定问题有完整的解决方案吗?现在尚不清楚在这里发出事件如何有帮助
Simon_Weaver


3

Angular2文档中有关此主题的主要文章是:

https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#parent-to-child

它涵盖以下内容:

  • 使用输入绑定将数据从父级传递到子级

  • 用设置器截取输入属性的更改

  • 使用ngOnChanges拦截输入属性更改

  • 家长听孩子活动

  • 父母通过局部变量与孩子互动

  • 父母称一个ViewChild

  • 父母与子女通过服务进行沟通


感谢您分享这个有用的链接。这是非常有益和全面的。
hamed
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.