我正在尝试创建一个自定义过滤器,它将按对象的title属性过滤对象数组,并仅显示标题中包含搜索子字符串的那些对象。问题是,undefined
是传递到我的管道组件的所有内容。
管道将在* ngFor循环中的模板中使用。模板代码如下所示:
<div class="col-md-2" *ngFor="let strategy of (strategies | NameFilter: searchStrategyText)">
在此上下文中,strategies
是一个策略对象数组,searchStrategyText
是一个字符串,其中双向数据绑定到输入字段。
自定义管道代码如下:
import {Injectable, Pipe, PipeTransform} from '@angular/core';
import {Strategy} from './strategy';
@Pipe({
name: 'NameFilter'
})
@Injectable()
export class NameFilter implements PipeTransform {
transform(strategies: Strategy[], searchString: string): Strategy[] {
return strategies.filter(strategy => strategy.title.indexOf(searchString) !== -1);
}
}
我正在使用的角度版本如下:
angular-cli: 1.0.0-beta.28.3
node: 6.9.2
os: darwin x64
@angular/common: 4.0.0
@angular/compiler: 4.0.0
@angular/core: 4.0.0
@angular/forms: 4.0.0
@angular/http: 4.0.0
@angular/platform-browser: 4.0.0
@angular/platform-browser-dynamic: 4.0.0
@angular/router: 4.0.0
我已经浏览了互联网并尝试了各种方法,但这种方法似乎与角度描述的最接近:https://angular.io/docs/ts/latest/guide/pipes.html
我在这里缺少什么?如果我遗漏了任何重要信息,请告诉我。
编辑: 输入部分的HTML,带有searchStrategyText的双向数据绑定:
<div class="form-group has-feedback has-feedback-left">
<input class="form-control" [(ngModel)]="searchStrategyText" name="searchStrategyText" (focus)="selectAllContent($event)" type="text" placeholder="Strategy Search">
<i class="glyphicon glyphicon-search form-control-feedback"></i>
</div>
我通过AppModule将自定义管道全局提供,方法是导入并将其添加到声明数组中。
编辑#2:编辑#2: 我从strategies
获取了StrategyService
数组,其中我模拟了一个只返回模拟数据类的getStrategies()
函数。
来自服务的策略的组件代码:
getStrategies(): void {
this.strategyService.getStrategies().then(strategies => this.strategies = strategies);
}
StrategyService组件:
import { Injectable } from '@angular/core';
import { Strategy } from './strategy';
import { STRATEGIES } from './mock-strategies';
import { ACTIVE_STRATEGIES } from './mock-active-strategies';
@Injectable()
export class StrategyService {
getStrategies(): Promise<Strategy[]> {
return Promise.resolve(STRATEGIES);
}
getActiveStrategies(): Promise<Strategy[]>{
return Promise.resolve(ACTIVE_STRATEGIES);
}
}
模拟数据组件:
import { Strategy } from './strategy';
export const STRATEGIES: Strategy[] = [
{title: "Key Reverse Long Entry",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
type: "Strategy Template",
modifiedTime: 1461155000,
symbolList:"S&P 100",
deployStatus:"LOAD",
action:"BUY",
isActive: false},
{title:"Key Reverse Short Entry",
description:"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
type:"Strategy Template",
modifiedTime: 1461154940,
symbolList:"S&P 100",
deployStatus:"UNLOAD",
action:"BUY",
isActive: false}
];
显然有更多的模拟数据,我只是为了简洁而缩短了它。
编辑#3:编辑#3: 控制所有这一切的StrategyList组件:import { Component, OnInit, ViewChild } from '@angular/core';
import { TabsetComponent } from 'ng2-bootstrap';
import { Strategy } from './strategy';
import { StrategyService } from './strategy.service';
@Component({
selector: 'strategy-list',
templateUrl: './strategy-list.component.html',
styleUrls: ['./strategy-list.component.css']
})
export class StrategyListComponent implements OnInit {
@ViewChild('staticTabs') staticTabs: TabsetComponent;
strategies: Strategy[];
activeStrategies: Strategy[] = [];
totalItems = 0; // from previous html: (allSignals | filter:searchSignalText).length
filterSelected = false;
searchStrategyText: string;
constructor(private strategyService: StrategyService) { }
ngOnInit() {
this.getStrategies();
this.searchStrategyText = "initial";
}
selectTab(tab_id: number){
this.staticTabs.tabs[tab_id].active = true;
}
getStrategies(): void {
this.strategyService.getStrategies().then(strategies => this.strategies = strategies);
}
getActiveStrategies(): void {
this.strategyService.getActiveStrategies().then(activeStrategies => this.activeStrategies = activeStrategies);
}
exists(strategy: Strategy): boolean {
let idx = this.activeStrategies.indexOf(strategy);
if ( idx > -1){
console.log('strategy is active');
return true;
} else {
console.log('strategy is inactive');
return false;
}
}
toggle(strategy: Strategy): void {
let idx = this.activeStrategies.indexOf(strategy);
if (idx > -1){
console.log("strategy exists in activeStrategies");
this.activeStrategies.splice(idx, 1);
// this.strategyService.cancelStrategy(strategy);
}
else {
console.log("strategy does not exist in activeStrategies");
this.activeStrategies.push(strategy);
// this.strategyService.activateStrategy(strategy);
}
}
toggleFilter(): void{
this.filterSelected = !this.filterSelected;
}
}
编辑#4:编辑#4:
错误输出:
strategy-list.component.html:9 ERROR CONTEXT DebugContext_ {view: Object, nodeIndex: 3, nodeDef: Object, elDef: Object, elView: Object}
View_StrategyListComponent_2 @ strategy-list.component.html:9
DebugContext_.logError @ services.ts:571
ErrorHandler.handleError @ error_handler.ts:69
(anonymous) @ application_ref.ts:286
ZoneDelegate.invoke @ zone.js:365
onInvoke @ ng_zone.ts:261
ZoneDelegate.invoke @ zone.js:364
Zone.run @ zone.js:125
(anonymous) @ zone.js:760
ZoneDelegate.invokeTask @ zone.js:398
onInvokeTask @ ng_zone.ts:253
ZoneDelegate.invokeTask @ zone.js:397
Zone.runTask @ zone.js:165
drainMicroTaskQueue @ zone.js:593
ZoneTask.invoke @ zone.js:464
zone.js:569 Unhandled Promise rejection: Cannot read property 'filter' of undefined ; Zone: <root> ; Task: Promise.then ; Value: TypeError: Cannot read property 'filter' of undefined
at NameFilter.transform (name-filter.pipe.ts:11)
at Object.eval [as updateDirectives] (strategy-list.component.html:9)
at Object.debugUpdateDirectives [as updateDirectives] (services.ts:273)
at checkAndUpdateView (view.ts:345)
at callViewAction (view.ts:700)
at execEmbeddedViewsAction (view.ts:670)
at checkAndUpdateView (view.ts:389)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callWithDebugContext (services.ts:645)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (services.ts:215) TypeError: Cannot read property 'filter' of undefined
at NameFilter.transform (http://localhost:3000/app/name-filter.pipe.js:13:26)
at Object.eval [as updateDirectives] (ng:///AppModule/StrategyListComponent.ngfactory.js:89:66)
at Object.debugUpdateDirectives [as updateDirectives] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12620:21)
at checkAndUpdateView (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12032:14)
at callViewAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12347:17)
at execEmbeddedViewsAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12319:17)
at checkAndUpdateView (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12033:5)
at callViewAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12347:17)
at execComponentViewsAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12293:13)
at checkAndUpdateView (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12038:5)
at callViewAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12347:17)
at execComponentViewsAction (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12293:13)
at checkAndUpdateView (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12038:5)
at callWithDebugContext (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:13020:42)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (http://localhost:3000/node_modules/@angular/core/bundles/core.umd.js:12560:12)
consoleError @ zone.js:569
handleUnhandledRejection @ zone.js:574
_loop_1 @ zone.js:609
drainMicroTaskQueue @ zone.js:613
ZoneTask.invoke @ zone.js:464
zone.js:571 Error: Uncaught (in promise): TypeError: Cannot read property 'filter' of undefined
TypeError: Cannot read property 'filter' of undefined
at NameFilter.transform (name-filter.pipe.ts:11)
at Object.eval [as updateDirectives] (strategy-list.component.html:9)
at Object.debugUpdateDirectives [as updateDirectives] (services.ts:273)
at checkAndUpdateView (view.ts:345)
at callViewAction (view.ts:700)
at execEmbeddedViewsAction (view.ts:670)
at checkAndUpdateView (view.ts:389)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callWithDebugContext (services.ts:645)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (services.ts:215)
at NameFilter.transform (name-filter.pipe.ts:11)
at Object.eval [as updateDirectives] (strategy-list.component.html:9)
at Object.debugUpdateDirectives [as updateDirectives] (services.ts:273)
at checkAndUpdateView (view.ts:345)
at callViewAction (view.ts:700)
at execEmbeddedViewsAction (view.ts:670)
at checkAndUpdateView (view.ts:389)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callViewAction (view.ts:700)
at execComponentViewsAction (view.ts:644)
at checkAndUpdateView (view.ts:392)
at callWithDebugContext (services.ts:645)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (services.ts:215)
at resolvePromise (zone.js:712) [<root>]
at :3000/node_modules/zone.js/dist/zone.js:638:17 [<root>]
at :3000/node_modules/zone.js/dist/zone.js:654:33 [<root>]
at Zone.run (zone.js:125) [<root> => <root>]
at :3000/node_modules/zone.js/dist/zone.js:760:57 [<root>]
at Zone.runTask (zone.js:165) [<root> => <root>]
at drainMicroTaskQueue (zone.js:593) [<root>]
at XMLHttpRequest.ZoneTask.invoke (zone.js:464) [<root>]
答案 0 :(得分:1)
您需要添加一个检查,如果策略是否存在,那么只将过滤器内部的方法克隆,因为第一次调用过滤器时策略未定义或将策略初始化为组件中的空错误
transform(strategies: Strategy[], searchString: string): Strategy[] { if(strategies){ return strategies.filter(strategy => strategy.title.indexOf(searchString) !== -1);} }
其余代码
export class AppComponent implements OnInit {
title = 'app works!';
strategies = [];
constructor(private strategyService: StrategyService) { }
ngOnInit() {
this.getStrategies();
}
getStrategies(): void {
this.strategyService.getStrategies().then((strategies) => this.strategies = strategies);
}
}
在服务中
@Injectable()
export class StrategyService {
getStrategies() {
return Promise.resolve(STRATEGIES);
}
}
export const STRATEGIES = [
{
title: "Key Reverse Long Entry",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
type: "Strategy Template",
modifiedTime: 1461155000,
symbolList: "S&P 100",
deployStatus: "LOAD",
action: "BUY",
isActive: false
},
{
title: "Key Reverse Short Entry",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
type: "Strategy Template",
modifiedTime: 1461154940,
symbolList: "S&P 100",
deployStatus: "UNLOAD",
action: "BUY",
isActive: false
}
];
并过滤
@Pipe({
name: 'NameFilter'
})
export class NameFilter implements PipeTransform {
transform(strategies: String[], searchString: string): String[] {
if(strategies) //Make sure to run this check otherwise strategies would be undefined for the first time{
return strategies;}
}
}
使用空数组调用第一个过滤器,然后使用最终结果调用
答案 1 :(得分:0)
import {Injectable, Pipe, PipeTransform} from '@angular/core';
import {Strategy} from './strategy';
@Pipe({
name: 'NameFilter'
})
/////////////////////////////////////////////////////////////
@Injectable()
/////////////////////////////////////////////////////////////
export class NameFilter implements PipeTransform {
transform(strategies: Strategy[], searchString: string): Strategy[] {
return strategies.filter(strategy => strategy.title.indexOf(searchString) !== -1);
}
}
您使用的是Injectable(),这是错误的。 每个类文件应该只有一个装饰器。删除此