3

On initialization I read an oData service to get a small list of values and I store the model for further use in the application.

sap.ui.getCore().setModel(oODataJSONModel, "xlist");

At multiple stages, I want to make a copy of the original model, make changes to the values list and use it in a Select drop down. I've tried multiple different things, but every time I update/delete the copied model values, it is instantly reflected in the original model. This seems like a simple ask, but is there a way to break the link between the original model and the copied model, ideally I want to keep the original list intact so that list can be re-used over and over, regardless of what changes are made to the copies?

            var oModelCpy = new sap.ui.model.json.JSONModel();

            var cpyModelArray = oOrigModel.getData();

            cpyModelJsonData = { results : [ cpyModelArray ] };

            oModelCpy.setData(cpyModelJsonData );

When I remove entries from the copy model, it also removes entries from the original model, which in this case is not what i want.

Any suggestions?

scarra_ball
  • 63
  • 3
  • 12
  • Were you able to find a solution to this? I'm facing the same issue, tried deep copying the js object using jquery.extend and JSON.parse, but the changes on one model still affects the other. – Themasterhimself Sep 12 '16 at 08:20

2 Answers2

6

A better approach is to save your data in the success handler:

oODataJSONModel.read("/yourService",  
  null,  
  null,  
  false,  
  function(oData, oResponse){  
    var oODataJSONModel =  new sap.ui.model.json.JSONModel();  
    oODataJSONModel.setData(oData);  
    this.getView().setModel(oODataJSONModel, "jsonModel");
  }
);  

EDIT

I just stumbled upon this question while I was browsing through the list of UI5 questions, and it dawned to me what is causing your underlying copy issue! :-)

If you copy an array of objects to a new array (which is also happens if you copy model data to another model), you won't get a new array with new objects

Instead, you actually will get a new array, but with references to the old objects. So any change you make to a value in an object inside an array in model 1, will end up having that same value in model 2

So, in effect, you need to create new objects based on the old ones. Luckily, you don't need costly for loops and hardcoded value-copying logic to achieve this; one single line should be ok.

Let's say your original data is referenced by an array aData.
You then copy this data (a true copy) to a new array using JSON:

var aDataCopy = JSON.parse(JSON.stringify(aData));

If you now set this aDataCopy as the data for your second model, it will not have any references to the old model anymore.

Hope this helps!

Qualiture
  • 4,900
  • 7
  • 27
  • 38
  • 1
    Thanks Qualiture (congrats on HDE recognition also btw), so this is exactly the steps i have done in the initialization part, i only wanted to call the service once, but I use the model in multiple sections within the application. I thought this would be a simple task, but i want to keep the original model/data values intact, and be able to make copies of the model that i can update/delete entries for as required, but keep those updates/deletes local to the copied model. – scarra_ball Apr 24 '15 at 11:38
  • You're welcome! And humbly thrilled to be part of it indeed! ;-) – Qualiture Apr 24 '15 at 11:42
  • Well deserved for sure, sorry I hit enter on the first comment and I edited it now to add the additional info i wanted to add. – scarra_ball Apr 24 '15 at 11:46
  • So, any updates you do on the local model are instantly reflected to the ODataModel too? That's weird indeed... Maybe the oData metadata is wrecking havoc, and just use `oData.results` (i.e. the array containing the plain results) instead? – Qualiture Apr 24 '15 at 11:48
  • Yeah, i thought by just taking the data (getData) from the original model, using the code above, adding it to oModelCpy that I would be safe to splice values in the copied model without altering the original model. Somehow it keeps the binding back to the original model and removes the same entries. I can't understand how it's keeping that link intact, when in my mind I've only taken the data and not the property or reference of the original model. I tried you're suggestion, with the cpyModelArray = oOrigModel.oData.results, again, same outcome. – scarra_ball Apr 24 '15 at 12:08
  • Hmmm, I'm pretty sure I've used this approach on a former project, and did not experience any issues with it... will have to dig up some old code to see how I did it exactly – Qualiture Apr 24 '15 at 12:11
  • 1
    Thanks Qualiture, not sure what i actually did to hack around it, but tried this out in a simple test and it worked fine. Marking it so more folks might find it useful. Thanks again. – scarra_ball Jun 30 '15 at 15:59
  • @Qualiture I get a converting circular structure to json error, when I use the solution. The first time it works fine. I have a dialog box in which if I make a change and press cancel, I want to show old values on reopening it. But currently it shows changed values. – THI Nov 12 '18 at 23:13
  • @THI You need to clean up your circular references first. See https://stackoverflow.com/questions/11616630/json-stringify-avoid-typeerror-converting-circular-structure-to-json/11616993. Generally speaking, circular references are a coding/structure error and should never happen in the first place – Qualiture Nov 13 '18 at 05:38
0

Try using jquery extend() method to make a copy of the data. I had similar troubles earlier.

var newObject = $.extend({},oldObject);

Try this for once. Find the reference at http://api.jquery.com/jquery.extend/