Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly observe nested array changes #14534

Closed
aaronbhansen opened this issue Oct 27, 2016 · 2 comments
Closed

Correctly observe nested array changes #14534

aaronbhansen opened this issue Oct 27, 2016 · 2 comments
Assignees

Comments

@aaronbhansen
Copy link

I'm not sure if this is a bug or just not possible in ember at the moment, but I've been trying unsuccessfully to get this to work.

The use case is, I want to observer changes in a child array for an array of items. In essence order.lines.@each.selections.@each.value. While I know that this exact computed property isn't possible at the moment in Ember, I've been trying multiple alternative variations to find a solution.

The data

let order = Ember.Object.create({
  lines: Ember.A([
    // Line 1
    Ember.Object.create({
      isDeleted: false,
      selections: Ember.A([
        Ember.Object.create({
          value: 1
        }),
        Ember.Object.create({
          value: 2
        })
      ])
    }),
    // Line 2
    Ember.Object.create({
      isDeleted: false,
      selections: Ember.A([
        Ember.Object.create({
          value: 3
        }),
        Ember.Object.create({
          value: 4
        })
      ])
    }),
    // Line 3 (deleted)
    Ember.Object.create({
      isDeleted: true,
      selections: Ember.A([
        Ember.Object.create({
          value: 100
        })
      ])
    }),
    // Line 4
    Ember.Object.create({
      isDeleted: false,
      selections: Ember.A([
        Ember.Object.create({
          value: 6
        })
      ])
    })
  ])
})

What I want to see happen (even if it wasn't ordered, at least show the new item added)

assert.equal(object.get('selections'), '1,2,3,4,6');
// Push a new selection into the second line
order.get('lines').objectAt(1).get('selections').pushObject(Ember.Object.create({ value: 5 }));
// 5 doesn't show up, since computed properties cache doesn't clear
assert.equal(object.get('selections'), '1,2,3,4,5,6');

These are some of the unsuccessful attempts I've tried to correctly observe the changes.

// Attempt 1
// Get all undeleted lines
lines: Ember.computed('order.lines.@each.isDeleted', function() {
  return this.get('order.lines').filterBy('isDeleted', false);
}),
// Get a flattened array of selections
lines_selections: Ember.computed('lines.@each.selections', function() {
  return this.get('lines').mapBy('selections').reduce(function(a, b) { return a.concat(b); }, []);
}),
// Get the final aggregated value
selections: Ember.computed('lines_selections.@each.value', function() {
  return this.get('lines_selections').mapBy('value').join(',');
})
// Attempt 2
// Try to filter and flatten selections at the same time
line_selections: Ember.computed('order.lines.@each.{isDeleted,selections}', function() {
  return this.get('order.lines')
             .filterBy('isDeleted', false)
             .mapBy('selections')
             .reduce(function(a, b) { return a.concat(b); }, []);
}),
// Observe the value of the flattened selections
selections: Ember.computed('line_selections.@each.value', function() {
  return this.get('line_selections').mapBy('value').join(',');
})
// Attempt 3
// Add selections to be observed, even though not used here
lines: Ember.computed('order.lines.@each.{isDeleted,selections}', function() {
  return this.get('order.lines').filterBy('isDeleted', false);
}),
// Create an array of arrays of selections
lines_selections: Ember.computed.mapBy('lines', 'selections'),
// Reduce the selections to a flattened array
reduced_selections: Ember.computed('lines_selections.[]', function() {
  return this.get('lines_selections').reduce(function(a, b) { return a.concat(b); }, []);
}),
// get the aggregated value 
selections: Ember.computed('reduced_selections.@each.value', function() {
  return this.get('reduced_selections').mapBy('value').join(',');
})

There are more attempts, but the general idea is there, try to observe the right properties to get selections to update in the end when items are added to the selection but the line doesn't change.

There has been a work around to this on templates or components because I'm able to take the lines array and then iterate and pass a single line into a component to observe all the selections for that line, but in this situation I need to aggregate all selections for multiple lines to get a total value.

If I make the properties volatile, of course it works then, but when dealing with this many values, I would like them to be cached if they haven't changed.

Is this a known limitation or bug?

@Serabe Serabe self-assigned this Oct 27, 2016
@Serabe
Copy link
Member

Serabe commented Oct 27, 2016

It is a limitation and one that is intended. See #12847 for references.

Here is a solution.

Closing this since it is not an issue. Providing the example so I can refer to this later.

Thank you!

@Serabe Serabe closed this as completed Oct 27, 2016
@aaronbhansen
Copy link
Author

@Serabe thanks for looking at that and giving a solution. I've done work arounds like that in the past, but was hoping by now there was a solution that provided a better separation of concerns.

Ideally I'll like to be able to have a lines computed property that is filtered based on several properties (type, isDeleted, etc), then be able to take that computed property result and filter or aggregate the child selections.

With the current work around in Ember, I start to add several properties on the line object that is aggregated, but only used in one specific object. The concerns should be on the object consuming these properties, but instead its been shifted to the line object. If start to have multiple of these aggregate properties, lines becomes somewhat of a dumping ground.

Anyway, thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants