Angular 8 组件嵌套在同一个组件事件发射器内

Posted

技术标签:

【中文标题】Angular 8 组件嵌套在同一个组件事件发射器内【英文标题】:Angular 8 component nested inside the same component event emitter 【发布时间】:2020-09-17 11:38:16 【问题描述】:

我使用了嵌套在同一个组件内的组件。当我更改正确调用的父组件附加函数中的复选框并且事件发射器工作正常但是当我更改子复选框时附加函数被触发但事件发射器不可用(据我所知,从来没有与孩子绑定)。当我更改子项中的复选框时,我想发出数据。

如果有人知道答案,请帮我解决这个问题。使用嵌套在同一个组件中的组件的术语是什么?

谢谢

这是 stackblitz 链接https://stackblitz.com/edit/angular-material-normal-tree (请查看控制台)

tree.component.ts

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

@Component(
  selector: 'app-tree',
  templateUrl: './tree.component.html',
  styleUrls: ['./tree.component.css'],
)

export class TreeComponent 
  @Input() treeData: any;
  @Output() toggleEmitter: EventEmitter<any> = new EventEmitter();

  constructor() 

  toggleChild(node) 
    console.log('from tree start');
    console.log(node);
    console.log('from tree end');
    this.toggleEmitter.emit(node);
    // if ('children' in node && node.children.length) 
    //   node.isExpand = !node.isExpand;
    // 
  

  test(node, i) 
    node.parentIndex = i;
    console.log(node);
    // this.toggleEmitter.emit(node);
  

  CBchangeEvent(node) 
    console.log(node);
    this.toggleEmitter.emit(node);
  


tree.component.html

<ul *ngIf="treeData">
    <li *ngFor="let node of treeData;let i = index;">
        <button mat-icon-button="" mattreenodetoggle="" class="mat-icon-button" (click)="toggleChild(node)">
        <span class="mat-button-wrapper">
          <mat-icon class="mat-icon material-icons" role="img" aria-hidden="true"> 
            node.isExpand != 0 ? 'expand_more' : 'chevron_right' 
          </mat-icon>
        </span>
      </button>
        <mat-checkbox class="checklist-leaf-node" (change)="CBchangeEvent(node)">node.name</mat-checkbox>
        <app-tree *ngIf="node.isExpand" [treeData]="node.children" (toggleEmitter)="test(node,i)"></app-tree>
    </li>
</ul>

tree.component.css

ul 
    list-style-type: none !important;

tree.module.ts

import  NgModule  from '@angular/core';
import  CommonModule  from '@angular/common';
import  TreeComponent  from './tree.component';
import 
  MatIconModule, MatCheckboxModule, MatFormFieldModule, MatButtonModule
 from '@angular/material';


@NgModule(
  imports: [
    CommonModule,
    MatIconModule, 
    MatCheckboxModule, 
    MatFormFieldModule, 
    MatButtonModule
  ],
  declarations: [TreeComponent],
  exports: [TreeComponent]
)
export class TreeModule 
  static forRoot() 
    return 
      ngModule: TreeModule
    
  

app.component.ts

import  Component  from '@angular/core';

@Component(
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
)
export class AppComponent  
  myData = [
    'id':1, 'name':'Main 1','isExpand':false,
     'children':[
       'id':1, 'name':'Child 1', 'isExpand':false,
       'children':[
         'id':2, 'name':'Test2','isExpand':false
       ]
       
     ] 
    ,
    
      'id':2, 'name':'Main 2','isExpand':false
    
  ]

  test(node) 
    console.log('from app start');
    console.log(node);
    console.log('from app end');
    if ('children' in node && node.children.length) 
      node.isExpand = !node.isExpand;
    
  

app.component.html

<app-tree [treeData]='myData' (toggleEmitter)="test($event)"></app-tree>

app.module.ts

import  NgModule  from '@angular/core';
import  BrowserModule  from '@angular/platform-browser';
import  FormsModule  from '@angular/forms';
import  BrowserAnimationsModule  from '@angular/platform-browser/animations';
import  TreeModule  from './tree/tree.module';
import 
  MdToolbarModule,
  MdTabsModule,
  MdButtonModule,
  MdInputModule,
  MdDatepickerModule,
  MdNativeDateModule,
  MdCheckboxModule,
  MdRadioModule,
  NoConflictStyleCompatibilityMode
 from '@angular/material';

import  AppComponent  from './app.component';

@NgModule(
  imports:      [ BrowserModule, FormsModule, BrowserAnimationsModule, MdToolbarModule, MdTabsModule, MdButtonModule, MdInputModule, MdDatepickerModule, MdNativeDateModule, MdCheckboxModule, MdRadioModule, TreeModule, NoConflictStyleCompatibilityMode ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
)
export class AppModule  

【问题讨论】:

这可能是相关的:***.com/questions/37746516/… @BerkKurkcuoglu 这与我的问题无关。谢谢 嘿@cfprabhu,你在tree-component.html中使用app-tree标签吗? tree-component.html 标签再次附加到 app-tree 组件。我不会做一个无限循环吗? 哦,我得到它更像是递归构建树。 嘿@cfprabhu 你已经在下面的函数 test(node, i) node.parentIndex = i; 中注释掉了发出代码控制台.log(节点); // this.toggleEmitter.emit(node); 【参考方案1】:

您应该在子组件中绑定“toggleChild”,而不是使用“test”。

改变

<app-tree *ngIf="node.isExpand" [treeData]="node.children" (toggleEmitter)="test(node,i)"></app-tree>

<app-tree *ngIf="node.isExpand" [treeData]="node.children" (toggleEmitter)="toggleChild(node,i)"></app-tree>

【讨论】:

没有兄弟。这是不对的。再次阅读我的问题并选中复选框 对不起,我的错。所以你想要的是当子节点(例如你的数据中的“child1”)被切换时,应该用它的值发出事件? ***.com/questions/62093782/… 在子节点中,您将方法与外部节点值绑定。 (toggleEmitter)="test(node,i)" 你不能在这里使用 $event 来获取子节点的值。类似 (toggleEmitter)="test($event,i)" 或 test($event,node,i)? 我在测试 this.toggleEmitter.emit(node); // 第 30 行,将值从 (toggleEmitter)="test(node,i)" 更改为 (toggleEmitter)="test($event,i)" 并且能够一直获取子节点的值,直到 app 组件.如果您不希望递归地发出事件,那么您可以留下评论并对测试中的子节点值做任何您想做的事情。【参考方案2】:

Event Emitter 就是这样工作的

父母将数据传递给孩子

Child 发出何时让父母知道 Data 已经存在 - 这样 parent 可以调用它的回调函数

对于知道父母已更改日期的孩子

这里发生了数据绑定,就像 *ngif 的工作方式一样 当孩子检查数据时,它总是最新的数据。

子组件 Input() 变量将处于与绑定传递的变量相同的状态。绑定负责更新子 UI - 绑定变量的状态发生变化

【讨论】:

是的,兄弟。我知道工作理念。如果您知道实现我目标的任何替代方法,请告诉我。

以上是关于Angular 8 组件嵌套在同一个组件事件发射器内的主要内容,如果未能解决你的问题,请参考以下文章

如何在动态添加的组件上使用事件发射器?

Angular 组件中的 SSE 发射器传递错误

Angular2事件发射器没有得到处理

Angular 8:组件内部的formControlName下面有多个嵌套级别

Angular 4 - 从子组件调用父方法不起作用

Angular 8 @output EventEmitter不允许发射对象