Ember view не обновляется после переупорядочения массива, используемого для создания дочерних представлений - PullRequest
14 голосов
/ 07 марта 2012

У меня есть представление действий, которое содержит массив действий. Этот массив иногда сортируется на основе вычисляемого свойства (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', 'App.activityController.activities.@each.distance_to_home').cacheable()
  });

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

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

Спасибо

EDIT

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

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

  });

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

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

  });

РЕДАКТИРОВАТЬ (второй)

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

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

Ответы [ 2 ]

10 голосов
/ 08 марта 2012

Это помогает? http://jsfiddle.net/rNzcy/

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

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

или

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

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

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

3 голосов
/ 23 июня 2012

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

...