我需要创建一个搜索输入,用于过滤每个父帐户中的子帐户列表。目前,输入任一输入都会过滤所有帐户,而不是仅关联相关帐户。
实例(StackBlitz)
Basic (no FormArray)
With FormArray
要求
问题
如何确保每个FormControl仅过滤当前* ngFor上下文中的帐户?
如何独立观看未知数量的FormControls以进行值更改?我意识到我可以观看FormArray,但我希望有更好的方法。
理想情况下,解决方案应该:
答案 0 :(得分:1)
参考Angular.io - Pipe - Appendix: No FilterPipe or OrderByPipe
Angular不提供这样的管道,因为它们表现不佳并且可以防止侵略性缩小。
根据这个建议,我会用方法替换管道过滤器。
正如@Claies所说,您还需要单独存储搜索条件
由于在编译时帐户数量未知,因此使用Array(this.accounts.length)
初始化searchTerm数组并使用this.searchTerms[accountIndex] || ''
处理空的searchTerms。
<强> app.component.ts 强>
export class AppComponent {
accounts = [
{
accountNumber: '12345',
subAccounts: [
{ accountNumber: '123' },
{ accountNumber: '555' },
{ accountNumber: '123555' }
]
},
{
accountNumber: '55555',
subAccounts: [
{ accountNumber: '12555' },
{ accountNumber: '555' }
]
}
];
searchTerms = Array(this.accounts.length)
filteredSubaccounts(accountNo, field) {
const accountIndex = this.accounts.findIndex(account => account.accountNumber === accountNo);
if (accountIndex === -1) {
// throw error
}
const searchTerm = this.searchTerms[accountIndex] || '';
return this.accounts[accountIndex].subAccounts.filter(item =>
item[field].toLowerCase().includes(searchTerm.toLowerCase()));
}
}
<强> app.component.html 强>
<div>
<div *ngFor="let account of accounts; let ind=index" class="act">
<label for="search">Find an account...</label>
<input id="search" [(ngModel)]="searchTerms[ind]" />
<div *ngFor="let subAccount of filteredSubaccounts(account.accountNumber, 'accountNumber'); let i=index">
<span>{{subAccount.accountNumber}}</span>
</div>
</div>
</div>
参考:StackBlitz
答案 1 :(得分:1)
在上一个答案中,将在每次更改检测时调用过滤器函数(基本上浏览器中与此组件无关的任何事件),这可能是错误的。一种更具角度和高效的方法是利用Observable的力量:
batchListFromQuery = session.createSQLQuery(sql).addEntity(TBatchEntry.class).list();
从内存写入平板电脑,如果通过复制粘贴无效,请使用ide提示查找错误。 :)
通过这种方式,您甚至可以将API调用传递到同一个observable中,从而无需订阅&amp;取消订阅自己,因为异步管道处理所有这些。
编辑:要使其适应2输入,您可以从两者合并.fromEvent(),并在过滤器调用中根据evt.target.id更改行为。对不完整的例子很抱歉,在平板电脑上编写代码非常糟糕:D
RXJS合并:https://www.learnrxjs.io/operators/combination/merge.html
答案 2 :(得分:1)
这是我解决问题的方法。
首先,您遍历外部帐户并为每个帐户创建专用formControl
并将其存储在FormGroup
中。作为ID参考,我使用了帐号。有了这个,我宣布了一个名为getSearchCtrl(accountNumber)
的函数来检索右formControl
。
使用[formControlName]="account.accountNumber"
将您的模板与FormGroup
中提供的formControl相关联。
使用formControl
向getSearchCtrl(account.accountNumber)
filter
引用正确的pipe
并传递该值。
<div *ngFor="let subAccount of account.subAccounts | filter : 'accountNumber':
getSearchCtrl(account.accountNumber).value; let i=index">
<span>{{subAccount.accountNumber}}</span>
</div>
我还编辑了你的stackblitz app:https://stackblitz.com/edit/angular-reactive-filter-4trpka?file=app%2Fapp.component.html
我希望这个解决方案可以帮到你。
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormControl } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
searchForm: FormGroup;
searchTerm = '';
loaded = false;
// Test Data. The real HTTP request returns one or more accounts.
// Each account has one or more sub-accounts.
accounts = [/* test data see stackblitz*/]
public getSearchCtrl(accountNumber) {
return this.searchForm.get(accountNumber)
}
constructor() {
const group: any = {}
this.accounts.forEach(a => {
group[a.accountNumber] = new FormControl('')
});
this.searchForm = new FormGroup(group);
this.loaded = true;
}
ngOnInit() {
this.searchForm.valueChanges.subscribe(value => {
console.log(value);
});
}
}
<ng-container *ngIf="loaded; else loading">
<div [formGroup]="searchForm">
<div *ngFor="let account of accounts; let ind=index" class="act">
<label for="search">Find an account...</label>
<input id="search" [formControlName]="account.accountNumber" />
<div *ngFor="let subAccount of account.subAccounts | filter : 'accountNumber': getSearchCtrl(account.accountNumber).value; let i=index">
<span>{{subAccount.accountNumber}}</span>
</div>
</div>
</div>
</ng-container>
<ng-template #loading>LOADING</ng-template>
答案 3 :(得分:0)
另一种方法是创建一个帐户组件来封装每个帐户及其搜索。在这种情况下,不需要管道 - Example app
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-account',
template: `
<label for="search">Find an account...</label>
<input id="search" [(ngModel)]="searchTerm" />
<div *ngFor="let subAccount of subAccounts()">
<span>{{subAccount.accountNumber}}</span>
</div>
<br/>
`
})
export class AccountComponent {
@Input() account;
@Input() field;
private searchTerm = '';
subAccounts () {
return this.account.subAccounts
.filter(item => item[this.field].toLowerCase()
.includes(this.searchTerm.toLowerCase())
);
}
}
父母将是
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<div>
<div>
<app-account *ngFor="let account of accounts;"
class="act"
[account]="account"
[field]="'accountNumber'">
</app-account>
</div>
</div>
`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
accounts = [
...
];
}