Does anyone have any recommendations for working with name/value pairs in Flex?
Context:
I want to create a Flex UI for updating a database table. I want the UI to contain the field name(read only) and current field value (which will be editable). Im using the WebService component to retrieve the field value and then asssigning it to an object with the field name hardcoded e.g.
private function resultHandler(event:ResultEvent):Object
{
var resultsObj:Object;
resultsObj = {
name:event.result.name as String,
This approach however is adding the dependency that the table structure/field names will never change. Using the object type also requries that i write my own algorithm to sort the output.
I'm not sure I understand the issue.
If you want to avoid dependency of the properties returned from the event at this point, simply use the event.result object, which is already an associative array.
As for sorting, we would need more context on what you are attempting to sort.
That's pretty simple. Don't use for each in loop. Use For-In Loop
Demo is shown below.
var dicEntry:Object = new Object();
dicEntry["Name"] = "Raj";
dicEntry["sal"] = 10000;
dicEntry["age"] = 33;
for(var key:Object in dicEntry)
{
trace("Object Key: "+key+" Object Value: +dicEntry[key]);
}
That's it.
Related
One of my components needs to fetch different data from a property based on a parameter I pass it. The parameterHolder is an Object with keys and parameter is the key name.
{{component-name parameterHolderBinding=parameterHolder parameterValueBinding=parameter}}
I'm trying to loop through it like so
{{#each item in parameterHolder.[{{parameter}}]}}
{{/#each}}
But it's not working. When I try,
{{parameterHolder.keyName}}
I'm getting [Object] which is correct. Could someone please point out the right way do this?
I've managed to get it working by dynamically creating new properties.
In my controller -
parameterUpdatedObserver: function ()
{
var reference = this;
$.each(parameterHolder, function (key, value) {
reference.set('parameterHolderName'+key, value);
});
}.observes('parameterHolder')
And my component -
{{component-name parameterHolderBinding=parameterHolderNameKey parameterValueBinding=parameter}}
I can probably abstract it up one more level using another component. If anyone has a better solution, please do post it.
I'm doing some Actionscript work right now and I'd like to know whether there's a way to initiate an empty object's value programatically like this:
var myObj:Object = new Object;
myObj.add("aKey","aValue");
To add a property called aKey whose value is aValue
I need to create a "Dumb" (data-only) object to use as a parameter to send via POST. So I don't know offhand how long and/or how many attributes it's gonna have.
Or something like that.
Thanks
ActionScript 3 allows you to create new Objects using an expressive Object Literal syntax similar to the one found in JavaScript:
const myObj : Object = {
aKey: "aValue",
};
trace(myObj.aKey); // "aValue"
If you want to assign properties after the object has been constructed then you can use either dot notation or square bracket notation, eg:
const myObj : Object = {}; // create an empty object.
myObj.aKey = "aValue";
myObj["anotherKey"] = "anotherValue";
If you plan on sending the data over HTTP, you may wish to consider looking at the URLVariables class which will take care of URL encoding the data for you.
So, there are a wealth of Flex articles online about how to handle a .NET WebMethod that returns a DataSet or DataTable. Here is an example:
Handling web service results that contain .NET DataSets or DataTables
So, I know how to use result.Tables.<tablename>.Rows and the like. But what I cannot seem to figure out or find online is how to go the other direction - a method to pass objects or tables back to the .NET Webservice from Flex, without stooping to passing XML as a string, or making huge web service methods that have one parameter for each property/column of the object being stored. Surely others, smarter than I, have tackled this issue.
I am using ASP.NET 2.0 Typed DataSets, and it would be really nice if I could just pass one object or array of objects from Flex to the web service, populate my Typed DataTable, and do an Update() through the corresponding typed TableAdapter. My dream would be a [WebMethod] something like one of these:
public void SaveObject(TypedDataTable objToSave) { ... }
public void SaveObject(TypedDataSet objToSave) { ... }
I've had the typed datatables saving to the database, I know how to do that part and even a few tricks, but we had XML being passed back-and-forth as a string - eww. I'm trying to get to a more object-based approach.
The best object based approach is AMF. I assume its probably a bit late in your your development cycle to change your integration layer, but otherwise I dont know of a way to get around marshalling your object(s) back into XML or separating them out into their primitive components.
For .NET implementations of AMF check out:
FlourineFX(FOSS)
WebORB for .NET
Its amazing how easy things become once AMF is used, for example using the Mate MVC framework and an AMF call passing a complex object to the server looks something like this:
<mate:RemoteObjectInvoker instance="yourWebservice" method="saveComplexObject" showBusyCursor="true" >
<mate:resultHandlers>
<mate:CallBack method="saveComplexObjectSuccess" arguments="{[resultObject]}" />
</mate:resultHandlers>
<mate:faultHandlers>
<mate:MethodInvoker generator="{DataManager}" method="presentFault" arguments="{fault}" />
</mate:faultHandlers>
</mate:RemoteObjectInvoker>
With result and fault handlers being optional.
The direction I ended up going was close to what I hoped was possible, but is "hack-ish" enough that I would consider SuperSaiyen's suggestion to use AMF/ORM a better solution for new/greenfield projects.
For sake of example/discussion, let's say I am working with a Person table in a database, and have a typed DataSet called PeopleDataSet that has PersonTableAdapter and PersonDataTable with it.
READ would look like this in .NET web service:
[WebMethod]
public PeopleDataSet.PersonDataTable GetAllPeople() {
var adapter = new PersonTableAdapter();
return adapter.GetData();
}
... which in Flex would give you a result Object that you can use like this:
// FLEX (AS3)
something.dataProvider = result.Tables.Person.Rows;
Check out the link I put in the question for more details on how Flex handles that.
CREATE/UPDATE - This is the part I had to figure out, and why I asked this question. The Flex first this time:
// FLEX (AS3)
var person:Object = {
PersonID: -1, // -1 for CREATE, actual ID for UPDATE
FirstName: "John",
LastName: "Smith",
BirthDate: "07/19/1983",
CreationDate: "1997-07-16T19:20+01:00" // need W3C DTF for Date WITH Time
};
_pplWebSvcInstance.SavePerson(person); // do the web method call
(For handling those W3C datetimes, see How to parse an ISO formatted date in Flex (AS3)?)
On the .NET web service side then, the trick was figuring out the correct Type on the web method's parameter. If you go with just Object, then step into a call with a debugger, you'll see .NET figures it is a XmlNode[]. Here is what I figured out to do:
[WebMethod]
public int SavePerson(PeopleDataSet p) {
// Now 'p' will be a PeopleDataSet with a Table called 'p' that has our data
// row(s) (just row, in this case) as string columns in random order.
// It WILL NOT WORK to use PeopleDataSet.PersonDataTable as the type for the
// parameter, that will always result in an empty table. That is why the
// LoadFlexDataTable utility method below is necessary.
var adapter = new PersonTableAdapter();
var tbl = new PeopleDataSet.PersonDataTable();
tbl.LoadFlexDataTable(p.Tables[0]); // see below
// the rest of this might be familiar territory for working with DataSets
PeopleDataSet.PersonRow row = tbl.FirstOrDefault();
if (row != null) {
if (row.PersonID > 0) { // doing UPDATE
row.AcceptChanges();
row.SetModified();
}
else { // doing CREATE
row.CreationDate = DateTime.UtcNow; // set defaults here
row.IsDeleted = false;
}
adapter.Update(row); // database call
return row.PersonID;
}
return -1;
}
Now, the kluge utility method you saw called above. I did it as extension method, that is optional:
// for getting the Un-Typed datatable Flex gives us into our Typed DataTable
public static void LoadFlexDataTable(this DataTable tbl, DataTable flexDataTable)
{
tbl.BeginLoadData();
tbl.Load(flexDataTable.CreateDataReader(), LoadOption.OverwriteChanges);
tbl.EndLoadData();
// Probably a bug, but all of the ampersand (&) in string columns will be
// unecessarily escaped (&) - kluge to fix it.
foreach (DataRow row in tbl.Rows)
{
row.SetAdded(); // default to "Added" state for each row
foreach (DataColumn col in tbl.Columns) // fix & to & on string columns
{
if (col.DataType == typeof(String) && !row.IsNull(col))
row[col] = (row[col] as string).Replace("&", "&");
}
}
}
I have the following dictionary in flex, and i d like to sort it by value. Couldn't find any resource.
'1'=>2, '0' =>1, '3'=>4 ..
Any ideas ? How can i sort this by value ?
I searched around for a similar solution, except that I needed to sort the dictionary map and return a sorted collection relating key value pairs. After failing to find a published solution I put together the approach below. This method takes a dictionary as input, creates an array maintaining the association then sorts the resultant array using array.sortOn() and returns the sorted results back as an array. "key" and "value" fields in the array in the example below are used for clarity, but any field name could be used.
This example assumes a string object as a key and a numeric object as a value, though of course any object type could be used, and field parameters adjusted.
The approach below could also be used for sorting by key instead of value by using "key" as the sort field for the sortOn method, and you could use different sort options than the descending numeric sort I used here( AS3 SortOn() documentation) Code below is intentionally non-generic to simplify it for example purposes.
public static function sortDictionaryByValue(d:Dictionary):Array
{
var a:Array = new Array();
for (var dictionaryKey:Object in d)
{
a.push({key:dictionaryKey,value:d[dictionaryKey]});
}
a.sortOn("value",[Array.NUMERIC|Array.DESCENDING]);
return a;
}
Probably not the best way to do it but it works:
var a:Array = new Array();
for each (var v:Number in dict)
{
a.push(v);
}
a.sort();
Is there a simple way to retrieve the length of an associative array (implemented as an Object) in ActionScript 3.0?
I understand that there are two primary ways of creating associative arrays in AS3:
Use a Dictionary object; especially handy when the key does not need to be a string
Use an Object, and simply create properties for each desired element. The property name is the key, and the value is, well, the value.
My application uses approach #2 (using the Object class to represent associative arrays).
I am hoping there is something more native than my for loop, which manually counts up all the elements.
You have to count them in a for loop as you do. Of course, you could make a class and stick the for loop in that class.
For some great implmentations of Collections in AS3, check these guys.
Edit 2013 Not surprisingly, links do break after time. Try this new one: http://www.grindheadgames.com/get-the-length-of-an-object.
Doing a few tests on this has actually surprised me. Here's normal use of an Array:
var things:Array = [];
things.push("hi!");
trace(things.length);
// traces 1
trace(things);
// traces hi!
Here's if we set a value to a string:
var things:Array = [];
things["thing"] = "hi!";
trace(things.length);
// traces 0
trace(things);
// traces an empty string
trace(things["thing"]);
// traces hi!
Basically if you add things using strings you're setting properties rather than actually adding to the array. Makes me wonder why Array is dynamic in this way.
So... yeah count the items with a for ... in loop!
I think you're stuck with counting them "manually".
An option would be to wrap the whole thing in a class and keep a separate variable that you update as you add/remove.
var count:int;
var key:String;
for (key in myObject)
{
count++;
}
trace ("myObject has this many keys in it: " + count);
or, alternatively, the for-each syntax (I haven't tested to see which is faster)
for each (var o:* in myObject)
{
count++;
}