Computed property loading multiple times


#1

Hello, I am working on passing a updatedAt property to a component to show at which time it was last updated. The way I am doing is by using computed_property inside of component’s js file. Although the page only uses this property at just one place on the page, it seems to load 3 times.

This computed property gets the latest udpated time from 2 different models within the app. Can you help me what the issue could be?

updatedAt: computed('student.updatedAt','marks.@each.updatedAt', function() {
    const studentupdatedAt = this.get('student.updatedAt');
    const marks = this.get('marks');

    const final = [];
    rates.forEach( function(mark){ final.push(mark.get('updatedAt')) });

    return final.sort().reverse()[0];
  }),

#2

@rahul_lakhanpal a computed property will be recomputed every time one of the observed properties changes. So in this case every time student.updatedAt changes, and every time ANY of the marks[x].updatedAt properties change. Often the cause of many recomputes on a page/component load is due to async data loading. For example when this component is first rendered maybe the marks aren’t fully loaded yet so they start as “undefined” and each time a mark gets loaded it triggers the observer. And same with student, it could be that the first time this CP is calculated the student.updatedAt property is not loaded yet so when it is loaded the CP would recalculate. But without knowing anything about your models and routes and how the component is being rendered I can’t say for sure what’s happening in this case. If you wanted to debug further you could put a breakpoint inside this CP and look at what student and marks look like each time the CP is called. I would recommend using breakpoints over console logs because sometimes console logs can be misleading.

For the most part this behavior is expected and even desired but it does help to be conscious of where and when your data is being loaded to understand how often this CP will be triggered. Having it recompute often isn’t really an issue unless is causing weird side effects or performance issues.


#3

I added a condition to return only when the marks field has any value.

updatedAt: computed('student.updatedAt','marks.@each.updatedAt', function() {
    const studentupdatedAt = this.get('student.updatedAt');
    const marks = this.get('marks');

    if (marks) {
    const final = [];
    final.push(studentupdatedAt);
    rates.forEach( function(mark){ final.push(mark.get('updatedAt')) });

    return final.sort().reverse()[0];
    }

    return studentupdatedAt;
  }),

So if the marks have been added, then only it will compute, else will return the studentUpdatedAt value.


#4

K.I.S.S.

updatedAt: computed('{student.updatedAt,marks.@each.updatedAt}', function() {
  const studentupdatedAt = this.get('student.updatedAt');
  const marks = this.get('marks') || [];
  return [studentupdatedAt, ...marks.mapBy(‘updatedAt’)]
    .sort()
    .reverse()
    .objectAt(0);
}),