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?
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!
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/
Related
I am trying to export a large feature collection from GEE. I realize that the Python API allows for this more easily than the Java does, but given a time constraint on my research, I'd like to see if I can extract the feature collection in pieces and then append the separate CSV files once exported.
I tried to use a filtering function to perform the task, one that I've seen used before with image collections. Here is a mini example of what I am trying to do
Given a feature collection of 10 spatial points called "points" I tried to create a new feature collection that includes only the first five points:
var points_chunk1 = points.filter(ee.Filter.rangeContains('system:index', 0, 5));
When I execute this function, I receive the following error: "An internal server error has occurred"
I am not sure why this code is not executing as expected. If you know more than I do about this issue, please advise on alternative approaches to splitting my sample, or on where the error in my code lurks.
Many thanks!
system:index is actually ID given by GEE for the feature and it's not supposed to be used like index in an array. I think JS should be enough to export a large featurecollection but there is a way to do what you want to do without relying on system:index as that might not be consistent.
First, it would be a good idea to know the number of features you are dealing with. This is because generally when you use size().getInfo() for large feature collections, the UI can freeze and sometimes the tab becomes unresponsive. Here I have defined chunks and collectionSize. It should be defined in client side as we want to do Export within the loop which is not possible in server size loops. Within the loop, you can simply creating a subset of feature starting from different points by converting the features to list and changing the subset back to feature collection.
var chunk = 1000;
var collectionSize = 10000
for (var i = 0; i<collectionSize;i=i+chunk){
var subset = ee.FeatureCollection(fc.toList(chunk, i));
Export.table.toAsset(subset, "description", "/asset/id")
}
I'm implementing a searchbar in IONIC 2 that search a JSON in one view so it can send its details to another view.
I have this JSON:
{
"Alphaville I": { //FIRST KEY
"ida": [{ //SECOND KEYS
"hora": "05:40",
"local": "AV. FERNÃO DIAS PAES LEME (Pref. Várzea Paulista)"
},... ],
"volta": [{ //SECOND KEYS
"hora": "05:40",
"local": "AV. FERNÃO DIAS PAES LEME (Pref. Várzea Paulista)"
},... ]
}, ... //MULTIPLE ITENS
}
So, in one view i create a list with the first keys (like Alphaville I), but i need to search the local inside of it.
But the Angular 2 *ngFor requires an array, so i iterate through my object and push it to an array, doing this it excludes my first key, so what i'm doing now (without searching, of course) is saving the keys in one array, geting the index and passing the jsonResultExample[index] to another page.
i'm using the basic searchbar example like the one in Seachbar Component Docs.
So what i need is: Search by the local key and return the first key (Alphaville I) of the nodes the contain the input text, the same local can appear in other first keys.
How can i do this? I can't post a better code because i haven't tried anything.
Is there a better way to structure my JSON for this? (i'm using firebase btw);
Any help or ideas is welcome, thanks.
EDIT
So i saved the first key value along with ida and volta so i can simply iterate through it, get the key value and everything without many problems, but since i need to filter by local it appears inside idaand volta as another array (cause i have many of these values), so it's looking like this now:
So now how can i access the local? Is it better to create another object only with all local and a key for every linha so i can return the values?
Remembering this is the searchbar code for Ionic 2 and my JSON has over 4k lines:
getItems(ev: any) {
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the searchbar
let val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.items = this.items.filter((item) => {
return (item.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
Thanks in advance :)
It comes to personal experience on how to design data structure. Therefore I can't say the follow method is the best way.
First, in the case that we have complicated data structure, I don't prefer using map (a.k.a. object as data structure) in javascript. The main reason is pretty related to what you are facing, object by design cannot be iterated. Yes you can use Object.keys() or Object.values() but they are so ugly and hard to fit on every cases.
It is a nice move to put your first key as a property. That comes to the second problem. There seems to be an assumption in your structure that, one linha is mapped only to one local or one local is only related to one linha. If so, I suggest building another separated map only for the linha and local relationship.
Another approach is to normalize your data structure in to multiple separated javascript objects like what you do on database. By doing so, you can maximize the data flexibility that you can query whatever you want by Array.prototype.filter(), Array.prototype.map() or even directly access by its index. However, this approach may increase the lines of code as you need to manage multiple maps.
I was actually looking for a way to pass by reference in AS3 but then it seemed that adobe and lots of people's understanding of pass by reference is different from what I have been taught at the university. I was taught java was pass by value and C++ allowed pass by reference.
I'm not trying to argue what pass by value and reference are. I just want to explain why I'm using pass by object in the question...
Back to the question, I would like to do something like:
public function swapCard(cardA:Cards, cardB:Cards) {
var temp:Cards = cardA;
cardA = cardB;
cardB = temp;
}
...
swapCard(c1, c2);
EDIT: adding two examples on how I'm using the swapCard function
1) in the process of swaping a card between player1 and player2's hand
swapCard(player1.hand[s], player2.hand[t]);
2) in the process of swaping a card between player1's hand and deck
swapCard(player1.hand[s], player1.deck[rand]);
In C++, we only need to add a symbol before the parameters to make it work (and we call THIS pass by reference). But in AS3, cardA and cardB are just pointers to the formal parameters. Here in the function, changing the pointers does not do anything to the formal parameters :(
I have been searching for hours but I couldn't find a way to without knowing all the properties of the Cards.
If I have to change the properties of the cards one by one then maybe I should change swapCard to a static function in class Cards? (because I don't want to expose everything to another class) I'm not sure if this is a good practice either. This is like adding a swap_cars function into class Cars. If I let this happen, what will be next? Wash car, lend car, rent car... I really want to keep the Cards class clean and holds only the details of the card. Is there a possible way to do this properly in AS3?
The kind of swap function that you're trying to implement is not possible in AS3. The input parameters are references to the input objects but the references themselves are passed by value. This means that inside the function you can change the cardA and cardB but those changes will not be visible outside the function.
Edit: I added this portion after you edited your question with sample usage.
It seems like you're trying to swap two objects in 2 different arrays at given array positions in each - you can create a function for this in AS3 but not the way you attempted.
One possible implementation is to pass the arrays themselves and the positions that you're trying to exchange; something like this:
// Assumes arrays and indices are correct.
public function SwapCards(playerHand:Array, playerCardIndex:int,
playerDeck:Array, playerDeckIndex:int):void
{
var tempCard:Card = playerHand[playerHandIndex];
playerHand[playerHandIndex] = playerDeck[playerDeckIndex];
playerDeck[playerDeckIndex] = tempCard;
}
Note that you still exchange references and the arrays themselves are still passed by reference (and the array references are passed by value - you could, if you wanted, change the arrays to new arrays inside this function but you wouldn't see new arrays outside). However, because the array parameters refer to the same arrays inside and outside the function, you can make changes to the contents of the array (or other array properties) and those changes will be visible outside.
This solution is faster than cloning the card because that involves allocating memory for a new Card instance (which is expensive) and that temporary instance will also have to be freed by the garbage collector (which is also expensive).
You mentioned in a comment that you pass cards down to lower levels of code - if you don't have a back reference to the arrays (and the positions of the cards), you will not be able to easily swap cards - in AS3, all input parameters are copies (either the copy of the value for primitive types or the copy of the reference for complex objects - changes to the input parameters in a function will not be visible outside).
EDIT: renaming the function from clone to copyFrom as pointed out by aaron. Seems like clone is supposed to be used as objA = objB.clone()
At this point, I'm adding a copyFrom() function in the Cards class such that
var temp:Cards = new Cards(...);
var a:Cards = new Cards(...);
...
temp.copyFrom(a);
...
temp will be copying everything from a.
public function swapCard(cardA:Cards, cardB:Cards) {
var temp:Cards = new Cards();
temp.copyFrom(cardA);
cardA.copyFrom(cardB);
cardB.copyFrom(temp);
}
I will wait for a week or so to see if there are any other options
You have some good answers already, but based on the comments back-and-forth with me, here's my suggestion (I use "left" and "right" naming because it helps me visualize, but it doesn't matter):
function swapCard(leftCards:Array, leftCard:Card, rightCards:Array, rightCard:Card):void {
var leftIndex:int = leftCards.indexOf(leftCard);
var rightIndex:int = rightCards.indexOf(rightCard);
leftCards[leftIndex] = rightCard;
rightCards[rightIndex] = leftCard;
}
Now you can swap the cards in the two examples you posted like this:
swapCard(player1.hand, player1.hand[s], player2.hand, player2.hand[t]);
swapCard(player1.hand, player1.hand[s], player1.deck, player1.deck[rand]);
However, note that while this swaps the cards in the arrays, it does not swap direct references to the cards in those arrays. In other words:
var a:Card = player1.hand[0];
var b:Card = player2.hand[0];
swapCard(player1.hand, a, player2.hand, b);
// does not change the references a and b, they still refer to the same card
a == player2.hand[0];
a != player1.hand[0];
b == player1.hand[0];
b != player2.hand[0];
Typically, this sort of thing is handled by dispatching a "changed" event so that any code that cares about the state of a player's hand array will know to re-evaluate the state of the hand.
There's a deep misunderstanding going on here. The question is about object reference but the PO is not trying to swap any Object reference at all.
The problem comes from the fact that the PO does not understand the difference between variable and objects. He's trying to swap variable/object reference which is not dynamically possible of course. He wants with a function to make the variable holding a reference to Object A, swap its object reference with another variable. Since Objects can be passed around but not variables (since they are just holders (not pointers)) the task is not possible without a direct use of the given variable.
To resume:
variables are not Objects!
variables hold a reference to an object.
variables cannot be passed in function or referenced in functions because THEY ARE NOT OBJECTS.
I've got an ArrayCollection that serves as a dataProvider for a list.
The collection stores objects of type MyObject:
public class MyObject {
public var myMap:Dictionary;
}
myMapstores key-value pairs, the key being an integer, the values are Strings.
So far for the constraints. What I want to do now is to sort the collection based on fields of the map.
Using a the ArrayCollection's sort function with my own compareFunction does work. This is how I've implemented it:
var key:int = 15;
var sort:Sort = new Sort();
sort.compareFunction = fidSort;
myCollection.sort = sort;
myCollection.refresh();
private function fidSort(a:Object, b:Object, fields:Array = null):int {
if(a.myMap[key].fieldValue == b.myMap[key].fieldValue) {
return 0;
} else if(a.myMap[key].fieldValue > b.myMap[key].fieldValue) {
return 1;
} else{
return -1;
}
}
As I said, that does work for the sake of sorting. However, naturally the sort (being a property of the collection) remains on the collection unless specifically removed from it, which means that every time a value in the map of MyObject changes, it will get sorted according the comparefunction.
What I need is to apply the sort exactly once, what happens afterwards with the map values shouldn't change the collections sorting.
I've tried things like disabling autoupdate on the colleciton (naturally that won't work as the collection doesn't get any updates any more (well it does, but they are cached only)).
After that I've read this post about sorting the underlying array.
However, that doesn't seem to work with the map, as I do get a compile error saying that the myMap[key].fieldValue couldn't be found on MyObject.
So yes, I'm kinda lost in space here. If someone has a clue how to achieve this, very basic task really, please let me know.
Cheers!
Got it, and for the sakes of completeness, I'd like to answer this question myself.
As said before, using myCollection.toArray().sort(fidSort) didn't work completely. The array made in this step has indeed been sorted, the collection, however, didn't get the sort, even though refresh() has been called.
To fix this, instead of creating a new array from the collection, we need to directly use the collection's source (which is an array of course) and sort that array;
collection.source.sort(fidSort);
collection.refresh();
Since we are still only sorting the array and not applying the Sort to the collection itself, the collection is sorted only once, regardless of the updates to it's data.
Edit: Just for kicks, restoring the original item positions isn't possible out of the box when sorting the collection's underlying array like it can be done when applying a sort on an ArrayCollection directly and setting it to null to restore the positions.
Simple solution is to cache the array item indices beforehand.
Ok. so I'm working on an app that retrieves items from a db and builds a gallery. I've done this a ton of times, and it should be simple.
I'm running into problems, because in this gallery, I get results from a db that includes both image files, and other files. Let's just say I can't change anything but the flash, so I need to detect if it's an image, and only display it if it is.
My question is: How the hell can I delete a property from an object without the object staying the same size? I use a count() function to generate pagination data, so I can't just 'null' them, and as I understand it, delete() is not an option either.
My solution for this was to just create another object, filter the good items with a for in loop, then pop them in to another object, but each item in the object is an object, and I have no push() function for objects.
So, in desperation, I am using an increment to add the objects to the new object using an index (goodItemsObject[index] = allItemsObject[object]), but that seems like a really gruesome way of getting around this problem.
Here's some code:
var filteredMO = new Object();
var newFile = 0;
for each(var file in mediaObject){
if(check_file(file)){
filteredMO[newFile] = file;
newFile++;
}
}
mediaObject = filteredMO;
check_file() just returns true or false, mediaObject is all full of objects.
I'd much prefer to be doing this:
for each(var file in mediaObject){
if(check_file(file)){
//remove_from_object_for_reals(mediaObject[file]);
}
}
I realize that might not be possible (would it throw off the for loop?), but something similar would be sweet. I'd love to be able to let the gc grab all these useless objects hanging out.
any ideas?
thanks,
Jesse
What you are using to store your object now is called an associative array. You cannot remove a key-value from an associative array. What you need is a dictionary (which as3 has a build-in one http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Dictionary.html).
import flash.utils.Dictionary;
var dict:Dictionary = new Dictionary();
then you can remove a key from your dictionary by calling
delete dict["myKey"]