how to retrieve data from database using flex code - actionscript-3

I want to display the values coming from database in a datagrid using flex. Here is my code. I am using webservice. I have database values from application1_initializeHandler() method. How to fetch these values into onResult() method and perform databinding? I want code for onResult() function and data binding. Please help..
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" initialize="application1_initializeHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.rpc.AsyncResponder;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
protected function application1_initializeHandler(event:FlexEvent):void
{
AreasOfWestBengal.loadWSDL();
var s:String = "SELECT * FROM [CSFTestNew].[dbo].[AreasOfWestBengal]";
var t:AsyncToken = AreasOfWestBengal.GetRec("[AreasOfWestBengal]", s, "1", "SQLExpress");
t.addResponder(new AsyncResponder(onResult, onFault, t));
}
protected function onResult(event:ResultEvent, token:Object=null):void
{
}
protected function onFault(event:FaultEvent, token:Object=null):void
{
trace(event.fault.toString());
}
]]>
</fx:Script>
<fx:Declarations>
<s:WebService id="AreasOfWestBengal" wsdl="https://www.geoviewer8.com/gv8webservices/CSF_NewGVOConfig/GVOConfig.asmx?wsdl"/>
</fx:Declarations>
<mx:DataGrid x="197" y="83" width="348" height="216">
<mx:columns>
<mx:DataGridColumn headerText="Areas" dataField="Areas"/>
<mx:DataGridColumn headerText="SubAreas" dataField="SubAreas"/>
</mx:columns>
</mx:DataGrid>
</s:Application>
Thanks

One solution would be to set a data provider (like an ArrayCollection) for your mx:DataGrid as its dataProvider attribute - see the Passing Data to a DataGrid Control section here for an example.
Now, when your onResult function executes, you probably want to first clear out your data provider (remove any rows from your DataGrid) - if the data source is an ArrayCollection, you would use the removeAll method. Now obtain the actual web service call result from the ResultEvent parameter (in your code, it is event.result). You need to know the data type of this result value (it should be some kind of list data structure) so that you can figure out how to add its elements into the DataGrid's data provider as rows of the grid. For example, if your data provider is an ArrayCollection, you can add each element of event.result into this ArrayCollection using its addItem method. If event.result implements the IList interface, you could add all rows into the data provider using the addAll method of ArrayCollection. Make sure that the objects that you add into the data provider as the rows conform to your mx:DataGridColumns - i.e. these objects need to have Areas and SubAreas properties so that their values will be displayed in these columns.
Here is a web service-specific DataGrid example from Adobe.
protected function onResult(event:ResultEvent, token:Object=null):void
{
// Assuming the grid's data provider is an ArrayCollection
// (1) clear existing table rows
dataProvider.removeAll();
// (2) add the new rows from event.result into dataProvider
// using dataProvider.addAll(event.result) if possible or one at a time
// using dataProvider.addItem(...)
dataProvider.addAll(event.result);
// An alternative to the above would be to replace the dataProvider
// of your grid with event.result if it is a compatible data type
// AreasOfWestBengal.dataProvider = event.result;
}

Related

Flex: application is confused when passing variables to custom component

