As the title suggests, is it possible to use AMF to encode/decode Dictionaries (without subclassing, that is)?
For example, here's a test case:
function serializeAndReload(obj:*):* {
var serialized:ByteArray = new ByteArray();
serialized.writeObject(obj);
serialized.position = 0;
return serialized.readObject();
}
function test():void {
var d:Dictionary = new Dictionary();
d[{}] = 42;
d[d] = true;
var x:* = serializeAndReload(d); // <<< x is an instance of Object
trace(x['[object Object]']); // <<< traces '42'
}
You may be over-thinking. I use Object instead of Dictionary and it is automatically encoded using AMF. I use pyamf all the time to pass Objects/dicts around and its always worked without any mental effort on my part. Never have I needed to manually serialize/deserialize anything
The keys in the Dictionary need to be serializable, too.
[RemoteClass(alias="Foo")]
public class Foo
{
}
Test:
var d:Dictionary = new Dictionary();
var f:Foo = new Foo();
d[f] = "Hello";
var ba:ByteArray = new ByteArray();
ba.writeObject(d);
ba.position = 0;
var d2:Dictionary = Dictionary(ba.readObject());
for (var key:* in d2)
{
trace(getQualifiedClassName(key));
trace(d2[key]);
}
Output:
Foo
Hello
Related
In this example:
var poets:Array = new Array();
poets.push({name:"Angelou", born:"1928"});
poets.push({name:"Blake", born:"1757"});
poets.push({name:"cummings", born:"1894"});
poets.push({name:"Dante", born:"1265"});
poets.push({name:"Wang", born:"701"});
Is it possible for 'name' and 'born' to be variables?
As #RIAstar points out, they are properties of an 'associative array' - your dynamic Object{}:
var poets:Array = new Array();
poets.push({"name":"test","born":"1928"});
poets.push({name:"Angelou", born:"1928"});
poets.push({name:"Blake", born:"1757"});
poets.push({name:"cummings", born:"1894"});
poets.push({name:"Dante", born:"1265"});
poets.push({name:"Wang", born:"701"});
trace(poets[0].name,poets[0].born);
or if a more expanded version:
var prop1:String = "name";
var prop2:String = "born";
var poets:Array = [];
poets[0] = {};
poets[0][prop1] = "test2";
poets[0][prop2] = "1900";
trace(poets[0].name,poets[0].born);
If you want to create a function that returns data given the attribute name, you can do something like this:
public function getDataByAttribute(fieldName:String):Array {
return poets.map(
function (item:*, index:int, array:Array):String {
return item[fieldName];
}
);
}
// sample call
var results:Array = getDataByAttribute("born");
You can modify it to suit your needs.
To explore Array's functions, see this blog (not mine).
My AIR-Application is based on Mate.
I receive Data from a SQLite and put the Date into a ArrayCollection.
In the class of my AdvancedDataGrid, i create a GroupingCollection via mxml. All works fine.
I prefer to build the GroupingCollection in Actionscript. But i can't find anything, how to code this.
In the adobe help itself, they create a GroupingCollection in mxml.
The goal is, to instanciate the gc in model of mate for another class. This will be a chart and the dataProvider must be the gc.
Another Idea is, to build the groupingCollection and put it into the model via two-way-bindung. But I'm not sure, if this will work.
Have you any hint for me?
Thank you
Frank
It works like this. What a fight.
private function onCreationComplete () :void
{
adg.dataProvider = createDataProvider();
}
private function createDataProvider () :GroupingCollection2
{
var tmp:GroupingCollection2 = new GroupingCollection2();
tmp.source = dpArrColl;
tmp.grouping = adgGrouping();
tmp.refresh(false);
return tmp;
}
private function adgGrouping () : Grouping
{
var tmp:Grouping = new Grouping();
tmp.fields = [groupingFieldArray()];
return tmp;
}
private function groupingFieldArray () :GroupingField
{
var tmp:GroupingField = new GroupingField();
tmp.name = "groupName1";
tmp.summaries = [adgSummaries()];
return tmp;
}
private function adgSummaries () : SummaryRow
{
var tmp:SummaryRow = new SummaryRow();
tmp.summaryPlacement = "group";
tmp.fields = [adgSummaryFiled1(), adgSummaryField2()];
return tmp;
}
private function adgSummaryFiled1 () :SummaryField2
{
var tmp:SummaryField2 = new SummaryField2();
tmp.dataField = "Sumfiel1";
tmp.summaryOperation = "SUM";
return tmp;
}
private function adgSummaryField2 () : SummaryField2
{
var tmp:SummaryField2 = new SummaryField2();
tmp.dataField = "Sumfield2";
tmp.summaryOperation = "COUNT";
return tmp;
}
I hope, someone will help this someday.
BR
Frank
I use the following to upload a file to Flex:
private var filer:FileReference;
protected function button1_clickHandler(event:MouseEvent):void
{
var fd:String = "Files (*)";
var fe:String = "*";
var ff:FileFilter = new FileFilter(fd, fe);
filer = new FileReference();
filer.addEventListener(Event.SELECT, onFileSelect);
filer.browse(new Array(ff));
filer.addEventListener(Event.COMPLETE,
function (e:Event):void {
e.currentTarget.data.toString();
}
);
}
private function onFileSelect(e:Event):void {
filer.load();
}
And my file looks like this:
Here is the original file: http://sesija.com/up/1.txt
I need to read the uploaded file and parse it. The problem is that in my e.currentTarget.data.toString(); I get only '1' and not the rest of the String.
Any idea on how to successfully read this entire txt file?
The data property is a ByteArray. Instead of using the toString method (which apparently treats NULL byte as end of string), use specific read methods of the ByteArray class like readByte, readInt etc.
var array:Array = [];
var ba:ByteArray = e.currentTarget.data as ByteArray;
while(ba.bytesAvailable != 0){
array.push(ba.readByte());
}
trace(array.join(", "));
You might want to read Working with byte arrays
I think I've established that in as3corelib JSON.decode I have no choice but to deserialise to a plain old flex object.
var data:Object = JSON.decode(json);
If I then want to get the data contained in the object into another type I can't use type casting. I have to instantiate a new instance and add the properties manually.
var data:Object = JSON.decode(json);
var model:Model = new Model();
model.name = data.name;
model.notes = data.notes;
A pain and a bit ugly, but I'm guessing this is the price to be paid for going from untyped json to a flex type. My first question is whether my assumption is correct and there is no prettier way to create my model instance with the data contained within the json?
My second question, if so then before I write my own method to do this, is there anything inside the flex api that will take the data object and mixin it's values to my model instance?
Cheers,
Chris
the approach I've always used proved to be part of the AMF3 serialization mechanism in ActionScript.
have a look at IExternalizable and registerClassAlias.
now what I use is the following:
interface ISerializable {
public function getRawData():Object;
public function setRawData(param:Object):void;
}
function registerType(id:String, type:Class):void {
//implementation
}
function getTypeByID(id:String):Class {
//implementation
}
function getTypeID(type:Class):String {
//implementation
}
and to the decoder/encoder you register a class alias.
serialization of an object works as follows:
var raw:Object = model.getRawData();
raw[" type"] = getTypeID(model);
var encoded:String = JSON.encode(raw);
decoding works as follows:
var raw:Object = JSON.decode(raw);
var cl:Class = getTypeByID(raw[" type"]);
if (cl == null) throw new Error("no class registered for type: "+raw[" type"]);
delete raw[" type"];
var model:ISerializable = new cl();
model.setRawData(raw);
you will need to do this recursively on the whole deserialized JSON tree, starting at the leafs.
For cyclic reference, you'll need a trick.
I had an implementation of this somewhere, but I can't find it.
You can loop within the field of you json decoded object and assign them into your model:
function json2model(json:String):Model{
var data:Object = JSON.decode(json);
var m:Model=new Model();
for (var field:String in data) {
if (m.hasOwnProperty(field)) {
m[field] = data[field];
}
}
return m;
}
var model:Model=json2model(json)
or add a static function within your Model if you preffer:
public class Model {
//...
public static function fromJSon(json:String):Model {
var data:Object = JSON.decode(json);
var m:Model=new Model();
for (var field:String in data) {
if (m.hasOwnProperty(field)) {
m[field] = data[field];
}
}
return m;
}
}
}
var model:Model=Model.fromJSon(json);
I am calling a web Method from javascript. The web method returns an array of customers from the northwind database. The example I am working from is here: Calling Web Services with ASP.NET AJAX
I dont know how to write this javascript method: CreateCustomersTable
This would create the html table to display the data being returned. Any help would be appreciated.
My javascript
function GetCustomerByCountry() {
var country = $get("txtCountry").value;
AjaxWebService.GetCustomersByCountry(country, OnWSRequestComplete, OnWSRequestFailed);
}
function OnWSRequestComplete(results) {
if (results != null) {
CreateCustomersTable(results);
//GetMap(results);
}
}
function CreateCustomersTable(result) {
alert(result);
if (document.all) //Filter for IE DOM since other browsers are limited
{
// How do I do this?
}
}
else {
$get("divOutput").innerHTML = "RSS only available in IE5+"; }
}
My web Method
[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
NorthwindDALTableAdapters.CustomersTableAdapter adap =
new NorthwindDALTableAdapters.CustomersTableAdapter();
NorthwindDAL.CustomersDataTable dt = adap.GetCustomersByCountry(country);
if (dt.Rows.Count <= 0)
{
return null;
}
Customer[] customers = new Customer[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
NorthwindDAL.CustomersRow row = (NorthwindDAL.CustomersRow)dt.Rows[i];
customers[i] = new Customer();
customers[i].CustomerId = row.CustomerID;
customers[i].Name = row.ContactName;
}
return customers;
}
Try to look what is the result variable value in debug mode. If the structure seems the structure that i'm imagining, something like this could work:
function CreateCustomersTable(result) {
var str = '<table>';
str += '<tr><th>Id</th><th>Name</th></tr>';
for ( var i=0; i< result.length; i++){
str += '<tr><td>' + result[i].CustomerId + '</td><td>' + result[i].Name + '</td></tr>';
}
str += '</table>';
return str;
}
And then You can do somethig like this:
var existingDiv = document.getElementById('Id of an existing Div');
existingDiv.innerHTML = CreateCustomersTable(result);
I wish this help you.
Something like this, assuming you have JSON returned in the "result" value. The "container" is a div with id of "container". I'm cloning nodes to save memory, but also if you wanted to assign some base classes to the "base" elements.
var table = document.createElement('table');
var baseRow = document.createElement('tr');
var baseCell = document.createElement('td');
var container = document.getElementById('container');
for(var i = 0; i < results.length; i++){
//Create a new row
var myRow = baseRow.cloneNode(false);
//Create a new cell, you could loop this for multiple cells
var myCell = baseCell.cloneNode(false);
myCell.innerHTML = result.value;
//Append new cell
myRow.appendChild(myCell);
//Append new row
table.appendChild(myRow);
}
container.appendChild(table);
You should pass the array as JSON or XML instead of just the toString() value of it (unless that offcourse is returns either JSON oR XML). Note that JSOn is better for javascript since it is a javascript native format.
Also the person who told you that browser other then IE can not do DOM manipulation should propably have done horrible things to him/her.
If your format is JSON you can just for-loop them and create the elements and print them. (once you figured out what format your service returns we can help you better.)