1

Having problems to understand how to resolve nested models in ember. Damn.

I don't know if it's a common approach but I don't want my controllers or components care about asynchronicity at all. Therefore it's necessary to resolve everything needed in my routes.

My current approach does not work for nested relations (I'm describing it in the comments).

First some model definitions:

var Project = DS.Model.extend({
    name: DS.attr("string"),
    tasks: DS.hasMany("task", {async: true}),
    // ...
});

var Task = DS.Model.extend({
    name: DS.attr("string"),
    documentation: DS.belongsTo("task_documentation", {async: true}),
    // ...
});

var TaskDocumentation = DS.Model.extend({
    lastEditor: DS.attr("string")
    // ...
});

ProjectRoute:

ProjectRoute = Em.Route.extend({
    model: function () {
        var project;
        return this.store.find("project", {name: "foo"}).then(function (resolvedProject) {
            project = resolvedProject.objectAt(0);
            return resolvedProject.get("tasks");
        }).then(function (resolvedTasks) {
            console.log("For some reason nothing left to do to resolve tasks: " 
                    + project.get("tasks").objectAt(0).get("name"));

            // Collect documentation
            var docu = []
            project.get("tasks").forEach(function (task, index) {
                docus[i] = task.get("documentation");
            });
            return Em.RSVP.all(docus);
        }).then(function (resolvedDocus) {
            // docus are resolved but not attached to project.
            console.log(project.get("tasks")
                   .objectAt(0)
                   .get("documentation")
                   .get("lastEditor")); // "undefined"

            // Setting documentation for each task manually does not help:
            project.get("tasks").forEach(function(task, index) {
                task.set("documentation", resolvedDocus.objectAt(index));
            });
            console.log(project.get("tasks")
                   .objectAt(0)
                   .get("documentation")
                   .get("lastEditor")); // still undefined

            return project;
        });
    }
});

I'm currently using Ember 1.7.0 with Ember Data 1.0.0-beta.10

I guess there's a much easier way. Hope you guys can give me a hint. Thanks in advance!

UPDATE:

Thank you for input KingPin!

An important detail I totally forgot to mention is that I'm using FixturesAdaptor right now. That's why everything had to be declared async.

You said the collection returned by find did not define tasks. That's not the case. Everything is resolved correctly. The tasks are available. Even the documentation for each task can be accessed.

// ...
}).then(function (resolvedDocus) {
    // resolvedDocus have been resolved. I simply cant't attach them to project's tasks
    console.log(resolvedDocus.firstObject.lastEditor); // "Mr. Foo"

});

What I want to accomplish is to return a single project whose properties are directly accessible. At the moment I could create something like model.project, model.tasks, model.taskDocs but when I set project.someTask's documentation, nothing happens.

Another Update (cause I'm stupid)

There's a typo.

var project;
return this.store.find("project", {name: "foo"}).then(function (resolvedProject) {
    project = resolvedProject.objectAt(0);
    // This of course returns a collection.
    return resolvedProject.get("tasks");
    // I meant...
    return resolvedProject.objectAt(0).get("tasks");

The problem still is the same. Sorry if that caused confusion.

SOLVED

It turned out to be a bug in Ember-Data 1.0 beta 10. I tried to identify the actual issue but there are multiple things listed that could have caused the problem.

Once again. Thanks!

Doe Johnson
  • 1,374
  • 13
  • 34
  • Do you have control of the API? Having these relationships async and then forcing them to all go fetch everything immediately seems like a waste of calls to your server. It seems like a good opportunity to use embedded records and skip async. – Kingpin2k Nov 09 '14 at 17:36
  • Sorry I forgot to tell. Updated the question. – Doe Johnson Nov 09 '14 at 21:38
  • Would you mind updating the question with what your full promise looks like, and the areas that aren't showing what you'd expect? – Kingpin2k Nov 10 '14 at 00:42
  • Do you think you could reproduce the issue you are seeing with my jsbin? – Kingpin2k Nov 10 '14 at 00:47

1 Answers1

2

Most of your issues here resolve around the fact that your find returns a collection, which won't have tasks defined on it (I'm specifically referring to resolvedProject.get('tasks')) so you never resolve tasks.

ProjectRoute = Em.Route.extend({
    model: function () {
        var project;
        return this.store.find("project", {name: "foo"}).then(function (resolvedProjects) {
            // resolvedProjects is a collection, 
            // but let's assume your api only returns a single project
            project = resolvedProject.objectAt(0);
            return project.get("tasks");
        }).then(function (resolvedTasks) {
            // this was empty because you didn't grab the tasks off a project
            console.log(project.get("tasks.firstObject.name"));

            var documents = resolvedTasks.getEach('documentation');
            return Em.RSVP.all(documents);
        });
    }
});

Example: http://emberjs.jsbin.com/sonane/1/edit

Kingpin2k
  • 47,277
  • 10
  • 78
  • 96