I'm new to Flex and I'm missing something very basic about architecting a Flex application -- I've implemented a custom component MyReportGrid and extended GridColumn with MyColumn. I've tried to outline the application code below.
The interesting thing to notice is that class OfficeItems is used by class MyItems, and the MyColumn (which extends GridColumn) includes a customPath variable that is used to access variables pen, pencil, and stapler inside class OfficeItems.
I believe that is the reason why manually sorting (by clicking on the columns in the datagrid) only works for columns corresponding to zipCode and stateCode and NOT pen, pencil, and stapler.
Also, when I try to use a simple labelFunction for zipCode or stateCode it always works fine, but implementing a labelFunction for pen, pencil, or stapler never works. By "never works" I mean that the labelFunction is called correctly, and it performs it's required task in that the labelFunction receives the correct object and actually returns the correct formatted String, but this returned value is never displayed in the datagrid (I'm assuming the customPath variable confuses the labelFunction as to which variable the returned String maps to).
I think these are both the same issue in that the customPath aspect of the MyColumn confuses the application. Any idea how to fix the sorting and/or labelFunction? Thanks in advance for your patience in reading this (long) posting.
The classes are:
package com.supportClasses
{
public class OfficeItems {
public var pen:*;
public var pencil:*;
public var stapler:*;
}
}
and
package com.models
{
import com.supportClasses.OfficeItems;
[Bindable]
public class MyItems extends Model {
public function myItems() {
super();
}
public var office:OfficeItems;
public var zipCode:int;
public var stateCode:String;
}
}
The data grid looks like:
...
<components:MyReportGrid id="myGrid" dataProvider="{_myData}"...>
<components:columns>
<fx:Array>
<supportClasses:MyColumn customPath="office" dataField="pen"... />
<supportClasses:MyColumn customPath="office" dataField="pencil"... />
<supportClasses:MyColumn customPath="office" dataField="stapler"... />
<supportClasses:MyColumn dataField="zipCode"... />
<supportClasses:MyColumn dataField="stateCode"... />
...
where _myData has a class of MyItems (note: the customPath feature is ignored by MyColumn when not present here, such as for zipCode and stateCode). MyColumn is:
package com.components.supportClasses {
import spark.components.gridClasses.GridColumn;
public class MyColumn extends GridColumn
{
public var customPath:String="";
...
public function MyColumn(headerText:String="header" customPath:String="", dataField:String="data", ...) {
this.headerText=headerText;
this.customPath=customPath;
this.dataField=dataField;
...
}
}
}
and MyReportGrid is:
package com.models {
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="400" height="300">
import com.components.myClasses.MyColumn;
import com.itemRenderers.myItemRenderer;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.collections.ListCollectionView;
import spark.components.gridClasses.GridColumn;
...
<s:DataGrid width="100%" ... />
</s:Group>
}
the labelFunction is:
private function redFormat(item:Object, column:MyColumn):String {
var formatResult:String = "red "+item.office.pen;
return formatResult; // returns "red Bic15938" (for example)
}
as called from:
<supportClasses:MyColumn customPath="office" dataField="pen" labelFunction="redFormat"... />
This is just a guess, but could it be something like adding a "toString" function to the OfficeItems class? (I would be using comments, but still working on getting reputation.)

Flex. pushView data Object being converted into a String

After executing a navigator.pushView with data object, I'm in need of the data object to be received into the next view, but at some stage transformed into a string to use in a sql function.
The code below shows what I'm working on at the moment.
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="{data.toString()}"
xmlns:model="model.*"
creationComplete = "{data=srv.findByCategory(data.toString())}"
>
.toString() was my quick attempt at it, but the resultant output is simply
[object Object]
There aren't any errors but it only shows during debug.
Any ideas?
As appendage, here is the code from the initial view where the data object originates from
<s:List id="list" top="0" bottom="0" left="0" right="0" width="100%"
alternatingItemColors="0xffffff"
contentBackgroundColor="0xffffff"
downColor="0xfc7d1a"
selectionColor="0xfc7d1a"
dataProvider="{data}"
labelFunction="getFullName"
change="navigator.pushView(CategoryView, list.selectedItem.toString())">
And here is some of the code which needs the data object to be a String.
public function findByCategory(searchKey:String):ArrayCollection
{
}
data is a keyed object containing containing the info you passed from the initial view. You need to access the correct key in your object.
It should be something like data.myKey.toString(). I would be able to tell you exactly if you paste your pushView code.

Alter ResourceManager to split values by semicolon, not comma

