Узнайте, какой отдельный элемент изменился в Ember ArrayController

В Ember.ArrayController у меня есть функция, которая .observes() определяет свойство всего массива модели для изменения свойства.

var FoosController = Ember.ArrayController.extend(Ember.Evented, {

    observesEachFooBar: function() {
        var foos = this.get('model');
        foos.forEach(function(foo) {
            //test if this foo has changed, then do something
        });
    }.observes('[email protected]'),

});

Здесь я вручную тестирую каждый Foo в его модели. Как я могу избежать этого и просто получить индивидуальный (или несколько), которые изменились?


person bguiz    schedule 25.07.2014    source источник
comment
@СтивХ. Это не совсем применимо - разница в том, что наблюдатели массива ищут изменения в самом массиве (добавление и удаление элементов). Однако то, о чем я прошу, это наблюдение за свойствами элементов массива.   -  person bguiz    schedule 25.07.2014
comment
@СтивХ. Иными словами, вопрос, на который вы ссылаетесь, может быть решением для .observes('model.@each'), но не решением для .observes('[email protected]')   -  person bguiz    schedule 25.07.2014
comment
Вариант использования? Наблюдение за каждым возможным свойством, как правило, плохая идея по довольно очевидным причинам.   -  person Matthew Blancarte    schedule 25.07.2014
comment
Я должен сказать, что наблюдать за всеми возможными свойствами больших коллекций, вероятно, плохая идея. Вероятно, хорошо для небольших коллекций. :)   -  person Matthew Blancarte    schedule 25.07.2014
comment
@MatthewBlancarte Да, согласен. В моем случае я наблюдаю только одно свойство каждого объекта в массиве (размер которого обычно меньше двадцати). Таким образом, фактическое количество необходимых наблюдателей должно быть вполне управляемым.   -  person bguiz    schedule 25.07.2014
comment
О да, вы готовы идти. У меня уже была подобная функция, которая кусала меня раньше, поэтому у меня возникает параноидальная реакция, когда я ее вижу. :) Один раз укусил, два раза стеснился или что-то в этом роде.   -  person Matthew Blancarte    schedule 25.07.2014


Ответы (2)


Ember делает это с помощью SortableMixin. Вы можете следовать той же схеме.

https://github.com/emberjs/ember.js/blob/v1.6.1/packages_es6/ember-runtime/lib/mixins/sortable.js#L247

        forEach(sortProperties, function(sortProperty) {
          addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange');
        }, this);
      }, this);
    }

    return this._super(array, idx, removedCount, addedCount);
  },

  insertItemSorted: function(item) {
    var arrangedContent = get(this, 'arrangedContent');
    var length = get(arrangedContent, 'length');

    var idx = this._binarySearch(item, 0, length);
    arrangedContent.insertAt(idx, item);
  },

  contentItemSortPropertyDidChange: function(item) {
    var arrangedContent = get(this, 'arrangedContent'),
        oldIndex = arrangedContent.indexOf(item),
        leftItem = arrangedContent.objectAt(oldIndex - 1),
        rightItem = arrangedContent.objectAt(oldIndex + 1),
        leftResult = leftItem && this.orderBy(item, leftItem),
        rightResult = rightItem && this.orderBy(item, rightItem);

    if (leftResult < 0 || rightResult > 0) {
      arrangedContent.removeObject(item);
      this.insertItemSorted(item);
    }
  },
person Kingpin2k    schedule 25.07.2014
comment
По сути, то, чего ОП пытался избежать, но эй, отличный урок по чтению источника. +1 - person Matthew Blancarte; 25.07.2014
comment
@ kingpin2k да, это просто добавление наблюдателей к каждому элементу в массиве по отдельности. Это сработает, но я надеялся, что есть способ сделать это с помощью декларативного синтаксиса, похожего на .observes('[email protected]'). - person bguiz; 25.07.2014
comment
Да, это единственный доступный шаблон, где вы можете это сделать. С положительной стороны, если производительность действительно является проблемой, это был бы путь, вы зацикливаетесь один раз при настройке наблюдателя, а затем при изменении этот точный элемент отправляется в обратный вызов вместо того, чтобы зацикливаться каждый раз, когда элемент изменяется. Таким образом, вы платите цену вперед, а более дешевые звонки будут позже. - person Kingpin2k; 25.07.2014

Вот пример использования метода addArrayObserver вместе с arrayContentWillChange и arrayContentDidChange.

App.IndexController = Em.ArrayController.extend({
  initializer: function() {
    this.addArrayObserver({
      arrayWillChange: Em.K,
      arrayDidChange: function(observedObj, start, removeCount, addCount) {
        if(!removeCount && !addCount) {
          alert('Array item at ' +start+ ' updated');
        }
      }
    });
  }.on('init'),

  actions: {
    updateData: function() {
      this.get('content').arrayContentWillChange(3, 0, 0);
      this.set('content.3.foo', 'foo3-updated');
      this.get('content').arrayContentDidChange(3, 0, 0);
    }
  }
});
person blessenm    schedule 25.07.2014
comment
Я не вижу смысла в настройке наблюдателя массива здесь, вы вручную запускаете события. С таким же успехом вы можете просто создать два метода и вызывать их каждый раз, когда хотите изменить данные. - person Kingpin2k; 26.07.2014
comment
@kingpin2k Я понимаю твою точку зрения. Это просто альтернативное решение. ОП не хотел проверять каждый элемент, чтобы проверить, какой элемент изменился. Тем не менее, мне нужно выяснить, для чего на самом деле используются эти arrayContentWillChange и arrayContentDidChange. - person blessenm; 26.07.2014