我有一个视图,允许用户查看项目列表并选择一个项目,然后启用一些按钮,如下所示:
查看模型
export class ListViewCustomElement{
@bindable rows= []
selectedRow= null
deleteRow() {
let event = new CustomEvent('delete-row',{
item: selectedItem,
bubbles: true
}
this.element.dispatchEvent(event)
}
查看
<!-- delete button enabled when user selected -->
<i class="button fa fa-times" if.bind="selectedRow" click.delegate="deleteRow()"></i>
<div repeat.for="row of rows" click.delegate="selectedRow = row">
<i class="fa ${selectedRow == row ? 'fa-check-circle' : 'fa-check-circle-o'}"></i>
${row.item1} ${row.item2}
</div>
parentview
<list-view rows.bind="users" delete-item.delegate="deleteUser($event)"></list-view>
现在我需要允许选择多个用户。如果已选择该用户,我仍然需要显示每行的图标。此外,我的deleteRow()
函数需要在事件中传递selectedRows列表,而不仅仅是单个用户。
最简单的方法是为每个行元素添加一个select属性,但我不能这样做,因为它会弄脏我的数据对象。
ATTEMPT 1
查看模型
//added to the above vm
selectedRows = []
selectClick(indexRef){
let index = this.selectedRows.indexOf(indexRef)
if(index < 0){
this.selectedRows.push(indexRef)
}
else{
this.selectedRows.splice(index,1)
}
}
查看
<!--Changed to call new function -->
<div ... click.delegate="selectClick($index)">
<i class="fa ${selectedRows.indexOf($index) < 0 ? 'fa-check-circle-o' : 'fa-circle-check'}"></i>
除了视图中的图标外,这一切都有效 - 在从selectedRows添加和删除项目时,indexOf不会被评估
ATTEMPT 2
查看
<div ref="rowItems">
<div ref="rowItems[$index].unselected" repeat.for="row of rows"
click.delegate="rowItems[$index].unselected = !rowItems[$index].unselected">
<i class="fa ${rowItems[$index].unselected ? 'fa-check-circle-o' : 'fa-check-circle'}"></i>
但是,这种方法很难启用/禁用删除按钮,并且当父视图实际删除所选记录时也会导致问题,因为视图更新但rowItems
属性的未选定标志未重置
关于实现我之后的最佳方式的任何想法?
答案 0 :(得分:0)
也许我错过了你的问题,但我认为你只想要这样的东西:
<div repeat.for="row of rows" click.delegate="row.isSelected = !row.isSelected">
<i class="fa ${row.isSelected ? 'fa-check-circle' : 'fa-check-circle-o'}"></i>
${row.item1} ${row.item2}
</div>
如果行对象没有isSelected
属性,那么最初它会解析为undefined
,这是假的。用户点击一次后,!
会将其强制转换为bool值为true,进一步点击将切换该布尔值。
我假设您希望在课程的稍后阶段对选择做些什么。然后你可以使用javascript的数组过滤功能来获取所有选中的项目:
var selectedRows = rows.filter(function(row) { return row.isSelected; });
<强>更新强>:
对不起,我以前误解了你的约束。我同意Eliran Malka。我认为在这些场景中的一般方法是,人们会将他们的数据从服务接收到他们的视图模型中,然后将数据操作到视图特定的对象中,这些对象将被绑定到视图。如果需要保存这些对象中的某些数据,那么会有一些东西可以将这些视图对象转换回服务对象。因此isSelected
属性不会使您的数据变得肮脏。
话虽如此,根据您需要跟踪这些变化的内容和原因,有一些不同的选择,复杂程度不同。
我能用您提供的信息看到的最简单的方法与第一种方法类似。如果这还不够,请告诉我,我们可以尝试其他选择。
查看强>
<div repeat.for="row of rows" click.delegate="selectedIndices[$index] = !selectedIndices[$index]">
<i class="fa ${${selectedIndices[$index] ? 'fa-check-circle' : 'fa-check-circle-o'}"></i>
${row.item1} ${row.item2}
</div>
<强>视图模型强>
selectedIndices = {}
答案 1 :(得分:0)
所以这就是我最终解决这个问题的方法。
<强>视图模型强>
import {BindingEngine} from 'aurelia-binding'
@inject(Element,BindingEngine)
...
selectedItems = {}
selectedItemsCount = 0 //used to enable/disable buttons
constructor(element,bindingEngine){
this.element = element
this.bindingEngine = bindingEngine
this.psub = this.bindingEngine
.propertyObserver(this,"rows")
.subscribe((data) => {
if(this.asub) this.asub.dispose();
if(!Array.isArray(data)) return;
this.asub = this.bindingEngine
.collectionObserver(this.rows)
.subscribe(changes => {
if(changes[0].removed.length){
for(let item in this.selectedItems){
if(!this.rows.find(v => {return v.id == item})){
this.selectedItemsCount -= (this.selectedItems[item] ? 1 : 0)
delete this.selectedItems[item]
}
}
}
})
})
}
selectClick(id){
this.selectedItems[id] = !this.selectedItems[id]
let total = 0
for(let item in this.selectedItems){
total += this.selectedItems[item] ? 1 : 0
}
this.selectedItemsCount = total
}
deleteRow(item){
let responseItem = null
if(!item){
responseItem = []
responseItem = this.rows.filter(v => {return this.selectedItems[v.id]})
}
else responseItem = item;
let event = new CustomEvent('delete-row',{
detail: {item: responseItem, isList: Array.isArray(responseItem)},
bubbles: true
})
this.element.dispatchEvent(event)
}
首先,实际选择的代码类似于peinearydevelopment所建议的 - 所以感谢让我朝着正确的方向前进。但是,我需要&#34;全球&#34;选择或取消选择项目时,启用/禁用删除按钮(列表外部)。这是selectClick函数中selectedItemsCount更新的目的。
然而,更大的问题是,如果我选择5个项目并单击删除,则父视图(拥有行列表)负责决定是否应删除行并实际删除它们。发生这种情况时,我的行已更新,但我的selectedItemsCount却没有。如果将项目添加到列表中也是如此。
所以,这就是构造函数中属性和集合观察者代码的目的。它确保随时添加或删除集合中的项目,清除selectedItems
列表并调整selectedItemsCount
。
注意:在许多情况下,propertyObserver代码可能不是必需的,但在我的情况下,在调用构造函数时始终不会加载行 - 也不会在视图附加时加载 - 并且数据加载器没有将新数据推送到现有阵列中,而是替换它。替换杀死了我的collectionObserver附加到的数组,因此有必要注意并附加一个新的collectionObserver。
查看强>
<!-- delete button enabled when user selected -->
<i class="button fa fa-times" if.bind="selectedItemsCount" click.delegate="deleteRow()"></i>
<div repeat.for="row of rows">
<i class="fa ${selectedItems[row.id] ? 'fa-check-circle' : 'fa-check-circle-o'}"></i>
${row.item1} ${row.item2}
</div>
我确信Aurelia团队会有更优雅的方式来处理这一切;但希望这对其他人也有帮助。
再次感谢peinearydevelopment和Eliran的投入。我同意你们的看法,即每行添加一个isSelected标志将是一个更多更简单的解决方案。