Ember:在模型外面创建一个DS.belongsTo *

时间:2015-01-05 05:11:29

标签: ember.js ember-data

我想在我自己的班级(DS.belongsTo,但不是BelongsToRelationship)中理想地创建Ember.Object / DS.Model,或者替代重新创建功能,让我在我自己的类中保存对记录的引用。我不知道是否可以在DS.belongsTo之外使用DS.Model,或者如果可以,如何设置它。

背景

我有一个使用ember-data + ember-fire + firebase的ember-cli应用程序。我的一个模型有一个属性,它是一个持有"类型特定的对象"记录的信息。我根据它描述的类型将此对象转换为我自己的类,有时该类型将引用数据库中的其他记录。在这些情况下,我希望在我的typeSpecific类中设置DS.belongsTo属性,我可以链接到与常规模型中的关系相同的方式。

替代:

经过大量的搜索并且没有找到关于如何做到这一点的任何信息,我创建了自己的课程,这让我大部分都在那里。我刚刚注意到虽然我可以更改它在客户端引用的记录并更新,但如果我在服务器端更改它,我就不会得到更新,所以它会在回到绘图板。

如果有人能够告诉我如何使这种替代方法起作用,那也是有用的。这个类的想法是我传递一个模型名称和id,它应该创建模型引用,然后如果任何一方改变,则保持modelid同步,并且如果它所连接的模型上的任何东西都会像常规关系一样发生变化。

export default Ember.Object.extend({

  id: null,
  table: undefined,
  model: undefined,
  store: undefined,

  init: function() {
    this._super();
    if(this.id && !this.model) {
      this.updateModel();
    }
    else if(this.model && !this.id) {
      this.updateId();
    }
  },

  updateModel: function() {
    var self = this;
    if( this.get('id') ) {
      this.store.find(this.get('table'), this.get('id')).then( function(model) {
         self.set('model', model);
      });
    }
    else {
      self.set('model', undefined);
    }
  }.observes('id','table'),

  updateId: function() {
    if(this.get('model')) {
      this.set('id', this.get('model.id'));
    }
    else {
      this.set('id', null);
    }
  }.observes('model'),
});

编辑:操纵上述对象的代码:

//Creating a reference:
this.set('target', ModelPointer.create({store:this.get('store'), table:this.get('targetTable'), id:targetId}));

//or:
this.set('target', ModelPointer.create({store:store, table:'myTable'}));
...
this.set('target.id', '42');

我相信,如果我更改客户端上的idmodel,另一个会自动更新,例如:

//either:
this.set('target.id', '43');
//or:
this.store.find('myTable','43').then( function(newModel) {
  self.set('target.model', newModel);
});

问题是,如果我登录Firebase并更改myTable['42'].name='Fred',那么我的网页上显示的与target.model.name相关联的值不会更新为' Fred&#39 ;。我怀疑,如果我将target.model.name设置为' Fred'在客户端并保存它不会更新服务器上的值(?)

1 个答案:

答案 0 :(得分:0)

我提出的最干净的解决方案是不单独存储id(留给模型本身)。我已验证我在Firebase中所做的更改会传播到显示的条目。

使用此解决方案设置,可以使用其id或简单地使用模型实例本身来完成引用的模型。有关示例,请参阅控制器代码。

首先,作为参考,Firebase的一些测试数据:

{
  "testModels": {
    "1": {
      "name": "Model one"
    },
    "2": {
      "name": "The second model"
    },
    "3": {
      "name": "Third is the charm"
    }
  }
}

因此它的模型app/models/test-model.js只需要那里的名字。

这是我的belongsTo - 就像代理类一样,我把它放在app/utils/proxy-class.js下面,但它可能应该是一个Mixin:

import Ember from 'ember';

export default Ember.Object.extend({
  remote: null, // reference to the remote DS.Model

  store: null, // reference to the actual store
  storeModel: null, // name of the model in the store

  _watchRemote: function() {
    var self = this;
    if ( typeof self.get('remote') === 'object' ) {
      // do nothing, already an object
      if ( ! Ember.isPresent( self.get('store') ) ) {
        // but set the store from the model
        self.set( 'store', self.get('remote.store') );
      }
    } else if ( typeof self.get('remote') === 'string' ||
                typeof self.get('remote') === 'number' ) {
      // it's an id, so fetch the model
      self._fetchModel( self.get('remote') );
    }
  }.observes('remote').on('init'), // on change, and during object init

  _fetchModel: function( id ) {
    var self = this;
    self.store.find( self.get('storeModel'), id ).then(
      function( model ) {
        self.set( 'remote', model );
      }, function ( err ) {
        console.error( "couldn't read from the store:", err );
      });
  },
});

我创建了这个控制器,并使用浏览器控制台动态更改模型以测试模型更改的选择:

import Ember from 'ember';
import proxyClass from '../utils/proxy-class';

export default Ember.Controller.extend({
  model: {
    remoteFromId: null,
    remoteFromModel: null,
  },

  init: function() {
    var self = this;

    self.set( 'model.remoteFromId',
      proxyClass.create({
        remote: 1,
        store: self.get('store'),
        storeModel: 'test-model',
      })
    );

    self.get('store').find( 'test-model', 2 )
      .then( function( model ) {
        self.set( 'model.remoteFromModel',
          proxyClass.create({
            remote: model,
            storeModel: 'test-model',
            // no store provided here: set from the model
          })
        );
      });

  }
});

控制器的模板:

<p>remoteFromId: {{model.remoteFromId.remote.id}}
  {{model.remoteFromId.remote.name}}</p>
<p>remoteFromModel: {{model.remoteFromModel.remote.id}}
  {{model.remoteFromModel.remote.name}}</p>