2015-08-14 49 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; 
    } 
} 
相關問題