Prevent ember-data from reloading relations from server if they are specified as links


#1

I already posted the question on stackoverflow and there the guys think that there is no solution to my problem. I wonder if you guys know some solution. This is what I posted there

I’m using Ember-CLI 0.2.7 with Ember-Data v1.0.0-beta.19.2 and Ember 1.13.0. I’m facing the following problem:

I have tags which have many items. So there is a hasMany relation from tags to items. An item can also belong to many tags to there is also a hasMany relation into the other direction.

Therefore the file models/tag.js looks as follows:

export default DS.Model.extend({
    //...
    // Relationships
    items: DS.hasMany('item', {async: true}),
    //...
});

and models/item.js

export default DS.Model.extend({
    //...
    // Relationships
    tags: DS.hasMany('tag', {async: true}),
    //...
});

When I request all tags from the server, the server responses with

{
    "meta": {
        "total": 162
    },
    "tags": [
        {
            "id": 1,
            // ...
            "links": {
                "items": "/tags/1/items"
            }
        }
    ]
}

Now if I’m doing somewhere var items = tag.get('items') Ember-Data correctly fetches the items belonging to the tag with an ajax call. But depending from where the user enters a certain page it could be possible that all items are already in the store. So a ajax call is unnecessary. Is there a way to tell Ember-data that the items are already in the store and that it can lookup all items to the tag in the store?

The use case where a subsequent ajax call is annoying for me is a simple version of infinite scroll. Fetching all the items again from the server is not good for the UX because it makes scrolling stuttering. The best thing in my opinion would be to preload all items with a single ajax call and then resolve the relations to the tag with the items in memory.

Is there any chance to achieve this behavior? Some reopen, extend, overwrite etc?

The guy on stackoverflow correctly pointed out, that it works when the server response with IDs instead of links. But IDs seems not a good option in this particular case because a category can have many items (100 until up to 1000+). Is there really no way to extend ember-data to handle my links differently? Some adapter, some extend or some reopen? Any ideas?

Thanks


#2

Linked resources use the adapter’s findHasMany or findBelongsTo.

Description for findHasMany:

Called by the store in order to fetch a JSON array for the unloaded records in a has-many relationship that were originally specified as a URL (inside of links).

If you find that it is still just grabbing any and everything, try shouldReloadAll: false. If that fails, extend/override adapter by collating the desired search items, compare with stored items using a array.reject{By}(), then passing the remainder as a request to the server.

// Inside custom adapter:
// a reference to all items in store
allItems   : computed(() => store.all('item')),

// an array of stored ids
allItemIds : computed('allItems', () => get(this, 'allItems').mapBy('id')),

// where 'requestedItems' = some collection of record references to get
remainingItems: computed('requestedItems', () => {
    var remainingItems,
        requestedItems = get(this, requestedItems);
    
    remainingItems = requestedItems.reject(
        (reqItm) => {
            return !allItemIds.contains(get(reqItm, 'id'));
        }
    );
    return remainingItems;
}),

findMany: function(/*store, type, ids, snapshots*/) {
    var remainingItems = get(this, 'remainingItems'),
        item = get(this, 'allItems'),
        url  = get(item, 'data.links');

    return this.ajax(url, 'GET', { data: { ids: remainingItems } });
})

#3

Thank you for your response. I’ll have a close look at your solution and I’ll post result when I’m finished :wink: