我有一个material-dropdown-select的以下实现,它运行得很漂亮。
<material-dropdown-select [buttonText]="organizer?.name">
<material-select-item *ngFor="let sailingClub of sailingClubs"
{{sailingClub.name}}
</material-select-item>
</material-dropdown-select>
我的数据来自这个属性:
Iterable<SailingClub> get sailingClubs => _store.state.sailingClubs.values;
关于它的好处是,一旦后端(firebase)将新项目添加到列表中,项目就会自动更新。
现在我想将其更改为使用可搜索的下拉列表。 为此,我必须将数据转换为SelectionOptions,并且我有问题。一切正常,但我不再进行变化检测。 这并不奇怪,因为我现在必须创建一个静态的SelectionOptions实例,这是我向视图组件提交的唯一内容。
<material-dropdown-select [buttonText]="organizer?.name"
[options]="filteredSailingClubs"
[itemRenderer]="displayNameRenderer">
<div header>
<material-select-searchbox
label="Search..."
[filterable]="filteredSailingClubs">
</material-select-searchbox>
</div>
</material-dropdown-select>
这就是我创建filteredSailingClubs
的方法filteredSailingClubs = new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);
并访问名称属性
ItemRenderer<SailingClub> displayNameRenderer = (SailingClub item) => item.name;
答案 0 :(得分:1)
您是否正在收听Firebase数据库进行更改?
我不确定_store
或其任何属性到底是什么,但是从Firebase DatabaseRef,您可以监听更改并更新您的选择选项。然后,更改检测应检测到选择选项已更改。
sailingClubsRef.onValue((value) {
filteredSailingClubs = new StringSelectionOptions(
value.snapshot.val(),
toFilterableString: displayNameRenderer,
);
});
答案 1 :(得分:1)
这是我当前的方法。将其作为更好的可读性的答案。
首先,我必须为计算值添加新变量,并手动跟踪变化。
StringSelectionOptions<SailingClub> filteredSailingClubs;
SelectionModel<SailingClub> singleSelectModel;
Map<String, SailingClub> oldSailingClubs;
SailingClub oldOrganizer;
然后在我的组件的构造函数中,我可以创建filteredSailingClubs。但是这个StringSelection将是空的,因为那时所有选项都没有从firebase加载。
filteredSailingClubs = new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);
并且最终能够更新filteredSailingClubs我必须添加它。
void ngDoCheck() {
if (oldSailingClubs != _store.state.sailingClubs) {
oldSailingClubs = _store.state.sailingClubs;
filteredSailingClubs =
new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);
}
if (oldOrganizer != organizer) {
oldOrganizer = organizer;
singleSelectModel = new SelectionModel<SailingClub>.withList(selectedValues: [organizer]);
singleSelectModel.selectionChanges.listen(update);
}
}
这是另外一个回调,它允许我在gui
中更改选择时更新值void update(List<SelectionChangeRecord> record) {
if (record.isNotEmpty && record.first.added.isNotEmpty) {
onOrganizerChanged(record.first.added.first);
}
}
不幸的是,这是很多锅炉板代码只是为了使列表可搜索。在所有变更检测由Angular处理并完全隐藏之前。所以我想知道我做错了。
我也不想改变商店的结构。它基本上是一个redux模式存储(使用greencat)并且是不可变的。 我也不希望我的商店知道关于gui的任何信息,例如选择模型等。
我的下一步是从材料下拉选择本身,看看我是否可以隐藏那里的复杂性。
答案 2 :(得分:0)
好的,这是我的最终解决方案。它在我看来并不是很好,因为它仍然需要相当多的代码,但至少它的效果非常好。 代码量的主要原因是map.values列表本身不稳定。因此map.values与旧值的每个新比较都将返回true。即使地图没有变化。因此我们必须保存原始地图。
StringSelectionOptions<SailingClub> _filteredSailingClubs;
Map<String, SailingClub> _oldSailingClubs;
SelectionModel<SailingClub> _singleSelectModel;
SailingClub _oldOrganizer;
StreamSubscription _selectionListener;
StringSelectionOptions<SailingClub> get filteredSailingClubs {
// We have to save the old state since the Iterable itself is unstable and would change all the time
if (_oldSailingClubs != _store.state.sailingClubs) {
_oldSailingClubs = _store.state.sailingClubs;
_filteredSailingClubs =
new StringSelectionOptions(_store.state.sailingClubs.values, toFilterableString: displayNameRenderer);
}
return _filteredSailingClubs;
}
SelectionModel<SailingClub> get singleSelectModel {
// We have to update the selection model on organizer change
if (_singleSelectModel == null || _oldOrganizer != organizer) {
_oldOrganizer = organizer;
_singleSelectModel = new SelectionModel<SailingClub>.withList(selectedValues: [organizer]);
_selectionListener?.cancel();
_selectionListener = _singleSelectModel.selectionChanges.listen(update);
}
return _singleSelectModel;
}