I have an activities view that contains an array of activities. This array gets sorted sometimes based on a calculated property(distanced_from_home) that the user can update. When the array is sorted I want the child views to be re-rendered by according to the new order. Here is my Template and View:
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()
  });
When I cause the distance_to_home property to change, the console.log output shows the list array is properly sorted, but the children views are not re-rendered in the new order. If I leave this view and then comeback to it (it is rendered again) then the correct order is shown.
What should I do to get the view to update automatically?
Thanks,
This seems to be working here and my 'activities' computed function is definitely firing, but no re-ordering of the view... I also tried to use an observer, but the results are the same.
  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;
    },
  });
I also tried to set the 'activities' parameter to an empty array and then reset it to the ordered array to force it to re-render, but this has no effect.
  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;
    },
  });
So it seems that using Ember.copy finally solved this. Setting the array property to an empty array (or null) did not have any effect. Here's the View code that finally worked:
  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;
    }
  });
                Does this help? http://jsfiddle.net/rNzcy/
Putting together this simple example, I was a little confused why the view update didn't "just work" when sorting the content array in the ArrayController. It seems there are 2 simple things you can do to trigger the view update. Either:
or
I guess Ember detects when a completely new Array object is set, and that triggers all the expected binding/view updates. Otherwise, maybe it's doing some sort of caching and if the Array object does not change (i.e. it's sorted in place) then no bindings fire? Just guessing.
UPDATE: See discussion @ https://github.com/emberjs/ember.js/issues/575#issuecomment-4397658 which has an improved workaround using propertyWillChange() and propertyDidChange() (http://jsfiddle.net/rNzcy/4/) -- should be a lot more efficient then cloning a large array.
I met the same issue. And I don't think observe array.@each or array.length is good practice. At last I found this http://jsfiddle.net/rNzcy/4/ i.e. call this.propertyDidChange('foo')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With