How to reload an async with links hasMany relationship?

前端 未结 6 1156
有刺的猬
有刺的猬 2021-01-02 01:34

Lets say we have

Post = DS.Model.extend({
  comments: DS.hasMany({async: true})
})

Comment = DS.Model.extend({
  post: DS.belongsTo()
})

a

相关标签:
6条回答
  • 2021-01-02 01:56

    With ember-data-1.0.0-beta.10 I'm using the following model extension.

    Just call model.reloadRelationship(name) where name is the name of the model attribute representing the relationship.

    This works for both normal and link belongsTo/hasMany relationships.

    DS.Model.reopen({
        reloadRelationship: function(name) {
            var meta = this.constructor.metaForProperty(name),
                link = this._data.links ? this._data.links[meta.key] : null;
            if (!link) {
                if (meta.kind === 'belongsTo') {
                    this.get(name).then(function(model) { model.reload(); });
                } else {
                    this.get(name).invoke('reload');
                }
            } else {
                meta.type = this.constructor.typeForRelationship(name);
                if (meta.kind === 'belongsTo') {
                    this.store.findBelongsTo(this, link, meta);
                } else {
                    this.store.findHasMany(this, link, meta);
                }
            }
        }
    });
    

    The only thing missing here are some checks, for example a check if the model is already reloading when the model is reloaded with a link or a check to see if the property name exists within the current model.

    EDIT ember-data-1.0.0-beta.14:

    DS.Model.reopen({
        reloadRelationship: function(key) {
            var record = this._relationships[key];
            if (record.relationshipMeta.kind === 'belongsTo') {
                return this.reloadBelongsTo(key);
            } else {
                return this.reloadHasMany(key);
            }
        },
        reloadHasMany: function(key) {
            var record = this._relationships[key];
            return record.reload();
        },
        reloadBelongsTo: function(key) {
            var record = this._relationships[key];
            if (record.link) {
                return record.fetchLink();
            } else {
                record = this.store.getById(record.relationshipMeta.type, this._data[key]);
                return record.get('isEmpty') ? this.get(key) : record.reload();
            }
        }
    });
    

    HasMany relationship will fallback to native reload method.

    For BelongsTo relationship, it will first check if record needs to be reloaded (if it is not loaded before yet, it will only call get to retrieve the record, otherwise it will call reload).

    0 讨论(0)
  • 2021-01-02 02:01

    Thanks to @igorT, this is implemented. https://github.com/emberjs/data/pull/2297

    Now the ManyArray has a reload() method, which you can even call if the relation has not been loaded yet.

    You can see some use cases by reading the tests

    0 讨论(0)
  • 2021-01-02 02:04

    Reloading a hasMany isn't directly built into Ember Data yet, but it's on its way. The solution I'm using requires Ember Data 1.0b9+canary, which includes opt-in coalesced finds.

    Step 1: Opt In.

    I've opted in at the ApplicationAdapter level, but you may want to do it on a per-model adapter basis. Here's what I have:

    MyApp.ApplicationAdapter = DS.ActiveModelAdapter.extend({
      coalesceFindRequests: true
    });
    

    To give you an idea of why this is important and good, one page on our app was seeing 50+ requests prior to this change. We're now only seeing 11. It's still not great, but that's one hell of an improvement!

    Step 2: Reloading Records in the Association

    I simply wrap up reloading in a function on my model as so:

    MyApp.SomeModel = DS.Model.extend({
      fooMany: DS.hasMany('foo', { async: true }),
      barMany: DS.hasMany('bar', { async: true }),
      bazOne: DS.belongsTo('baz', { async: true }),
    
      reloadAssociated: function () {
        var foosPromises = this.get('foos').invoke('reload'),
            barsPromises = this.get('bars').invoke('reload'),
            bazPromise = this.get('baz').reload();
    
        return Em.RSVP.hash({
          foos: foosPromises,
          bars: barsPromises,
          baz: bazPromise
        });
      }
    });
    

    I admit that it isn't terribly pretty, but it's the best solution I've come up with until reloading is built directly into associations.

    0 讨论(0)
  • 2021-01-02 02:12

    i had the same problem and i cheated to find a "solution"

    i created a component "CommentLoader". This component takes one argument ( post_id ) and before "inserting" (willInsertElement) i grad all the comments and render them. it works but ... i am not proud of it :(

    0 讨论(0)
  • 2021-01-02 02:14

    UPDATE

    Like @sly7_7 said in your answer below, this feature is now avaliable in ember-data. So if you are using the 1.0.0-beta.11 version or greater, this code isn't needed

    You can reopen the ManyArray, and create a new method called reloadLinks(). With the following:

    var get = Ember.get;
    
    DS.ManyArray.reopen({
        reloadLinks: function() {
            var records = get(this, 'content'),
            store = get(this, 'store'),
            owner = get(this, 'owner'),
            type = get(this, 'type'),
            name = get(this, 'name'),
            resolver = Ember.RSVP.defer();
    
            var meta = owner.constructor.metaForProperty(name);
            meta.type = type;
            var link = owner._data.links[meta.key];
            store.findHasMany(owner, link, meta, resolver);
        }
    });
    

    The usage is the following:

    comments.reloadLinks();
    

    Give a look in that fiddle http://jsfiddle.net/H6Gqf/

    0 讨论(0)
  • 2021-01-02 02:17

    Another option is to add a method to the model. Should also work for hasMany:

    search: DS.belongsTo('search', {async: true})
    
    updateSearch: ->
      resolver = Ember.RSVP.defer()
      resolver.resolve = =>
        # do something after promise resolves
      relationship = @constructor.metaForProperty('search')
      link = @_data.links[relationship.key]
      @store.findBelongsTo this, link, relationship, resolver
    
    0 讨论(0)
提交回复
热议问题