1
votes

I'm on Ember 2.12.

I have an array selectedDays: [Object] in the controller that is passed to component. component has an array like monthDays: [Object]. Objects in component need to have selected property set if they can be found in the array from controller.

The problem is comparing objects is very costly, based on Moment library method (moment1.isSame(moment2, 'day')). So right now when I add something to selectedDays array, every object in monthDays needs to be compared with every object in selectedDays. This can be hundreds or thousands of costly comparisons.

The monthDays always have 42 length (6 weeks) but selectedDays can be tens or hundreds.

I wonder is it possible to optimize that without some bruteforce custom sorting/finding optimization.

The simplest solution would be: on controller array change, check what exactly changed and modify only one day that matches the change. But as far as I know:

  • you can't send an action from controller to component
  • array observers don't "know" what exactly changed in array (?)

What other options do I have?

I set up an Ember Twiddle where there's visible 200-300ms delay every time you click a day before it becomes selected.

1
Can you store only the indices of data in selectedDays array? Or can you wrap your days as {day, isSelected}? - ykaragol
I can wrap my days, in fact they are wrapper, but that doesn't change the fact I don't want to modify the objects in controller (DDAU). selectedDays are raw moment() objects, they are not stored in app Store. - Senthe

1 Answers

0
votes

When you change selectedDays in controller, do you know object that you are going to add/remove? if its so then you can pass that newlyAddedDays object to component, and in component didUpdateAttrs hook, you can check with newlyAddedDays and set the selected property in component.

{{my-component selectedDays=selectedDays newlyAddedDays=newlyAddedDays }}

Initially newlyAddedDays will be empty/undefined.

my-component.js file,

import Ember from 'ember';
export default Ember.Component.extend({
    init() {
        this._super(...arguments);
        //prepare selected property using the selectedDays from controller and monthdDays in component.
    },
    //this hook will not be called for first render.
    //It will be called whenever you change selectedDays/newlyAddedDays. ie, whenever the passed property is updated 
    didUpdateAttrs() {        
        if (Ember.isPresent(this.get('newlyAddedDays'))) {
            //look for it and update selected property.
        }
    }

});

From your options,

you can't send an action from controller to component

Don't do this. instead, you can try with service having the modified property and component will take it from there.

array observers don't "know" what exactly changed in array

Yes. Array observers don't know what exactly changed, so you have to write the code for taking the diff.