Представление Ember не обновляется после повторного упорядочивания массива, используемого для создания дочерних представлений

У меня есть представление действий, которое содержит массив действий. Этот массив сортируется иногда на основе вычисленного свойства (distanced_from_home), которое пользователь может обновить. Когда массив отсортирован, я хочу, чтобы дочерние представления были повторно отображены в соответствии с новым порядком. Вот мой шаблон и вид:

index.html

  <script type="text/x-handlebars" data-template-name="activities">
    <h1>Activities</h1>
    {{#each activities}}
      {{view App.ActivityView activityBinding="this"}}
    {{/each}}
  </script>

app.js

  App.ActivitiesView = Em.View.extend({
    templateName: 'activities',
    activities: (function() {
      var list;
      list = App.activityController.activities;
      console.log("Activities View");
      console.log(list);
      return list;
    }).property('App.activityController.activities', '[email protected]_to_home').cacheable()
  });

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

Что делать, чтобы автоматически обновлять представление?

Спасибо,

ИЗМЕНИТЬ

Это, кажется, работает здесь, и моя "активная" функция вычисляет определенную стрельбу, но не переупорядочивает представление... Я также пытался использовать наблюдатель, но результаты одинаковы.

  App.ActivitiesView = Em.View.extend({
    templateName: 'activities',
    classNames: ['activities rounded shadow'],
    homeBinding: 'App.user.home',
    activities: [],
    homeChanged: (function() {
      console.log("homeChanged()");
      this.set('activities', App.activityController.activities.sort(this.compare_activities));
      return null;
    }).observes('home'),

    compare_activities: function(a, b) {
      var result;
      result = 0;
      if (App.user.home != null) {
        result = a.get('distance_to_home') - b.get('distance_to_home');
      }
      return result;
    },

  });

Я также попытался установить параметр "activity" в пустой массив, а затем reset его в упорядоченный массив, чтобы заставить его повторно отобразить, но это не имеет никакого эффекта.

  App.ActivitiesView = Em.View.extend({
    templateName: 'activities',
    classNames: ['activities rounded shadow'],
    homeBinding: 'App.user.home',
    activities: [],
    homeChanged: (function() {
      console.log("homeChanged()");
      this.set('activities', []);
      this.set('activities', App.activityController.activities.sort(this.compare_activities));
      return null;
    }).observes('home'),

    compare_activities: function(a, b) {
      var result;
      result = 0;
      if (App.user.home != null) {
        result = a.get('distance_to_home') - b.get('distance_to_home');
      }
      return result;
    },

  });

EDIT (второй)

Итак, похоже, что использование Ember.copy, наконец, решило это. Установка свойства массива в пустой массив (или null) не имела никакого эффекта. Вот код, который наконец-то работал:

  App.ActivitiesView = Em.View.extend({
    templateName: 'activities',
    classNames: ['activities rounded shadow'],
    homeBinding: 'App.user.home',
    activities: [],
    homeChanged: (function() {
      var list;
      list = App.activityController.activities.sort(this.compare_activities);
      this.set('activities', Ember.copy(list), true);
      return null;
    }).observes('home'),
    compare_activities: function(a, b) {
      var result;
      result = 0;
      if (App.user.home != null) {
        result = a.get('distance_to_home') - b.get('distance_to_home');
      }
      return result;
    }
  });

Ответы

Ответ 1

Помогает ли это? http://jsfiddle.net/rNzcy/

Объединяя этот простой пример, я был немного смущен, почему обновление обзора не "просто работало" при сортировке массива содержимого в ArrayController. Кажется, есть две простые вещи, которые вы можете сделать, чтобы вызвать обновление вида. Или:

  • Задайте массив содержимого равным null, отсортируйте исходное содержимое и затем настройте отсортированный контент.

или

  • Клонировать массив содержимого при его сортировке с помощью Ember.copy()

Я думаю, что Ember обнаруживает, когда установлен совершенно новый объект Array, и он запускает все ожидаемые обновления привязки/просмотра. В противном случае, возможно, он выполняет какое-то кэширование, и если объект Array не изменяется (т.е. Он отсортирован на месте), то никаких привязок не срабатывает? Просто гадать.

UPDATE: См. Обсуждение @https://github.com/emberjs/ember.js/issues/575#issuecomment-4397658, у которого улучшен обходной путь с использованием свойствWillChange() и propertyDidChange() (http://jsfiddle.net/rNzcy/4/) - следует быть намного более эффективным, чем клонирование большого массива.

Ответ 2

Я встретил ту же проблему. И я не думаю, что наблюдение [email protected] или array.length - хорошая практика. Наконец, я нашел это http://jsfiddle.net/rNzcy/4/, то есть вызов this.propertyDidChange('foo')