samedi 3 décembre 2016

Ember waiting for relationships to load in array with ember concurrency

I'm attempting to sort an array of model objects based on one of their related models.

I have a Document which hasMany LineItem and a LineItem belongsTo a Location. I want to sort the Line Items by their location. So if I had something like this:

let lineItems = [
  {
    itemName: "One",
    location: {
      name: "Kitchen"
    }
  },
  {
    itemName: "Two",
    location: {
      name: "Kitchen"
    }
  },
  {
    itemName: "Three",
    location: {
      name: "Bathroom"
    }
  },
  {
    itemName: "Four",
    location: {
      name: "Bathroom"
    }
  },
  {
    itemName: "Five",
    location: {
      name: "Hall"
    }
  },
  {
    itemName: "Six",
    location: {
      name: "Hall"
    }
  }
];

I'd want to get to:

let groupedLineItems = {
  "Kitchen": [
    {
      itemName: "One",
      location: "Kitchen"
    },
    {
      itemName: "Two",
      location: "Kitchen"
    },
  ],
  "Bathroom": [
    {
      itemName: "Three",
      location: "Bathroom"
    },
    {
      itemName: "Four",
      location: "Bathroom"
    },
  ],
  "Hall": [
    {
      itemName: "Five",
      location: "Hall"
    },
    {
      itemName: "Six",
      location: "Hall"
    }
  ]
}

I've figured out how to sort, but only once all the relationships have loaded. I can't figure out how to use ember concurrency to wait for all the relationships to load before sorting the data.

This is my controller:

~/app/controllers/document.js

import Ember from 'ember';
import _ from 'underscore';
import { task } from 'ember-concurrency';
const { computed } = Ember;

export default Ember.Controller.extend({
    init() {
        this.get('myTask').perform();
    },

    myTask: task(function * () {
        // Wait for locations to resolve.
        let lineItems = this.get('model').get('lineItems');

        yield this.get("secondTask").perform(lineItems);

        let groupedLineItems = yield _.groupBy(lineItems.toArray(), (lineItem) => {
            lineItem.get('location').then((location) => {
                return location.get('name');
            });
        });

        this.set("groupedLineItems2", Ember.Object.create(groupedLineItems));
    }),

    secondTask: task(function * (lineItems) {
        yield lineItems.toArray().forEach((lineItem) => {
            lineItem.get('location');
        });
    })
});

This is WIP on the controller and not correct. On init the first task runs, but doesn't wait for the locations to be loaded for each line item. I'm trying to make it load all the locations in the second task, but is clearly not the right way to do it. Consequently on init it'll run through sorting, but the function for _.groupBy will return undefined because location is undefined at that point. Then if I run the task again manually (using a button on the template) after I know the locations have loaded (because I'm using them elsewhere on the template) it works fine.

Solution doesn't have to use ember concurrency, it just seemed like the right tool, but I think it can be done with promises as well.




Aucun commentaire:

Enregistrer un commentaire