Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

You modified *** twice in a single render

Tags:

ember.js

After upgrading to 1.13 I get this exception and I can't figure out what's the issue. I also couldn't find any helpful resource which tackles my issue.

It happens for properties I set in another computed property. But this property is definitely called only once.

I have created a jsbin example: http://emberjs.jsbin.com/roderameya/edit?html,js,console,output

UPDATE

As requested I post some code which is more close to my real implementation.

Ember.Controller.extend({

  filter: '',

  resultCount: {
    total: 0,
    matches: 0,
    mismatches: 0
  },

  results: function() {
    var items = this.get('model'),
        matches = [],
        resultCount = {};

    // Apply search filter
    matches = items.filter(function(item){
      // Just a dummy filter function
      return true;
    });

    // We need the total number matched by the filter string
    resultCount.total = matches.length;

    // The already matched items must be narrowed further down
    matches = matches.filter(function(item) {
      // Another filter function
      return true;
    });

    resultCount.matches = matches.length;
    resultCount.mismatches = resultCount.total - matches.length;

    this.set('resultCount', resultCount);

    return matches;

  }.property('model', 'filter'),

});
like image 621
val Avatar asked Jul 16 '15 18:07

val


1 Answers

Try to have your properties not set other properties, but rather depend on each other:

App.IndexController = Ember.Controller.extend({
  count: function() {
    return this.get("data.length") || 0;
  }.property('data.length'),

  data: [1,2,3]
});

Updated jsbin for you.

UPDATE

Basically, your resultCount is a temporary variable that we can get rid of, and the rest are just chaining computed properties together:

updated jsbin for advanced example

code:

// Index controller
App.IndexController = Ember.Controller.extend({
  count: Ember.computed('filteredItems.length', function(){
    return this.get('filteredItems.length');
  }),

  data: [
    Ember.Object.create({ name: "jim", age: 15 }),
    Ember.Object.create({ name: "jeff", age: 42 }),
    Ember.Object.create({ name: "eric", age: 7 })
  ],

  filter: RegExp(".*"),
  ageFilter: -1,

  mismatchCount: Ember.computed('filteredItems.length', 'secondPassFilteredItems.length', function() {
    return this.get('filteredItems.length') - this.get('secondPassFilteredItems.length');
  }),

  filteredItems: Ember.computed('data', 'filter', function() {
    var controller = this;
    return this.get('data').filter(function(item) {
      return item.get('name').match(controller.get("filter"));
    });
  }),

  secondPassFilteredItems: Ember.computed('filteredItems', 'ageFilter', function() {
    var controller = this;
    var ageFilter = controller.get("ageFilter");
    if (Ember.isEqual(ageFilter, -1)) {
      return this.get('filteredItems');
    } else {

      return this.get('filteredItems').filter(function(item) {
        // more filtering
        return item.get("age") <= ageFilter;
      });
    }
  }),

  results: Ember.computed.alias('secondPassFilteredItems'),

  actions: {
    filterByJ: function() {
      this.set('filter', new RegExp("j"));
    },
    filterByEric: function() {
      this.set('filter', new RegExp("eric"));
    },
    filterAllNames: function() {
      this.set('filter', new RegExp(".*"));
    },
    filterYoungins: function() {
      this.set('ageFilter', 15);
    },
    filterAllAges: function() {
      this.set('ageFilter', -1);
    }
  }

});

Template usage:

<script type="text/x-handlebars" data-template-name="index">
    <p>Results found: {{count}}</p>
    <p>Diff between first and second filter: {{mismatchCount}}</p>
    <p>First Filter:
      <button {{action 'filterAllNames'}}>all people</button>
      <button {{action 'filterByJ'}}>People with J in name</button>
      <button {{action 'filterByEric'}}>People named 'eric'</button>
    </p>
    <p> Second Filter:
      <button {{action 'filterAllAges'}}>all ages</button>
      <button {{action 'filterYoungins'}}>15 years old or younger</button>
    </p>
    <ul>
    {{#each results as |item|}}
      <li>{{item.name}} is {{item.age}} years old</li>
    {{/each}}
    </ul>
  </script>
like image 135
Kori John Roys Avatar answered Nov 06 '22 16:11

Kori John Roys