我在我的项目中使用bootstrap-selectpicker,当我尝试动态放置数据时,下拉列表不起作用。我认为selectpicker()过早被调用。我希望在获取数据后调用它。
export class MyComponent implements AfterViewInit {
accounts = Observer<Account[]>;
// Account service is just a http service returning Observer with accounts.
constructor(private accountService : AccountService) {
this.accounts = this.accountService.getAccounts();
}
ngAfterViewInit() {
$('.selectpicker').selectpicker();
}
}
模板:
<select class="selectpicker" multiple>
<option *ngFor="let account of accounts | async" >{{account.username}}</option>
</select>
只有在我使用预定义列表时才有效:
<select class="selectpicker" multiple>
<option>One</option>
<option>two</option>
<option>three</option>
</select>
这是我的AccountService:
@Injectable()
export class AccountService {
constructor(private http: Http) { }
// TODO: Error handling
getAccounts() : Observable<Account[]> {
return this.http.get("/api/accounts").map(response => response.json());
}
}
答案 0 :(得分:2)
虽然您的技术可以正常运行,但由于ngAfterViewChecked
(顾名思义)在每次更改检测运行期间都会调用,因此存在此技术存在潜在性能问题的风险。这是因为无论您的列表是否实际更改过,都会调用selectpicker('refresh')
函数。
解决此问题的一种方法是稍微调整您的observable,以便它仅在您的服务返回新的帐户列表时触发selectpicker('refresh')
函数。
constructor(private accountService : AccountService) { }
ngOnInit() {
$('.selectpicker').selectpicker(); // <-- i don't know if this first call is necessary before the version with 'refresh' parameter will work - try removing it
this.accounts = this.accountService.getAccounts().do(() => {
setTimeout(() => {
$('.selectpicker').selectpicker('refresh');
}, 150);
});
}
<强>解释强>
基本上,关键是do
运算符,它允许您在从observable发出新值时运行一些副作用代码,而不会更改来自observable的值。因此,使用此选项可以使用每个新的帐户列表运行刷新功能。我还将您的逻辑移动到ngOnInit
- 您应该将构造函数逻辑限制为通过依赖注入简单地初始化属性。最后,您需要将selectpicker('refresh')
调用包装在setTimeout中,以便在尝试在选择选择器的DOM上查找新元素之前运行更改检测(以及要更新的DOM)。确切的超时延迟与确保使用setTimeout一样重要,因此在更改检测更新DOM后,selectpicker('refresh')
调用将在事件循环的单独刻度中运行。
要说清楚,我真的怀疑现有技术的性能损失是值得关注的,但上述技术可以添加到您的工具箱中,以应对性能可能会受到影响的情况。
答案 1 :(得分:1)
您可以使用主题。
let subject = new Rx.Subject();
constructor(private accountService : AccountService) {
this.accountService.getAccounts().subscribe(subject);
this.accounts = subject.asObservable();
}
ngAfterViewInit() {
subject.asObservable()
.subscribe(x=> {
$('.selectpicker').selectpicker();
});
}
<select class="selectpicker" multiple>
<option *ngFor="let account of accounts | async" >
{{account.username}}</option>
</select>
答案 2 :(得分:0)
我想我可以在动态更新selectpicker后调用selectpicker('refresh')
。到目前为止,这是解决此问题的最简单方法。
ngAfterViewInit() {
$('.selectpicker').selectpicker();
}
ngAfterViewChecked() {
$('.selectpicker').selectpicker('refresh');
}
我通过查看React here的包装器库找到了它。
编辑:此方法似乎第一眼就能正常工作,但它没有,它会在您尝试检查选择框中的某个项目时刷新,并且不允许选择更多项目。对于工作解决方案,请参阅snorkpete的anwser。
答案 3 :(得分:0)
只需在ngIf="accounts"
标记的上方<div>
中添加<select>
,就像这样:
<div *ngIf="accounts">
<select class="selectpicker" multiple>
<option *ngFor="let account of accounts" >{{account.username}}</option>
</select>
</div>