14

I'm trying to figure out how to clone an Ext.data.Store without keeping the old reference.

Let me explain better with some code. Here's the source store:

var source = Ext.create ('Ext.data.Store', {
    fields: ['name', 'age'] ,
    data: [
        {name: 'foo', age: 20} ,
        {name: 'boo', age: 30} ,
        {name: 'too', age: 10} ,
        {name: 'yoo', age: 80} ,
        {name: 'zoo', age: 30}
    ]
});

Follows an example of what I want to do:

var target = source;
target.removeAll ();
// Here I need to have target empty and source unchanged
// But in this case, source is empty as well

Now, in the above example the copy is done by reference while I need to do it by value. So I found Ext.clone () in the docs but it seems it doesn't work for complex object, like Ext.data.Store:

var target = Ext.clone (source);
target.removeAll ();
// source is still empty

Then I tried with Ext.data.Model.copy () but the only way to do it work is this:

var target = Ext.create ('Ext.data.Store', {
    fields: ['name', 'age']
});

source.each (function (model) {
    target.add (model.copy ());
});

Now, for my reasons, I don't want to instantiate another Ext.data.Store, so I want to avoid this:

var target = Ext.create ('Ext.data.Store', {
    fields: ['name', 'age']
});

I'd like to have something like this:

var target;

source.each (function (model) {
    target.add (model.copy ());
});

But, obviously, it doesn't work.

So, how can I clone the source store?

Wilk
  • 7,873
  • 9
  • 46
  • 70
  • 1
    I don't think there is a way to copy a store. Instantiating a new, empty one is probably the only choice you have. – Yoshi Sep 27 '12 at 11:59
  • Would you mind explaining why you want to clone your store? – mbarthelemy Sep 27 '12 at 19:41
  • Because I need to represent some data into a grid. I'm using MVC and a complex model associations for a complex nested XML database. I'm searching for something different from defining a new store, obviously if it's possible. – Wilk Sep 27 '12 at 19:48

4 Answers4

15

ExtJS 6.x, 5.x and 4.x solution

Here's a quasi-all ExtJS versions solution. Mind you that record.copy already creates a clone of the data. No need to Ext.clone that again.

function deepCloneStore (source) {
    source = Ext.isString(source) ? Ext.data.StoreManager.lookup(source) : source;

    var target = Ext.create(source.$className, {
        model: source.model,
    });

    target.add(Ext.Array.map(source.getRange(), function (record) {
        return record.copy();
    }));

    return target;
}
Christiaan Westerbeek
  • 10,619
  • 13
  • 64
  • 89
  • I'll try this and see how it goes – oneofakind Nov 05 '15 at 02:21
  • 1
    That's much tidier. Works fine in ExtJS4 if you change "source.getModel()" to "source.model". I also added this line at the start, to give the option of supplying a store ID: source = Ext.isString(source) ? Ext.data.StoreManager.lookup(source) : source; – David Easley Nov 19 '15 at 12:45
  • 2
    For Ext 6.5 and 7 I would use record.clone() instead of record.copy(). States like `dropped`, `phantom` and `dirty` are kept. – klodoma Nov 03 '19 at 20:27
13

ExtJS 3.x solution

Try this:

cloneStore : function(originStore, newStore) {

    if (!newStore) {
        newStore = Ext.create('Ext.data.Store', {
            model : originStore.model
        });
    } else {
        newStore.removeAll(true);
    }

    var records = [], originRecords = originStore.getRange(), i, newRecordData;
    for (i = 0; i < originRecords.length; i++) {
        newRecordData = Ext.ux.clone(originRecords[i].copy().data);
        newStore.add(new newStore.model(newRecordData, newRecordData.id));
    }

    newStore.fireEvent('load', newStore);

    return newStore;
}

Note: Ext.ux.clone is a separated plugin (you will find it) which makes a deep clone of an object. Maybe, Ext JS 4 provides a familiar thing, I don't know.. I'm using this special clone since Ext JS 3.x

It is possible that it is required to specify the proxy memorywhen creating a new store (I'm not sure right now because I'm using always the "provided" way.

ExtJS 4.x solution

function deepCloneStore (source) {
    var target = Ext.create ('Ext.data.Store', {
        model: source.model
    });

    Ext.each (source.getRange (), function (record) {
        var newRecordData = Ext.clone (record.copy().data);
        var model = new source.model (newRecordData, newRecordData.id);

        target.add (model);
    });

    return target;
}
Wilk
  • 7,873
  • 9
  • 46
  • 70
knalli
  • 1,973
  • 19
  • 31
  • 1
    As Yoshi said, maybe that's the only way to do it. So, that's exactly what I was looking for! I added the ExtJS4 solution to your answer! Thanks a lot knalli! – Wilk Sep 29 '12 at 13:02
  • 1
    These methods do not copy any relations (stores) the records may have in turn, so not deep enough for models with relations. – oldwizard Apr 11 '13 at 11:20
  • Well, this means that the relation data aren't stored into `data`. More "deeper" is not possible. ;) – knalli Apr 11 '13 at 15:11
  • the ExtJS 4 solution does not copy any relationships as pcguru already said! – Chris Aug 05 '13 at 16:55
  • just use target.add(record.copy()) you dont need that extra code above that line. – 1-14x0r Apr 02 '15 at 17:27
  • No, that is not correct. Referring latest 4.x branch spec http://docs.sencha.com/extjs/4.2.3/#!/api/Ext.data.Model-method-copy, you will see this approach will not clone a record but duplicate (copy with new id). That is not the same. – knalli Apr 02 '15 at 23:07
  • Do you have something for EXTJS 5? – oneofakind May 04 '15 at 12:58
  • @oneofakind Check my answer for an ExtJS 5 and 6 version – Christiaan Westerbeek Nov 04 '15 at 11:48
2

I did the following successfully in Ext.js 4.1:

var source = Ext.create('Ext.data.Store', {
    fields: ['name', 'age'],
    data: [
        {name: 'foo', age: 20},
        {name: 'boo', age: 30},
    ],
});

In a method:

cloneStore: function (source) {
    var clone = Ext.create('Ext.data.Store', {
        fields: ['name', 'age']
    });

    // load source store data
    clone.loadData(source.data.items);

    return clone;
}

Inline:

var clone = Ext.create('Ext.data.Store', {
    fields: ['name', 'age']
}).loadData(source.data.items);
TriumphST
  • 1,194
  • 1
  • 10
  • 17
0

since this is still something I was looking for and the above answers did not fix it for me, I found another solution myself:

var target = Ext.create ('Ext.data.Store', {
    // add other properties here if needed
    reader: source.reader
})

This worked for me to create clones of a store.

Allie
  • 1,081
  • 1
  • 13
  • 17