16

I want to make a clone of a model currently being edited.

I've found a couple of ways that almost work. But neither are perfect.

1) model.get('data.attributes') gets all the attributes except for relationships in camelCase form, generates a new record fine but the relationships are missing of course.

2) model.serialize() generates a JSON object, with all attributes including relationships. But createRecord will not handle it well since the object is not camelCased (attributes with underscores like first_name will not be handled)

After my clone has been created I want to transaction.createRecord(App.Document, myNewModelObject) change/set a couple of attributes and finally commit(). Anyone have some insight in how to do this?

4

7 回答 7

5

Now we have a add-on to copy models ember-cli-copyable

With this add on, just add the Copyable mix-in to the target model which is to be copied and use the copy method

Example from the add-on site

import Copyable from 'ember-cli-copyable';

Account = DS.Model.extend( Copyable, {
  name: DS.attr('string'),
  playlists: DS.hasMany('playList'),
  favoriteSong: DS.belongsTo('song')
});

PlayList = DS.Model.extend( Copyable, {
  name: DS.attr('string'),
  songs: DS.hasMany('song'),
});

//notice how Song does not extend Copyable 
Song = DS.Model.extend({
  name: DS.attr('string'),
  artist: DS.belongsTo('artist'),
});
//now the model can be copied as below
this.get('currentAccount.id') // => 1 
this.get('currentAccount.name') // => 'lazybensch' 
this.get('currentAccount.playlists.length') // => 5 
this.get('currentAccount.playlists.firstObject.id') // => 1 
this.get('currentAccount.favoriteSong.id') // => 1 

this.get('currentAccount').copy().then(function(copy) {

  copy.get('id') // => 2 (differs from currentAccount) 
  copy.get('name') // => 'lazybensch' 
  copy.get('playlists.length') // => 5 
  copy.get('playlists.firstObject.id') // => 6 (differs from currentAccount) 
  copy.get('favoriteSong.id') // => 1 (the same object as in currentAccount.favoriteSong) 

});
于 2015-09-11T07:52:23.690 回答
3

How about using toJSON() method instead of serialize() like this

js transaction.createRecord(App.Document, model.toJSON());

于 2013-08-27T14:31:02.637 回答
1

You can use https://github.com/offirgolan/ember-data-copyable. Been using this package for some time now, and it is very much reliable. Some of its features :

  • Shallow & deep copy an Ember Data model

  • Shallow & deep copy model relationships

  • Handles cyclical relationships

  • Handles custom transforms to create true copies

  • Overwrite, ignore attributes, and copy objects by reference

  • Intelligent failure and cleanup

  • Uses ember-concurrency to allow cancelling a copy task

于 2019-01-29T08:50:55.960 回答
0

Most simple way I found:

function cloneModel(model) {
  const root = model._internalModel.modelName;
  const store = model.get('store');
  let attrs = model.toJSON();

  attrs.id = `clone-${attrs.id}`;
  store.pushPayload({
    [root]: attrs
  });
  return store.peekRecord(root, attrs.id);
}
于 2017-03-08T09:56:30.367 回答
0

Here is the simple way to clone your Ember Model with relationships. working fine.

Create a Copyable mixin like,

import Ember from 'ember';

export default Ember.Mixin.create(Ember.Copyable, {

    copy(deepClone) {
      var model = this, attrs = model.toJSON(), class_type = model.constructor;
      var root = Ember.String.decamelize(class_type.toString().split(':')[1]);

      if(deepClone) {
          this.eachRelationship(function(key, relationship){
              if (relationship.kind == 'belongsTo') {
                  attrs[key] = model.get(key).copy(true);
              } else if(relationship.kind == 'hasMany' && Ember.isArray(attrs[key])) {
                  attrs[key].splice(0);
                  model.get(key).forEach(function(obj) {
                      attrs[key].addObject(obj.copy(true));
                  });
              }
          });
      }
      return this.store.createRecord(root, attrs);
    }
});

Add the mixin in your model,

Note: If you want to clone your child model then, you need to include the mixin in child model as well

USAGE:

  1. With relationship : YOURMODEL.copy(true)
  2. Without relationship : YOURMODEL.copy()
于 2017-03-29T03:31:14.637 回答
0

This will also solve my problem

Account = DS.Model.extend({
   name: DS.attr('string'),
   playlists: DS.hasMany('playList'),
   favoriteSong: DS.belongsTo('song')
});

Duplicate = Ember.Object.extend({});

TemporaryRoute = Ember.Route.extend({
   model : function(){
      var model = this.store.findAll('account');
      var json = model.toJSON(); 
      var duplicateModel = Duplicate.create(json);
      this.set('duplicateModel', duplicateModel);
      return model;
   }
});
于 2017-06-28T07:33:19.013 回答
-1

Here's an updated answer, it still doesn't handle hasMany relationships.

cloneBelongsTo: function(fromModel, toModel) {
  var relationships;
  relationships = Em.get(fromModel.constructor, 'relationships');
  return relationships.forEach(function(relationshipType) {
    var _relType;
    _relType = relationships.get(relationshipType);
    return _relType.forEach(function(relationship) {
      var name, relModel;
      relModel = Em.get(fromModel, relationship.name);
      if (relationship.kind === 'belongsTo' && relModel !== null) {
        name = relationship.name;
        return toModel.set(name, fromModel.get(name));
      }
    });
  });
}

And here's how I use it:

// create a JSON representation of the old model
var newModel = oldModel.toJSON();
// set the properties you want to alter
newModel.public = false;
// create a new record
newDocument = store.createRecord('document', newModel);
// call the cloneBelongsTo method after the record is created
cloneBelongsTo(model, newDocument);
// finally save the new model
newDocument.save();
于 2013-02-16T17:44:36.027 回答