2015-08-14 137 views
14

我正在使用Aurelia,并且我有一个绑定到网格的项目数组,并且他们有一个选定的属性。我想绑定一个按钮,当任何一个项目为真时启用。我可以通过暴力破解方法来获取筛选列表并返回选定项目的getter,但这意味着我会在应用程序中不断进行脏检查,而且我不想那样做。我希望有一个更有效的方法。有任何想法吗?观察任意变化的对象数组上的属性

回答

32

,你可以做 - 假设几件事我有你的使用情况的权利:

脏检查(这只是一个财产而不是什么大不了的)

export class Item { 
    selected = false; 
} 

export class ViewModel { 
    items = [new Item(), new Item(), new Item()]; 

    get anySelected() { 
    var items = this.items, i = items.length; 
    while(i--) { 
     if (items[i].selected) { 
     return true; 
     } 
    } 
    return false; 
    } 
} 

观察项目

import {BindingEngine, inject} from 'aurelia-framework'; 

export class Item { 
    selected = false; 
} 

@inject(BindingEngine) 
export class ViewModel { 
    items = [new Item(), new Item(), new Item()];  
    anySelected = false; 
    subscriptions = []; 

    constructor(locator) { 
    this.bindingEngine = bindingEngine; 
    } 

    updateAnySelected() { 
    var items = this.items, i = items.length; 
    while(i--) { 
     if (items[i].selected) { 
     this.anySelected = true; 
     return; 
     } 
    } 
    this.anySelected = false; 
    } 

    activate() { 
    var items = this.items, i = items.length, observer; 
    while(i--) { 
     observer = this.bindingEngine.propertyObserver(items[i], 'selected'); 
     subscriptions.push(observer.subscribe(() => this.updateAnySelected()); 
    } 
    this.updateAnySelected(); 
    } 

    deactivate() { 
    let dispose; 
    while(subscription = subscriptions.pop()) { 
     subscription.dispose(); 
    } 
    } 
} 

使用集合类

import {computedFrom} from 'aurelia-framework'; 

export class Item { 
    _selected = false; 

    constructor(parent) { 
    this.parent = parent; 
    } 

    @computedFrom('_selected') 
    get selected() { 
    return this._selected; 
    } 
    set selected(newValue) { 
    newValue = !!newValue; 
    if (newValue === _selected) { 
     return; 
    } 
    _selected = newValue; 
    this.parent.itemChanged(newValue); 
    } 
} 

export class Items { 
    items = []; 
    selectedCount = 0; 
    anySelected = false; 

    createItem() { 
    let item = new Item(this); 
    this.items.push(item); 
    return item; 
    } 

    itemChanged(selected) { 
    this.selectedCount += (selected ? 1 : -1); 
    this.anySelected = this.selectCount > 0;  
    } 
} 

export class ViewModel { 
    items = new Items(); 

    constructor() { 
    let item = this.items.createItem(); 
    item = this.items.createItem(); 
    item = this.items.createItem(); 
    } 
} 

使用selectedItems阵列,而不是选择布尔的支撑

export class ViewModel { 
    items = [{}, {}, {}]; 
    selectedItems = []; 

    selectItem(item) { 
    this.items.push(item); 
    } 

    deselectItem(item) { 
    this.items.splice(this.items.indexOf(item), 1); 
    } 
} 

结合的目的,使用selectedItems.length为你的“任何选择”属性

+0

太棒了!一些很棒的选择。谢谢。 –

+0

这个改变了吗? –

+0

是的......这有改变吗? – Reft

0

除了杰里米的例子,你可以创建一个自定义二传手,例如:

class Item { 
    // this is your ~private~ field 
    _isSelected = false; 

    // in our constructor, we pass the view model and the property name 
    constructor(vm, prop, name) { 
    this.vm = vm; 
    this.prop = prop; 
    this.name = name; 
    } 

    get isSelected() { 
    return this._isSelected; 
    } 
    // when you set the value, you increase the vm's property 
    set isSelected(value) { 
    if (value !== this._isSelected) { 
     this.vm[this.prop] += value ? 1 : -1; 
     this._isSelected = value; 
    } 
    } 
} 

export class MyViewModel 
{ 
    items = []; 
    itemsSelected = 0; // that's the property we'll pass to the class we've created 

    constructor() 
    { 
    for (let i = 0; i < 50; i++) { 
     // instead of adding a annonymous {} here, we add an instance of our class 
     this.items.push(new Item(this, 'itemsSelected', `Item ${i+1}`)); 
    } 
    } 

    toggleIsSelected(item) { 
    item.isSelected = !item.isSelected; 
    } 
} 

我已经创建了一个plunker你:http://plnkr.co/edit/OTb2RDLZHf5Fy1bVdCB1?p=preview


这样做,您将永远不会循环查看某个项目是否已更改。

+1

这与“使用集合类”示例相同,尽管isSelected getter函数中缺少@computedFrom('_ isSelected')装饰器,这意味着isSelected将被脏检查。 –

+0

谢谢你的帮助! –

0

我想你也可以利用EventAggregator,如here所示。以这种方式,不需要一直执行脏检查,而是在自己的VM中处理项目选择事件并发布事件数据;另一方的用户将会听到相同的声音并执行所需的体操。

但是,我从来没有使用它,所以我不确定它的更深层的细节。但从文档看起来很容易。

0

杰里米让我想起了这个in this bug。所以看起来你也可以通过自定义绑定行为来获取绑定刷新。希望杰里米能够证实我在这里没有做任何愚蠢的事情。

像这样来使用:

repeat.for="item of items | filter & array:'propertyName'"

它覆盖标准观察行为,观察你在每个项目定义数组和属性上。它可能可以改进为更通用的...

function observeProperty(obj, property) { 
    this.standardObserveProperty(obj, property); 
    let value = obj[property]; 
    if (Array.isArray(value)) { 
    this.observeArray(value); 
    for(let each of value){ 
     this.standardObserveProperty(each, this.propertyName); 
    } 
    } 
} 

export class ArrayBindingBehavior { 
    bind(binding, source, property) { 
    binding.propertyName = property; 
    binding.standardObserveProperty = binding.observeProperty; 
    binding.observeProperty = observeProperty; 
    } 

    unbind(binding, source) { 
    binding.observeProperty = binding.standardObserveProperty; 
    binding.standardObserveProperty = null; 
    delete binding.propertyName; 
    } 
}