【问题标题】:Angular2: child component access parent class variable/functionAngular2:子组件访问父类变量/函数
【发布时间】:2016-03-16 00:53:09
【问题描述】:

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

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");
    }
}

【问题讨论】:

  • 我想知道我们是否应该开始以不同的方式标记 Angular2“alpha”解决方案,这样现在开始使用它的人就不会感到困惑了。这显然是与“@View”过时的。想法?
  • 对我来说很有意义。我自己对 SO 的答案感到困惑,最终意识到它已经很久了

标签: angular


【解决方案1】:

像 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 并提供列表而不是组件)。当然,也许你想要整个组件,但我正是在这种情况下,我有一个子组件,它只需要访问父组件的“报告”属性
  • 我收到一个错误:在声明之前使用了“父级”类。如果要将提供程序移动到另一个文件,则它会显示:检测到循环依赖中的警告
【解决方案2】:

你可以这样做 在父组件中声明:

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

【讨论】:

  • 虽然接受的答案是更棱角分明的方式(并且更精简),但可能有些人正在开发一个非常规的应用程序并希望完全访问父上下文。我会为此建议这种方法 - 特别是如果您的父组件有很多您想要使用的成员变量和函数。
  • 我知道在某些情况下可能需要这种方法,但这可以归类为反模式还是 Angular 2+ 中的常见做法?
【解决方案3】:

Angular2 文档中关于这个主题的主要文章是:

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

它涵盖以下内容:

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

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

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

  • 家长监听子事件

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

  • Parent 调用 ViewChild

  • 父母和孩子通过服务进行交流

【讨论】:

  • 感谢您分享这个有用的链接。这是非常有用和全面的。
【解决方案4】:

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

在父模板中:

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

在孩子身上:

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

如果您想在构建子项时将项目添加到列表中,请使用 ngOnInit() 挂钩(不是构造函数(),因为此时未初始化数据绑定属性):

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

这个Plunker shows a working example,在父组件和子组件中都有按钮,它们都修改了共享列表。

请注意,您不得在子项中重新分配引用。例如,不要在子组件中这样做:this.aList = someNewArray; 如果这样做,那么父组件和子组件将各自引用两个不同的数组。

如果你想共享一个原始类型(即字符串、数字、布尔值),你可以把它放入一个数组或一个对象中(即,把它放在一个引用类型中),或者你可以emit()一个事件每当原始值发生变化时,来自子级(即,让父级侦听自定义事件,子级将具有EventEmitter 输出属性。有关更多信息,请参阅@kit 的答案。)

更新 2015/12/22:Structural Directives 指南中的 heavy-loader 示例使用了我上面介绍的技术。主/父组件有一个绑定到子组件的logs 数组属性。子组件push() 放到该数组上,父组件显示该数组。

【讨论】:

  • 我不知道这种方法,但是它不适用于例如。字符串。 @mark-rajcok 你能看看我的plunker
  • @kit,您的链接似乎是我的 plunker 的链接。但是无论如何......像这样在父子之间共享字符串是行不通的(在子->父方向上),因为子具有本地原始类型,而不是本地引用类型。对于原始类型,父级和子级都有自己的(字符串的)副本——这就是 JavaScript 的工作原理……我们不能创建对原始类型的引用。尽管父级会强制将新的字符串值向下传递给子级,但父级没有引用子级的字符串属性,因此它不会注意到任何子级的更改。
  • 明确一点:如果我想使用@Input 在子组件和父组件之间共享字符串变量,我只需使用原始字符串 new String("myValue") 的包装器,一切正常.
  • @user59442,使用您的方法,您将如何更改子项中的字符串值,并将其反映在父项中?
  • 在模板HTML中使用根据当前路由指定子组件(页面)时,如何在父子组件之间共享数据?
【解决方案5】:

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-02-02
  • 1970-01-01
  • 2011-04-08
  • 2017-09-28
  • 1970-01-01
  • 2017-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多