如何从子组件更改父变量?

Posted

技术标签:

【中文标题】如何从子组件更改父变量?【英文标题】:How to change parent variable from children component? 【发布时间】:2017-05-30 21:38:42 【问题描述】:

这个问题很简单,但我无法摆脱它。

我在父模板中有一个<header>,当通过路由模块显示子模板时我需要它消失。我期望的是在标题标签中添加一个类,这样我就可以通过 CSS 隐藏它。这就是我所拥有的:app.component.ts

import  Component  from '@angular/core';
@Component(
  selector: 'app',
  template: `
    <header [class.hidden]="hide">
      <h1>My App</h1>
      <ul>
            <li><a href="/home"></a></li>
            <li><a href="/showoff"></a></li>
      </ul>
    </header>
    <router-outlet></router-outlet>
  `
)

export class AppComponent 
  hide = false; // <-- This is what I need to change in child component

app-routing.module.ts

import  RouterModule, Routes  from '@angular/router';

import  HomeComponent  from './welcome.component';
import  ShowOffComponent  from './show.off.component';

const routes: Routes = [
   path: '', component: HomeComponent ,
   path: 'showoff', component: ShowOffComponent ,
];

export const AppRouting = RouterModule.forRoot(routes, 
  useHash: true
);

show.offf.component.ts

import  Component  from '@angular/core';
@Component(
   selector: 'app-showoff',
   template: `
       <h2>Show Off</h2>
       <div>Some contents...</div>
   `
)

export class ShowOffComponent 
   hide = true; // <-- Here is the problem.
                // I don't have any idea how to reach parent variables.

【问题讨论】:

【参考方案1】:

您可以使用output emitter

在您的子组件中,

import  Component  from '@angular/core';
@Component(
   selector: 'app-showoff',
   template: `
       <h2>Show Off</h2>
       <div>Some contents...</div>
   `
)

export class ShowOffComponent 
    @Output() onHide = new EventEmitter<boolean>();
    setHide()
       this.onHide.emit(true);
    

在父级中,

export class AppComponent 
  hide = false;

  changeHide(val: boolean) 
    this.hide = val;
  

使用该事件发射器向父级添加一个子级,

<app-showoff (onHide)="changeHide($event)"></app-showoff>

【讨论】:

对于更复杂的场景,你可以做一个服务('LayoutService')并在那里创建一个 EventEmitter,所以你可以在任何地方使用这个 Event 来处理任何组件。 对.. 根据文档,父子通信的方式有很多,具体取决于具体情况。 谢谢,但在这种情况下,父组件上的 onHide() 参数不起作用。我已经在setHide()onHide() 上使用简单的警报对其进行了测试。当(click) 处理程序触发时,只有setHide() 显示警报。然后我发现在我找到 [this] (***.com/questions/35878762/…) 之后,我意识到这不能使用路由模块来实现。 ok.. 所以你需要使用公共服务。 here 嗯,它有效!但是,为了使服务正常工作,它要求我在 router-outlet 内定义&lt;app-showoff [onHide]="hide"&gt;&lt;/app-showoff&gt;,这不是很好,因为即使我更改路由,它也会使模板仍然存在。此外,使用服务是实现这一点的更复杂的方式,因为我只需要将变量设置为真/假,而不是双向通信。【参考方案2】:

在您的app.component.ts 中,您可以检查您的网址并设置hide 变量值如下:

import  Component  from '@angular/core';
import  Router, NavigationStart  from '@angular/router';

@Component(
  selector: 'app',
  template: `
    <header [class.hidden]="hide">
      <h1>My App</h1>
      <ul>
            <li><a href="/home"></a></li>
            <li><a href="/showoff"></a></li>
      </ul>
    </header>
    <router-outlet></router-outlet>
  `
)

export class AppComponent 
  hide = false; // <-- This is what I need to change in child component

  constructor(private router: Router)

  public ngOnInit() 
    this.router.events.subscribe((events) => 
      if (events instanceof NavigationStart) 
        if (events.url === '/' || events.url === '/home') 
          this.hide = false;
         else 
          this.hide = true;
        
      
    );
  


【讨论】:

【参考方案3】:

我最近在使用 Angular 6 时遇到了同样的现象。

我想访问和更改属于父组件或祖父组件的变量。见下图。我想从 Jim(Tom 的孩子)和 Sara(Tom 的孙子)访问和更改属于 Tom 的变量。

可能还有其他一些解决方案,但我用来克服这个问题的方法是使用ViewContainerRef。我必须将ViewContainerRef 注入到子组件的构造函数中,我需要访问父组件并遍历父节点(或多个节点)以找到父变量。

注入构造函数,

constructor(private viewContainerRef: ViewContainerRef)  

访问并遍历到父节点,

getParentComponent() 
    return this.viewContainerRef[ '_data' ].componentView.component.viewContainerRef[ '_view' ].component

我用上图中给你的场景制作了一个 StackBlitz 示例。

https://stackblitz.com/edit/angular-comms

希望有人会觉得这很有用。

谢谢。

【讨论】:

我刚遇到这个问题,感谢修复!你为我节省了不少时间! @JacquesOlivier 我很高兴你发现我的回答很有帮助:) @AnjanaSilva 角度 12 不起作用。请在此处分享该解决方案。我有componentView undefined 控制台错误。【参考方案4】:

不那么直接,但(恕我直言)更准确的方法是使用服务。

    创建 parent-to-child.service.ts 文件并创建主题属性

    导出类 ParentToChildService showHeader = 新主题();

    通过构造函数在父组件和子组件中注入它:

    构造函数(私有 ptcService: ParentToChildService)

    用 ngIf(或者你可以使用 ngClass,如果你坚持使用 CSS 方法)将 header 组件绑定到其 TS 文件中的属性:

html&lt;header *ngIf="showStatus"&gt; TS:showStatus: boolean = true; // true by default ptcSubscription: Subscription;

    在标头组件的 ngInit 上订阅该主题:

    ngOnInit(): this.ptcSubscription = this.ptcService.showHeader.subscribe( (newStatus: boolean) => this.showStatus = newStatus ); );

    在您的子组件中,当您需要隐藏&lt;header> 时,请在服务主题上调用next

    this.ptcService.showHeader.next(false); //隐藏标题

【讨论】:

以上是关于如何从子组件更改父变量?的主要内容,如果未能解决你的问题,请参考以下文章

将变量从子组件传递到父组件

如何将变量的值从子组件发送到父组件?

将一个变量的值从子组件传递给两个父组件,vuejs? nuxt

如何在 nuxt.js 上从子组件获取父组件的值?

为啥Vue会更新父级中的变量-未使用事件

使用自定义事件从子组件更改变量的状态