Javascript 实现trackBy(),以便在过滤后修复expandRow()函数
运行角度材料2和TS 2.4 概述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,尽
- 目前,我有一个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>