As the title says, is there a way to alter the ResourceManager's getStringArray() in a way that it splits the resources by semicolon, not comma?
The actual method can be found in the ResourceManagerImpl class, which can be found in in the package mx.resources.
Overriding that method would be fine, but ideally I'd like to write my own getStringArray with a variable separator, however, there seems to be no way of extending either the ResourceManager or ResourceManagerImpl class to somehow add that method.
Anyone got a clue what to do here?
The problem is not that you can't extend ResourceManagerImpl since it's not final, but rather that you have to be able to register your implementation with the application instead of the default one. And doing this is a bit tricky.
So first create your implementation:
public class MyResourceManager extends ResourceManagerImpl {
private static var instance:IResourceManager;
static public function getInstance():IResourceManager
{
if (!instance) instance = new MyResourceManager();
return instance;
}
override public function getStringArray(bundleName:String,
resourceName:String,
locale:String = null):Array {
//do your stuff
}
}
So we've overriden the getStringArray method. Notice that we've done the same for getInstance, because we want it to return a new instance of MyResourceManager instead of ResourceManagerImpl (we don't have to mark override because it's a static method). Also, you may have to write some import statements manually, because some of the classes you're using are marked as 'excluded'.
Now we have to tell Flex to use MyResourceManager instead of ResourceManagerImpl. We can do this with the following code:
import mx.core.Singleton;
Singleton.registerClass("mx.resources::IResourceManager", MyResourceManager);
The problem is that we have to do this before Flex registers ResourceManagerImpl, because you can't override it once it's registered. For this we need to create a custom preloader in which we do the registering (sadly, the Application's 'preinitialize' phase is not early enough).
public class RegisteringPreloader extends DownloadProgressBar {
override public function initialize():void {
super.initialize();
Singleton.registerClass("mx.resources::IResourceManager",
MyResourceManager);
}
}
Now assign the custom preloader to the application and we're done:
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
preloader="RegisteringPreloader" >
For further info I refer you to a fairly similar, but somewhat more elaborate answer that I wrote for a different question: Is there a way to listen for events on the pop up manager class?
Just for the record: if you want to provide your localization with array of strings containing commas, it is way easier to use getObject method of IResourceManager.
In your properties file:
my.beloved.strings: ["That's it, string one", "Okay, string two"]
In your code:
var strings:Array = _resourceManager.getObject(_bundleId, 'my.beloved.strings') as Array;
var stringOne:String = strings[0];
You don't have to override anything this way.

Flex : Communicate between the skin and the data model?

How to send to the skin some value which have changed?
There are two approaches to this: one uses binding and is easier, the other is more complex but better for performance.
Using binding
Suppose your view class looks like this:
public class MyClass extends SkinnableComponent {
[Bindable] public var myValue:String;
}
then you can bind to that value in your skin like this:
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
[HostComponent("MyClass")]
</fx:Metadata>
<s:Label id="myLabel" text="{hostComponent.myValue}" />
</s:Skin>
Overriding commitProperties
Assume the same skin without the binding, then you can set the label's text property by using a skinpart and overriding commitProperties in the host component. The skinpart's name must be exactly the same as the id of the component in the skin (in this case 'myLabel').
public class MyClass extends SkinnableComponent {
[SkinPart(required="true")]
public var myLabel:Label;
public var myValue:String;
override protected function commitProperties():void {
if (myLabel) myLabel.text = myValue;
super.commitProperties();
}
}
Of course you would have to call invalidateProperties() whenever you want to apply the new value (for instance in a setter function for 'myLabel'). Also notice that 'myLabel' no longer needs to be bindable, unless you would want to be able to bind on it externally.
edit: which approach to choose?
I have just answered a question that is closely related to this one in which I elaborate on the pro's and cons of each approach in different situations. You can find it here: Flex: Additional label in ButtonBarButton

Action script3 trace in flex builder

this is the code, i am using flex builder 4.5,
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
public var ss:Array = ["a", "b", "c"];
trace(ss[0]);
public var str:String = "Good Luck";
trace(str);
]]>
</fx:Script>
</s:Application>
i get red cross next to trace statment and fault is
"1120:Access of defined property ss"
i have tried the commented line as well but no luck. i have tried with 3.5, 4.1 and 4.5 sdk.
Am i missing something? please guide!!
(i tried googling it but nothing came up )
thanks in advance.
(updated the code)
public var ss:String is a field declaration and trace(ss) is an action in code execution flow. Place trace(ss) in an appropriate scope (in a function aka method) and it will be compiled and executed without any problem.
I think you are getting confused between Class member properties and local variables. Inside a method, you can only declare local variables, for example:
public function debugString() : void {
// declare a local property, only this, 'debugString' function can acess
// or modify this property - it is deleted when this function finishes.
var myString : String = "Hello World";
trace(myString);
}
However, it would appear that you were trying to define Class member properties instead (because you were declaring the visibility of the property (ie: public)).
public class HelloWorld {
// Define a Class member property; all functions in this Class will be
// able to access, and modify it. This property will live for as long as the
// Class is still referenced.
public var myString : String = "Hello World";
public function debugString() : void {
// notice how we did not declare the 'myString' variable inside
// this function.
trace(myString);
}
}
Note that you can only access member properties once a Class has been constructed; so the earliest you can (sensibly) access them is in your Constructor, for example:
class HelloWorld {
public var myString : String = "Hello World";
// This will not work, because you can only access static properties
// outside of a function body. This makes sense because a member property
// belongs to each instance of a given Class, and you have not constructed
// that instance yet.
trace(myString);
// This is the Class Constructor, it will be called automatically when a
// new instance of the HelloWorld class is created.
public function HelloWorld() {
trace(myString);
}
}
What you might be trying to do is make use of a static property; these differ from Class member properties as they are Globally shared amongst all instances of a given class. By convention, static properties are defined in CAPS:
public class HelloWorld {
// Here we define a static property; this is accessible straight away and you
// don't even need to create a new instance of the host class in order to
// access it, for example, you can call HelloWorld.MY_STRING from anywhere in your
// application's codebase - ie: trace(HelloWorld.MY_STRING)
public static var MY_STRING : String = "Hello World";
}