Javascript 实现trackBy(),以便在过滤后修复expandRow()函数

Javascript 实现trackBy(),以便在过滤后修复expandRow()函数,javascript,html,angular,typescript,angular-material2,Javascript,Html,Angular,Typescript,Angular Material2,运行角度材料2和TS 2.4 概述 目前,我有一个cdk表,它是通过迭代一个JSON[]生成的,我从ThisService检索该表,并根据 此数据源负责通过过滤器异步过滤任何字段的数据 expandRow()显示在生成的窗口中单击的任何行的名称 问题 我遇到的问题与expandRow()的功能有关 在发生任何过滤后。如果筛选栏中有任何内容,expandRow()的索引仍然正确,但显示在扩展行中的名称始终基于未筛选的值数组的索引 我的猜测是,发生这种情况是因为我不知道如何使用trackBy,尽

运行角度材料2和TS 2.4

概述
  • 目前,我有一个cdk表,它是通过迭代一个JSON[]生成的,我从
    ThisService
    检索该表,并根据
  • 此数据源
    负责通过
    过滤器
    异步过滤任何字段的数据
  • expandRow()
    显示在生成的窗口中单击的任何行的名称
问题 我遇到的问题与
expandRow()的功能有关
在发生任何过滤后。如果筛选栏中有任何内容,expandRow()的索引仍然正确,但显示在扩展行中的名称始终基于未筛选的值数组的索引

我的猜测是,发生这种情况是因为我不知道如何使用
trackBy
,尽管我阅读了和其他我无法链接的资源,因为我在StackOverflow上还没有声誉


代码如下:

my.component.ts
从'@angular/core'导入{OnInit};
从'rxjs/operator/filter'导入{filter};
从“rxjs/Observable”导入{Observable};
从“../../models/MyObject”导入{MyObject};
从“@angular/material”导入{MdPaginator};
从'rxjs/BehaviorSubject'导入{BehaviorSubject};
从“../../services/MyService.service”导入{MyService};
从'@angular/cdk'导入{DataSource,CdkTable,CdkRowDef};
从'@angular/Http'导入{Headers,Http,RequestMethod,RequestOptions,Response};
进口{
组件参考,
组件工厂,
查看儿童,
ViewContainerRef,
输入,
组成部分,
组件工厂分解器,
ElementRef,
视图儿童
}从“@angular/core”开始;
导入'rxjs/add/operator/map';
导入“rxjs/add/observable/merge”;
导入'rxjs/add/operator/startWith';
@组成部分({
选择器:“应用程序内联消息”,
模板:“详细信息:{{user}}”,
风格:[`
:主持人{
显示:块;
填充:24px;
颜色:红色;
背景:rgba(0,0,0,0.1);
}
`]
})
导出类InlineMessageComponent{
@Input()用户:字符串;
}
@组成部分({
选择器:'激活此',
templateUrl:“./activate.this.component.html”,
提供者:[此服务],
样式URL:['../../../../../expanding table.css']
})
导出类组件{
displayedColumns=['foo'、'bar'、'qux'、'grault'];
mockDb=新的MockDatabase(this.service);
数据源:MockDataSource | null;
expandedRow:数字;
构造函数(私有服务:MyService,私有解析器:ComponentFactoryResolver){}
@ViewChild(“过滤器”)过滤器:ElementRef;
@ViewChildren('cdkrow',{read:ViewContainerRef})容器:任意;
恩戈尼尼特(){
this.dataSource=新的MockDataSource(this.mockDb);
Observable.fromEvent(this.filter.nativeElement,'keyup')
.debounceTime(100)
.distinctUntilChanged()
.订阅(()=>{
如果(!this.dataSource){return;}
this.dataSource.filter=this.filter.nativeElement.value;
});
}
expandRow(索引:编号){
如果(this.expandedRow!=null){
//清除旧信息
this.containers.toArray()[this.expandedRow].clear();
}
if(this.expandedRow==索引){
this.expandedRow=null;
}否则{
const container=this.containers.toArray()[index];
常量工厂:ComponentFactory=this.resolver.resolveComponentFactory(InlineMessageComponent);
const messageComponent=container.createComponent(工厂);
messageComponent.instance.user=this.mockDb.data[index].foo;
this.expandedRow=索引;
}
}
trackByFilter(索引:任意,项:任意){
收益指数;
}
}
导出类数据库{
myObjects:MyObject[];
/**每当数据被修改时发出的流*/
dataChange:BehaviorSubject=新的BehaviorSubject([]);
获取数据():MyObject[]{返回this.dataChange.value;}
构造函数(私有服务:MyService){
//在本地数据库中填充
service.getAllUnactivatedMyObject().subscribe(myObject=>{
for(让myObject.json()的对象
{this.addUnactivatedmyObject(myObject);}
});
}
//将myObject添加到数据库
添加未激活的myObject(myObject:myObject){
const copiedData=this.data.slice();
复制数据推送(myObject);
this.dataChange.next(复制数据);
}
}
/**
*数据源提供应在表中呈现的数据。请注意,数据源
*可以以任何方式检索其数据。在这种情况下,数据源提供了一个参考
*到一个公共数据库,MockDatabase。数据源不负责管理
*基础数据。取而代之的是,它只需要获取数据并发送表所需的数据
*应该被渲染。
*/
导出类MockDataSource扩展了DataSource{
_filterChange=新行为主体(“”);
get filter():字符串{返回此值。_filterChange.value;}
设置筛选器(筛选器:字符串){this.\u filterChange.next(筛选器);}
构造函数(私有_mockDb:MockDatabase){
超级();
}
/*由表调用的Connect函数,用于检索包含要呈现的数据的一个流*/
/*它只调用一次,不考虑过滤*/
connect():可观察{
const displayDataChanges=[
这个._mockDb.dataChange,
这个.\u过滤器更换,
];
//这是过滤器
返回可观察的.merge(…displayDataChanges).map(()=>{
返回此值。_mockDb.data.slice()
.filter((myObject:myObject)=>{
让searchStr=(myObject.qux+myObject.foo+myOb
import { OnInit } from '@angular/core';
import { filter } from 'rxjs/operator/filter';
import { Observable } from 'rxjs/Observable';
import { MyObject } from '../../models/myObject';
import { MdPaginator } from '@angular/material';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { MyService } from '../../services/myservice.service';
import { DataSource, CdkTable, CdkRowDef } from '@angular/cdk';
import { Headers, Http, RequestMethod, RequestOptions, Response } from '@angular/http';

import {
    ComponentRef,
    ComponentFactory,
    ViewChildren,
    ViewContainerRef,
    Input,
    Component,
    ComponentFactoryResolver,
    ElementRef,
    ViewChild
} from '@angular/core';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/startWith';

@Component({
    selector: 'app-inline-message',
    template: 'Detail: {{ user }} ',
    styles: [`
    :host {
      display: block;
      padding: 24px;
      color: red;
      background: rgba(0,0,0,0.1);
    }
  `]
})

export class InlineMessageComponent {
    @Input() user: string;
}

@Component({
    selector: 'activate-this',
    templateUrl: './activate.this.component.html',
    providers: [ThisService],
    styleUrls: ['../../../../expanding-table.css']
})

export class Component {
    displayedColumns = ['foo', 'bar', 'qux', 'grault'];
    mockDb = new MockDatabase(this.service);
    dataSource: MockDataSource | null;
    expandedRow: number;

    constructor(private service: MyService, private resolver: ComponentFactoryResolver) { }

    @ViewChild('filter') filter: ElementRef;
    @ViewChildren('cdkrow', { read: ViewContainerRef }) containers: any;

    ngOnInit() {

        this.dataSource = new MockDataSource(this.mockDb);

        Observable.fromEvent(this.filter.nativeElement, 'keyup')
            .debounceTime(100)
            .distinctUntilChanged()
            .subscribe(() => {
                if (!this.dataSource) { return; }
                this.dataSource.filter = this.filter.nativeElement.value;
            });
    }


    expandRow(index: number) { 
        if (this.expandedRow != null) {
            // clear old message
            this.containers.toArray()[this.expandedRow].clear();
        }

        if (this.expandedRow === index) {
            this.expandedRow = null;
        } else {
            const container = this.containers.toArray()[index];
            const factory: ComponentFactory<any> = this.resolver.resolveComponentFactory(InlineMessageComponent);
            const messageComponent = container.createComponent(factory);

            messageComponent.instance.user = this.mockDb.data[index].foo;
            this.expandedRow = index;
        }
    }

    trackByFilter(index: any, item: any) {
        return index; 
    }
}

export class MockDatabase {
    myObjects: MyObject[];
    /** Stream that emits whenever the data has been modified. */
    dataChange: BehaviorSubject<MyObject[]> = new BehaviorSubject<MyObject[]>([]);
    get data(): MyObject[] { return this.dataChange.value; }

    constructor(private service: MyService) {

        // Fill up the local database with the 
        service.getAllUnactivatedMyObject().subscribe(myObject => {
            for (let object of myObject.json())
            { this.addUnactivatedmyObject(myObject); }

        });
    }

    // Add a myObject to the database
    addUnactivatedMyObject(myObject: MyObject) {
        const copiedData = this.data.slice();
        copiedData.push(myObject);
        this.dataChange.next(copiedData);
    }

}

/**
 * Data source to provide what data should be rendered in the table. Note that the data source
 * can retrieve its data in any way. In this case, the data source is provided a reference
 * to a common data base, MockDatabase. It is not the data source's responsibility to manage
 * the underlying data. Instead, it only needs to take the data and send the table exactly what
 * should be rendered.
 */
export class MockDataSource extends DataSource<any> {

    _filterChange = new BehaviorSubject('');
    get filter(): string { return this._filterChange.value; }
    set filter(filter: string) { this._filterChange.next(filter); }

    constructor(private _mockDb: MockDatabase) {
        super();
    }

    /* Connect function called by the table to retrieve one stream containing the data to render. */
    /* it is only called once, regardless of filtering */
    connect(): Observable<MyObject[]> {
        const displayDataChanges = [
            this._mockDb.dataChange,
            this._filterChange,
            
        ];
        //here is the filter
        return Observable.merge(...displayDataChanges).map(() => {
            return this._mockDb.data.slice()
                    .filter((myObject: MyObject) => {
                let searchStr = (myObject.qux + myObject.foo + myObject.grault + myObject.bar).toLowerCase();
                return searchStr.indexOf(this.filter.toLowerCase()) != -1;
            });
        });

    }

    disconnect() { }
}
<div class="container">
  <div>
    <h3>Activate MyObjects</h3>
  </div>
  <div class="header">
    <md-input-container floatPlaceholder="never">
      <input mdInput #filter placeholder="Filter myObjects">
    </md-input-container>
  </div>

  <div #insertionPoint></div>
  <cdk-table #table [dataSource]="dataSource" class="example-table">

    <ng-container cdkColumnDef="foo">
      <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Foo </cdk-header-cell>
      <cdk-cell *cdkCellDef="let row;" class="example-cell"> {{row.foo}} </cdk-cell>
    </ng-container>

    <ng-container cdkColumnDef="bar">
      <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Bar </cdk-header-cell>
      <cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.bar}} </cdk-cell>
    </ng-container>

    <ng-container cdkColumnDef="qux">
      <cdk-header-cell *cdkHeaderCellDef class="example-header-cell"> Qux</cdk-header-cell>
      <cdk-cell *cdkCellDef="let row" class="example-cell"> {{row.qux}} </cdk-cell>
    </ng-container>

    <ng-container cdkColumnDef="grault">
      <cdk-header-cell *cdkHeaderCellDef class="example-header-cell">Grault</cdk-header-cell>
      <cdk-cell *cdkCellDef="let row" class="example-cell">
        {{row.grault}}
      </cdk-cell>
    </ng-container>

    <cdk-header-row *cdkHeaderRowDef="displayedColumns" class="example-header-row"></cdk-header-row>
    <cdk-row *cdkRowDef="let row; columns: displayedColumns; let index=index" class="example-row" (click)="expandRow(index)"
      #cdkrow>
    </cdk-row>
  </cdk-table>
</div>