I have an object in localStorage, something like:
{"one":"oneone","two":"twotwo"}
You get the picture.
For some reason attempting to add more items to the object won't work. If I want to add "three":"threethree", it ignores that and when I update the storage area in Opera Dragonfly it shows the same old object, unchanged...
Does anybody know how to append to objects on the fly? Or will I have to append to a copy of the object in my code, then clear the old object from localStorage, and store the updated one? I can see this being the only way, but it seems like it might be a bit ugly... Ideas please! :D
I think that the safest and cleanest way to do this is getting the object from localStorage, parsing it, add some data ans stringify it for storing.
Like you say, it is a bit ugly, but you can create a function to do this
function mergeLocalStorage(key, obj){
var newObj = JSON.parse(localStorage.getItem(key));
for (var k in obj){
newObj[k] = obj[k];
}
localStorage.setItem(key, JSON.stringify(newObj));
return newObj;
}
Related
I have Object parsed from JSON (haxe.Json.parse()) and I need to iterate over it.
I already tried to cast this object to Array<Dynamic>:
var data:String='{"data":{"0":0,"1":1},"method":"test"}';
var res:{method:String,data:Array<Dynamic>} = haxe.Json.parse(data);
for (n in res.data)
trace('aa')
There is no Can't iterate dynamic exception, just not working (iterating).
I completley don't understand why in Haxe iterating procedure is so difficult.
For the sake of posting a complete answer, and in case other people are wondering
In your first example, you've told the compiler that "res" contains two properties - one called "method" (which is a String) and one called "data" (which is Array). Now the JSON you're using doesn't actually have an Array<Dynamic>, it just has a dynamic object. An Array would look like: "data":[0,1].
So, assuming you meant for the JSON to have data as a Dynamic object, here is how you loop over it, using Reflect (as you mentioned in the comments):
var data:String='{"data":{"0":0,"1":1},"method":"test"}';
var res = haxe.Json.parse(data);
for (n in Reflect.fields(res.data))
trace(Reflect.field(res.data, n));
Note here we don't have to specify the type of "res", since we're using Reflection just leaving it as Dynamic will be fine.
Now, if your JSON actually contains an Array, the code might look like this:
var data:String='{"data":[0,1],"method":"test"}';
var res:{method:String,data:Array<Int>} = haxe.Json.parse(data);
for (n in res.data)
trace(n);
Here you use explicit typing to tell the compiler that res.data is an Array (and this time it actually is), and it can loop over it normally.
The reason you didn't get an error at compile-time is because the compiler thought there was genuinely going to be an array there, as you told it there was. At runtime, whether or not it throws an exception probably depends on the target... but you probably want to stay out of that anyway :)
Demo of both styles of code: http://try.haxe.org/#772A2
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.
Would it be possible to serialize a model object into a query string?
I've no idea if this is even possible, but if not, what is the best way to do this?
<% Html.RenderAction("Grid", "Grid", new { gridModel= ViewData["model"]}); %>
The Model is containing ca 20 properties, and creating the querystring with them in individually would make it a pain to work with and it would look really ugly. so what alternatives do I have?
To answer directly, you could use something like JSON.NET to serialize it to ASCII and then base64 encode it.
However, there are very real limits on how much data you can include in the query string and I'd hesitate to do this.
The closest thing I can think of would be to create a GUID, use that GUID as a key to store the object in Session, then pass the RenderAction the GUID. That action would pull the object out of the Session and then remove it from the Session.
Quick pseudocode (not guaranteed to even compile, much less work)
var _requestKey = Guid.NewGuid();
Session[requestKey] = gridModel;
Then on the other side:
var gridModel = Session[requestKey] as GridModelType;
Session[requestKey] = null;
I ended up using Form for this. Wasn't as pretty and nice as I wanted, but as far as I understand the only good way I could do it.
I have an object and a temp object now if i do
tempObj = obj
and change stuff in tempObj they changes have an effect on obj is there a way i can stop it from doing this?
Regards
Mark
This is a standard behavior in many languages. When you do tempObj = obj you are NOT creating a duplicate object. You are creating another reference to the same object.
I don't think you can change this behavior, and certainly I don't think you should :)
What you need is creating another object, a duplicate of the original object. You can implement a function to do that. Maybe this can help
http://blog.comtaste.com/2007/10/improving_object_copy.html
Good luck!
What you are doing is making a reference to the original object not a copy of the original. You should create a deep copy of your object. It seems that someone already wrote the steps to do so...
http://www.as3dp.com/2008/09/23/actionscript-30-clone-a-prelude-to-the-prototype-design-pattern/
Hope this helps
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"]