Observez la propriété sur un éventail d'objets pour tout changement

J'utilise Aurelia et j'ai un ensemble d'éléments liés à une grille et ils ont une propriété sélectionnée sur eux. Je souhaite lier un bouton pour être activé lorsque l'un des éléments est vrai. Je peux faire une approche de la force brute où j'ai un getter qui filtre la liste et renvoie les éléments sélectionnés, mais cela signifie que je ferais des contrôles sales constamment dans l'application et je ne veux pas le faire. J'espère une approche plus efficace. Des idées?

Peu de choses que vous pourriez faire – en supposant que j'ai votre cas d'utilisation correct:

Sale-checking (c'est seulement une propriété, pas une grosse affaire)

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; } } 

Observer les éléments

 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(); } } } 

Utiliser une classe de collecte

 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(); } } 

Utiliser un tableau selectedItems au lieu d'un objet booléen sélectionné

 export class ViewModel { items = [{}, {}, {}]; selectedItems = []; selectItem(item) { this.items.push(item); } deselectItem(item) { this.items.splice(this.items.indexOf(item), 1); } } 

À des fins de liaison, utilisez selectedItems.length comme votre propriété "quelconque sélectionnée"

En plus des exemples de Jeremy, vous pouvez créer un setter personnalisé, par exemple:

 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; } } 

J'ai créé un plongeur pour vous: http://plnkr.co/edit/OTb2RDLZHf5Fy1bVdCB1?p=preview


Si vous faites cela, vous ne verrez jamais si un élément a changé.

Je pense que vous pouvez également exploiter EventAggregator comme indiqué ici . De cette façon, il n'est pas nécessaire d'effectuer des vérifications sales tout le temps et à la place gérer l'événement de sélection d'élément dans sa propre machine virtuelle et publier les données d'événement; L'abonné de l'autre côté va écouter les mêmes et effectuer la gymnastique nécessaire.

Cependant, je ne l'ai jamais utilisé, alors je ne suis pas sûr des détails plus profonds. Mais de la documentation, il semble très simple.

Jeremy m'a fait réfléchir à ce problème . Il semble donc que vous pouvez également obtenir le rafraichissement de liaison via des comportements de liaison personnalisés. J'espère que Jeremy peut confirmer que je ne fais rien de trop idiot ici.

Utilisé comme ceci:

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

Il remplace le comportement d'observation standard et observe le tableau et la propriété que vous définissez sur chaque élément. On peut probablement améliorer pour être plus générique …

 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; } }