按边列表中的选择顺序进行角度显示层次结构选择

时间:2018-08-20 22:43:08

标签: javascript html angular typescript hierarchy

我正在尝试实现一些功能,这些功能将按照选择的顺序在另一侧的另一侧显示“ TreeNode”层次结构中的选择。 我发现了这个类似的东西:  http://next.plnkr.co/edit/1Fr83XHkY0bWd9IzOwuT?p=preview&utm_source=legacy&utm_medium=worker&utm_campaign=next&preview

在当前方法中,我使右侧列表的层次结构顺序与左侧列表相同,而不是选择顺序。

例如:即使在列表中,在节点“ A”之前选择节点“ B”,它仍然会先显示A,然后显示B(因为在所显示的层次结构中A在B之上)。

Rightside.component.html:

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  <ul class="selection-list">
    <li *ngFor="let item of getSelections()">
      <button class="btn" (click)="deselect(item)" *ngIf="item.selected">
        <i class="fa fa-close"> {{ item.displayName }} </i>
      </button> 
    </li>
  </ul>

rightside.component.ts:

import { Component, Input, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { DataService } from '../../shared/service/data.service';
import { TreeNode } from '../../shared/dto/TreeNode';

import html from './rightside.component.html';
import css from './rightside.component.css';

@Component({
  selector: 'rightside-component',
  template: html,
  providers: [DataService],
  styles: [css],
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class RightSideComponent implements OnInit {
  selections: string[];
  @Input() treeNode: TreeNode<string>[];

  constructor(private cd: ChangeDetectorRef) {}

  ngOnInit() {
  }

  getSelections() : TreeNode<string>[] {
    if (typeof(this.treeNode) == "undefined" || (this.treeNode) === null) {
      return [];
    }
    return this.treeNode;
  }

  deselect(item: TreeNode<string>): void {
    if((item.children) !== null) {
      item.children.forEach(element => {
        this.deselect(element);
      });
    }
    item.selected = false;
  }

}

productline.component.html:

<p>Productlines</p>
<mat-input-container>
    <input #searchInput matInput placeholder="Search for Product Line">
</mat-input-container>
<div class="flex-container">
<div class="PLCheck" *ngIf="isDataLoaded">
    <fortune-select
       (dataChanged)="onDataChange($event)"
       [searchTerm]="searchInput.value"
       [currentNode]="tree"
       [singleSelect]="singleSelect"
       [collapsed]="true"></fortune-select>
</div>
<div class="sendToRight">
    <rightside-component
        [treeNode]="selectedProductLine">
    </rightside-component>
</div>
</div>

Productline.component.ts:

import { Component, Input, OnInit, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import * as API from '../../shared/api-routes';
import { DataService } from '../../shared/service/data.service';
import { ValidationService } from '../../shared/service/validation.service';
import { Subject } from 'rxjs/Subject';
import { BasestepComponent } from '../basestep-component/basestep.component';
import { TreeNode } from '../../shared/dto/TreeNode';

import html from './productline.component.html';
import css from './productline.component.css';

@Component({
  selector: 'productline-component',
  template: html,
  providers: [DataService],
  styles: [css],
  changeDetection: ChangeDetectionStrategy.OnPush
})

export class ProductlineComponent extends BasestepComponent<string> implements OnInit {
  selectedProductLine:    TreeNode<string>[];

  constructor(dataService:DataService, cd:ChangeDetectorRef) {
    super(dataService, cd);
  }

  ngOnInit() {
    this.subject.subscribe((productline) => this.productLineChange(productline));
  }

  public productLineChange(productLine: TreeNode<string>[]):void {
    this.selectedProductLine = productLine;
  }

}

Basestep.component.ts:

import { Input, ChangeDetectorRef } from '@angular/core';
import { castTree, ReportTemplate } from '../report-common';
import { DataService } from '../../shared/service/data.service';
import { Subject } from 'rxjs/Subject';
import { ValidationService } from '../../shared/service/validation.service';
import { TreeNode } from '../../shared/dto/TreeNode';

export class BasestepComponent<T> {
  public tree: TreeNode<T>;
  public singleSelect: boolean = false;
  public isDataLoaded: boolean;
  public template: ReportTemplate;
  @Input() templateSubject: Subject<ReportTemplate>;
  @Input() subject: Subject<TreeNode<T>[]>;

  constructor(private dataService:DataService, private cd: ChangeDetectorRef) {}

  public onDataChange(event:TreeNode<T>[]):void {
    if (!ValidationService.isNullOrUndefined(this.subject)) {
      this.subject.next(event);
    }
  }


  public markForCheck() {
    this.cd.markForCheck();
  }

  public reset() {
    this.tree = null;
    this.isDataLoaded = false;
    this.markForCheck();
  }
}

fortune-select.component.ts:

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { TreeNode } from './../dto/TreeNode';

import html from './fortune-select.component.html';
import css from './fortune-select.component.css';

@Component({
  selector: 'fortune-select',
  template: html,
  styles: [css],
})

export class FortuneSelectComponent<T> {
  @Input() currentNode:  TreeNode<T>;
  @Input() collapsed:    boolean = false;
  @Input() linked:       boolean = true;
  @Input() searchTerm:   string  = '';
  @Input() singleSelect: boolean = false;
  @Output() dataChanged          = new EventEmitter<TreeNode<T>[]>();

  selectedRadioValue:T;

  public checkboxChangedEvent():void {
    let list:TreeNode<T>[];
    this.currentNode.indeterminate = true;

    if (this.linked) {
      list = TreeNode.getTopLevelCheckedNodes(this.currentNode);
    } else {
      list = TreeNode.getAllCheckedNodes(this.currentNode);
    }

    this.dataChanged.emit(list);
  }

  public radioChangedEvent(event:TreeNode<T>):void {
    this.dataChanged.emit([event]);
  }
}

TreeNode.ts:

import { ValidationService } from '../service/validation.service';

export class TreeNode<T> {
  displayName:   string;
  children:      TreeNode<T>[];
  selected:      boolean;
  collapsed?:    boolean;
  indeterminate: boolean;
  selectable:    boolean;
  value:         T;

  public static getAllNodeValues<T>(tree: TreeNode<T>):T[] {
    return TreeNode.getAllCheckedNodes<T>(tree).map((nodes:TreeNode<T>) => nodes.value);
  }

  public static getTopLevelNodeValues<T>(tree: TreeNode<T>):T[] {
    return TreeNode.getTopLevelCheckedNodes<T>(tree).map((nodes:TreeNode<T>) => nodes.value);
  }

  public static getTopLevelCheckedNodes<T>(tree: TreeNode<T>):TreeNode<T>[] {
    if(tree.selected) {
      return [tree];
    } else if(tree.indeterminate) {
      return tree.children.reduce(
        (acc,child) => acc.concat(TreeNode.getTopLevelCheckedNodes(child)),[]);
    } else {
      return <TreeNode<T>[]>[];
    }
  }

  public static getAllCheckedNodes<T>(tree: TreeNode<T>):TreeNode<T>[] {
    if(tree.selected && tree.children) {
      return tree.children.reduce(
        (acc,child) => acc.concat(TreeNode.getAllCheckedNodes(child)),[tree]);
    } else if (tree.selected) {
      return [tree];
    } else if(tree.children) {
      return tree.children.reduce(
        (acc,child) => acc.concat(TreeNode.getAllCheckedNodes(child)),[]);
    } else {
      return <TreeNode<T>[]>[];
    }
  }

  public getValue(): T {
    return this.value;
  }

  public matches(searchTerm:string):boolean {
    if(this.displayName.toLowerCase().includes(searchTerm.toLowerCase())) {
      return true;
    }
    if (!ValidationService.isEmptyList(this.children)) {
      return this.children.some((child) => child.matches(searchTerm));
    }
    return false;
  }

  public selectChildren(selected:boolean):void {
    if (!ValidationService.isEmptyList(this.children)) {
      this.children.map((child) => {
        child.selected = selected;
        child.indeterminate = false;
        child.selectChildren(selected);
      });
    }
  }
}

我希望右边的顺序与选择项目的顺序相同,而不是基于层次结构。因此,即使A在层次结构中高于B,我也希望显示B,然后根据选择显示A。

例如:https://stackblitz.com/angular/mjgkvlymlyp?file=app%2Ftree-checklist-example.ts

在这种情况下,正在使用材料树。如果要在“有机鸡蛋”(在杂货店下)之前打印“蛋白粉”,该怎么办?我的代码中需要类似的内容,但是,我有自己的树结构。

基本上,我希望选择项按照选择的顺序动态显示。

有没有一种方法可以将每个选择存储在列表中,然后仅显示列表?这样,它将按顺序显示选择。现在,整个结构都在遍历,因此按树的顺序显示。

有没有办法做到这一点?

0 个答案:

没有答案