Angular 2单击事件导致整个组件重新初始化(丢失状态)

时间:2017-01-24 00:41:26

标签: angular events recursion tree

我尝试构建一个简单的树状结构,允许嵌套数据,以便扩展/折叠节点的子节点,最后通过单击元素进行选择。

我遇到的问题是,当我触发click事件以切换显示/隐藏子节点时,顶层组件正在重新初始化并将标志重置为false,因此不会#&# 39; t显示子节点。

以下是所涉及的所有相关代码:

查找-data.interface.ts:

export interface LookupData {
     id: string;
     label: string;
     parentId?: string;
}

查找-modal.component.ts:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { LookupData } from './lookup-data.interface';

@Component({
    selector: 'lookup-modal',
    host: {
        '(window:keydown)': 'handleKeyPress($event)'
    },
    templateUrl: '/app/shared/lookup-modal/lookup-modal.component.html',
    styleUrls: ['./app/assets/css/modal.css']
})
export class LookupModalComponent {
    constructor() { }

    @Input() label: string = '';
    @Input() data: LookupData[] = [];
    @Output() close: EventEmitter<string> = new EventEmitter<string>();

    search: string = '';

    get topLevelData(): LookupData[] {
        return this.data.filter((item: LookupData): boolean => !item.parentId);
    }

    handleKeyPress(event: any): void {
        if (event && event.keyCode === 27) {
            this.close.emit();
        }
    }
}

查找-modal.component.html:

<div class="modal-backdrop fade in fsi-modal-backdrop"></div>
<div tabindex="-1"
     role="dialog"
     class="modal fade scale up in fsi-modal">
    <div class="modal-dialog modal-lg fsi-modal-dialog">
        <div class="modal-content fsi-modal-content">
            <div class="modal-header fsi-modal-header">
                <button type="button" class="close" (click)="close.emit()">
                    <span>×</span>
                </button>
                <h4 class="modal-title">{{label}}</h4>
            </div>
            <div class="modal-body nopad fsi-modal-body">  
                <input type="search" class="form-control" [(ngModel)]="search" />

                <div style="margin-top: .5rem;">
                    <div *ngFor="let topLevelItem of topLevelData; let i = index;">
                        <lookup-item [item]="topLevelItem"
                                     [data]="data"
                                     [i]="i"
                                     [search]="search"
                                     (selection)="close.emit($event)"></lookup-item>
                    </div>
                </div>
            </div>
            <div class="modal-footer fsi-modal-footer">
                <button class="btn btn-danger pull-left" type="button" (click)="close.emit('')">Clear</button>
                <button class="btn btn-default" (click)="close.emit()">Cancel</button>
            </div>
        </div>
    </div>
</div>

查找-item.component.ts:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { LookupData } from './lookup-data.interface';

@Component({
    selector: 'lookup-item',
    templateUrl: '/app/shared/lookup-modal/lookup-item.component.html'
})
export class LookupItemComponent {
    constructor() { }
    @Input() item: LookupData;
    @Input() i: number;
    @Input() data: LookupData[] = [];
    @Input() search: string = '';
    @Output() selection: EventEmitter<string> = new EventEmitter<string>();

    showChildren: boolean = false;

    // temp/test, not needed
    ngOnInit() {
        if (this.item.id === '1') 
            console.log(this.item.label);
    }

    toggleChildren(): void {
        console.log('toggle');
        this.showChildren = !this.showChildren;
    }

    get children(): LookupData[] {
        return this.data.filter((i: LookupData): boolean => i.parentId === this.item.id);
    }
}

查找-item.component.html:

<div class="row" style="padding: 5px;"
     [ngStyle]="{'border-top': i || item.parentId ? 'none' : '1px solid #eee', 'border-bottom': item.parentId ? 'none' : '1px solid #eee'}">

    <div class="col-xs-1" 
         *ngIf="children.length" 
         style="cursor: pointer; text-align: center;"
         (click)="toggleChildren()">

        <span class="glyphicon"
              [ngClass]="{'glyphicon-triangle-right': !showChildren, 'glyphicon-triangle-down': showChildren}"></span>
    </div>

    <div class="col-xs-11"
         [ngClass]="{'col-xs-offset-1': !children.length}"
         (click)="selection.emit(item.id)"
         style="cursor: pointer;">

        {{item.label}}

        <div *ngIf="showChildren">
            <div *ngFor="let child of children; let j = index;">
                <lookup-item [item]="child"
                             [data]="data"
                             [i]="j"
                             [search]="search"
                             (selection)="selection.emit($event)"></lookup-item>
            </div>
        </div>
    </div>
</div>

所以我的问题是,当(click)事件被触发并在lookup-item组件中调用toggleChildren()时,由于某种原因,ngOnInit()方法再次运行(整个组件重新初始化自己)。这会导致showChildren属性重置为false,即使toggleChildren()方法应将其设置为true,因此子节点永远不会显示。

我已经在这个问题上花了好几个小时,并尝试过研究但是在互联网上的任何地方都没有找到与我的问题相关的内容。

我真的希望有人可以指出我错过的一个明显的错误,因为我此刻非常难过。

提前致谢。

1 个答案:

答案 0 :(得分:3)

所以我只想出这个 - 它与我生成输入数据的方式有关(原始问题中没有显示,因为我认为它最初并不相关) - 而不是将一个实际的数组传入其中我使用的是一个打字稿getter,当我因某种原因试图对数据进行更改时,它迫使它重新初始化。