How would I debug Flex 3 databinding? - apache-flex

I'm trying to connect a datagrid to an HTTPService via a simple external XML document, and this is failing. How would I go about debugging where the problem is arising?
I'm using the following:
<mx:HTTPService id = "licenseService" resultFormat="e4x" url="http://localhost/licenseTest.xml" />
with
<mx:DataGrid horizontalCenter="0" width="476" top="50" dataProvider="{licenseService.lastResult.license}">
I'm relatively new to flex, so basic help would be appreciated.

Add result event handler for HTTP Service:
<mx:HTTPService id = "licenseService" resultFormat="e4x" url="http://localhost/licenseTest.xml" result="licenseService_resultHandler(event)" />
And define the handler inside <mx:Script>:
private function licenseService_resultHandler(event:ResultEvent):void
{
trace("Result:", event.result);
}
You can place a breakpoint inside this method and start debugging the data that comes from the server

Related

popup editor for datagrid items - hangs the browser

i've got a pretty straightforward thing: a datagrid which renders some items. clicking on an item would bring up a popup editor (as the item has lots of properties and may not be edited right in the datagrid).
the popup contains just a form and a [Bindable] reference to the item it edits (which is passed from itemClick handler of the datagrid). form's default values are taken by binding to corresponding item properties with {} notion, while form values are bound back to the item using mx:Binding tags.
and now the problem. when the popup is brought up for the first time, everything is fine. however, when after being closed the popup is brought up again by clicking on the same item, the browser hangs (afaik because of change watchers being endlessly fired resulting in stackoverflow or something similar).
we have same behaviour in Safari, IE and Chrome, so i guess it's not to do with something browser-related. removing either [Bindable] from the item reference in the popup or mx:Binding tags from editors suppresses the problem, but of course the editing no longer works.
i'm banging my head against the wall for several days already, but still can't make it work. does it ring a bell to someone, what can be wrong in here (what can be damn easier that this)?
here's the code of the popup:
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" title="Details"
showCloseButton="true" close="PopUpManager.removePopUp(this);" creationComplete="PopUpManager.centerPopUp(this)">
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
import my.Detail;
[Bindable] private var _documentDetail:Detail;
public function set documentDetail(value:Detail):void {
this._documentDetail = value;
}
public function set readOnly(value:Boolean):void {
if (value) {
this.currentState = "read-only";
}
}
]]>
</mx:Script>
<mx:states>
<mx:State name="read-only">
<mx:SetProperty target="{startDate}" name="enabled" value="false"/>
<mx:SetProperty target="{comments}" name="enabled" value="false"/>
</mx:State>
</mx:states>
<!--
<mx:Binding source="this.startDate.selectedDate" destination="_documentDetail.startDate"/>
<mx:Binding source="this.comments.text" destination="_documentDetail.comment"/>
-->
<mx:VBox width="100%" height="100%">
<mx:FormItem label="{resourceManager.getString('eRequestAppli','startdate')}:" labelWidth="160" width="100%">
<mx:DateField id="startDate" width="100%" selectedDate="{_documentDetail.startDate}" formatString="{resourceManager.getString('eRequestAppli', 'dateformat')}" editable="false"/>
</mx:FormItem>
<mx:FormItem label="{resourceManager.getString('eRequestAppli','comments')}:" labelWidth="160" width="100%" height="79">
<mx:TextArea id="comments" width="100%" height="100%" text="{_documentDetail.comment}" editable="false"/>
</mx:FormItem>
</mx:VBox>
</mx:TitleWindow>
here's how i call it:
private function show(detail:Detail, readOnly:Boolean=false):void {
var popup:fxc_ProposalDetail =
fxc_ProposalDetail(PopUpManager.createPopUp(UIComponent(Application.application), fxc_ProposalDetail, true));
popup.documentDetail = detail;
popup.readOnly = readOnly;
}
Thanks for posting the code. Now I might be able to help.
Where are you handling the close event of the popup? Besure to use something like this:
private function handleCloseEvent():void {
PopUpManager.removePopUp(this);
}
Besides that it appears your problem has to do with the following:
Because a module is loaded into a child domain, it owns class definitions that are not in the main application’s domain. For example, the first module to load the PopUpManager class becomes the owner of the PopUpManager class for the entire application because it registers the manager with the SingletonManager. If another module later tries to use the PopUpManager, Adobe ® Flash® Player throws an exception.
The solution is to ensure that managers such as PopUpManager and any other shared services are defined by the main application (or loaded late into the shell’s application domain). When you promote one of those classes to the shell, the class can then be used by all modules. Typically, this is done by adding the following to a script block:
import mx.managers.PopUpManager;
private var popUpManager:PopUpManager;
The module that first uses the component owns that component’s class definition in its domain. As a result, if another module tries to use a component that has already been used by another module, its definition will not match the existing definition. To avoid a mismatch of component definitions, create an instance of the component in the main application. The result is that the definition of the component is owned by the main application and can be used by modules in any child domain.
see: http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-799a.html
for a better understanding of modules.
as suggested before, reusing the popup instead of creating a new one each time seems to have solved the issue.

How to Send Info From a Flex 3 Component?

I need some help with sending info from a component. I'm not sure how to proceed.
I'm using Alex Uhlmann's flip card class (Distortion Effects). I've got a card that has 3 faces. When the user clicks the button, it fires a change event, and in the main application, the change event calls a function, flipTo, that flips the card. The component is below:
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel
xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="500"
height="400">
<mx:Metadata>
[Event("change", type="mx.events.Event")]
</mx:Metadata>
<mx:Script>
<![CDATA[
[Bindable]
public var backCaption:String;
]]>
</mx:Script>
<mx:Text id="myAnswer" htmlText="{backCaption}" width="100%" />
<mx:ControlBar height="40" width="100%" >
<mx:Button
x="20" y="400"
label="Flip"
click="dispatchEvent( new Event( Event.CHANGE ) );" />
</mx:ControlBar>
</mx:Panel>
The main application looks like:
<mx:Canvas id="homeStack" >
<mx:ViewStack id="flipViewStack2" x="200" y="150" >
<sides:FlipFace
id="frontFace2"
title="Newport"
change="flipTo(frontFace2, backFace2, DistortionConstants.LEFT, DistortionConstants.RIGHT);" />
<sides:FlipReverse
id="backFace2"
title="Newport: Answer"
change="flipTo(backFace2, anotherFace2, DistortionConstants.LEFT, DistortionConstants.LEFT);" />
<sides:FlipAnotherSide
id="anotherFace2"
title="Other Stuff"
change="flipTo(anotherFace2, frontFace2, DistortionConstants.RIGHT, DistortionConstants.LEFT);"/>
</mx:ViewStack>
</mx:Canvas>
<mx:Canvas id="OtherStack" >
(more code)
</mx:Canvas>
The flipTo function in the main application takes 4 parameters: the starting side, the ending side, and then two parameters that determine the direction of the flip.
Everything works great. If I hit the button, I can flip through all of the sides. But, I'd like to add a comboBox, so that the user can flip directly to the side that they want instead of having to cycle through all of the sides. (This is important as I plan to add more sides).
In the main application, please note that the sides have the number 2 in their ids. For example, frontFace2. I've got multiple sets of cards each with a different number, frontFace3, frontFace4, etc. The number determines which data is pulled from the database. (I've simplified the code for brevity).
How can I add a comboBox in the component that causes the card to flip to the selected side?
Do I need a custom event? (Unfortunately, I don't know anything about custom events). Is there a way to have the comboBox set a public variable and then somehow access that variable in the main application and call flipTo with the comboBox's chosen side? Other possibilities?
Any suggestions?
Thank you.
-Laxmidi
oh, yeah, you will need a custom event.
the custom event is your inheritance to the Event class which on it you can load more data, params, views and more.
in your case, things are a bit more simple but you will need to see what "face" the user selected and flip to it.
steps
1. create a custom event (inherit from event)
2. add a var to the event class that's called face
3. when the user selects the value from the combo, fill the face var with value and dispatch the event
4. listen to the event in the application level and then flipTo the relevant face.

Updating external Flex components from an action

I'm new to Flex and am having trouble understanding Events. I think Events are what I want to use for my situation. I have 2 components, addUser.mxml and listUsers.mxml. I access these from a ViewStack in my main application. When I load listUsers.mxml it shows a list of current users in a datagrid via a HTTPService call. When I add a user using the form on addUser.mxml I would like the datagrid in listUsers.mxml to refresh when I return to that view to show the new user. I've tried several different things with addEventListener and dispatchEvent but can't seem to get it working. Can someone help me with this logic?
--
Sample code for comment, I've parsed out the non-relative stuff.
adduser look like this:
<mx:HTTPService id="httpService"
url="{'http://someurl.com'}"
useProxy="false"
method="POST"
fault="faultHandler()"
result="resultHandler(event)"
/>
public function addUser():void{
if(validateForm()){
params = {};
params['action'] = 'adduser';
params['firstName'] = firstName.text;
params['lastName'] = lastName.text;
params['email'] = email.text;
params['isActive'] = isActive.selected;
httpService.cancel();
httpService.addEventListener("result", addUserResult);
httpService.send(params);
}
}
public function addUserResult(event:ResultEvent):void{
var result:Object = event.result;
//reset fields if add user was successful
if(result.returnXML.action=='adduser'){
var m:String = result.returnXML.message.toString();
if(result.returnXML.status=='fail'){
Alert.show(m, null, Alert.OK, null, null, Application.application.IconError);
}
if(result.returnXML.status=='success'){
firstName.text = "";
lastName.text = "";
email.text = "";
isActive.selected = true;
Alert.show(m, null, Alert.OK, null, null, Application.application.IconSuccess);
}
}
}
<mx:Button id="addButton" label="Add" click="addUser();" />
listUsers looks like this:
<mx:HTTPService id="httpListService"
url="{'http://someurl.com'}"
useProxy="false"
method="POST"
fault="faultHandler()"
result="resultHandler(event)"
/>
<mx:DataGrid id="dgUsers"
itemClick="dgClickEvent(event);"
width="85%"
maxHeight="500"
>
<mx:columns>
<mx:DataGridColumn headerText="First Name" dataField="fn" />
<mx:DataGridColumn headerText="Last Name" dataField="ln" />
<mx:DataGridColumn headerText="Email" dataField="email" />
<mx:DataGridColumn headerText="Active" dataField="active" />
</mx:columns>
</mx:DataGrid>
I don't think event listeners are necessarily the way to go. You use an event listener to do something upon detection of something else. ie) listening for a mouse down on a ui component = detect mouse down, do drag operation.
Given your example I think you just need to chain your functions together. It looks like your addUser function saves the user to the same source as your list users gets data from, so in your position I would call the listUsers httpService at the end of the add user result to refresh your data populating the datagrid.
httpListService.send()
I don't see your result handler for httpListService but that's where you update the data in your dataGrid.
good luck, and please post back with any complications.
Got it working. Here's what i did - basically everytime the parent viewstack brings the listUsers view into focus, it sends the httpListService and refreshes the datagrid regardless of any events (or non events) in the addUser component or any other component. it adds to the network traffic but, for the scope of my project, that is acceptable.
in listUsers.mxml:
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
...
public function init():void{
//vsUsers is my view stack on the main application component
Application.application.vsUsers.addEventListener(IndexChangedEvent.CHANGE, refreshUsersGrid);
}
...
public function refreshUsersGrid(e:IndexChangedEvent):void{
//if the new viewable child is the list users view, then refresh the datagrid
if(Application.application.vsUsers.getChildAt(e.newIndex).name=='viewListUsers'){
//the sendListUsersRequest method fires the HTTPService send method and binds the results to the datagrid
sendListUsersRequest();
}
}

Problem with setting the xml dataprovider for combo box

I am trying to get the drop down list of combobox by using a php file. That php file returns an xml string which has been used as data provider for combobox.
I followed this thread too but in vain.
Details
I have set the creationComplete attribute of mx:Application to init(). In the init() function i have sent the following HTTPService
<mx:HTTPService id="interfaces" url="interfaces.php" resultFormat="e4x" method="POST">
</mx:HTTPService>
Combo Box:
Update:
The xml should look like
<?xml version=\"1.0\" encoding=\"utf-8\"?>
<ifaces>
<iface>
<option>eth0</option>
</iface>
<iface>
<option>eth1</option>
</iface>
</ifaces>
but if i execute interfaces.php in browser the only things that gets display is
eth0eth1
whereas i am echoing the string that contains whole xml data. Shouldn't whole xml type of string display? :(
The problem is that ifaces is the root element of your XML, so interfaces.lastResult == ifaces. So the XMLList you want is interfaces.lastResult.iface.
This is a whole main class that works for me:
`<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
initialize="{interfaces.send();}">
<mx:HTTPService id="interfaces" url="interfaces.xml" resultFormat="e4x" method="POST">
</mx:HTTPService>
<mx:ComboBox dataProvider="{interfaces.lastResult.iface}" labelField="option"/>
</mx:Application>`

How can I target a Flex 3 datagrid in MXML from Actionscript?

I have a datagrid defined in an mxml file (flex 3):
I am using an external class to connect to a sqlite database and generate some results (this is working and I can trace the results).
How can I target the datagrid generated in the mxml from the external class? I have tried:
Application.application.resultsGrid.dataProvider = results.data;
And get 'Error: Access of undefined property Application.' from the amxmlc compiler.
I've also tried:
[Bindable]
public var resultsGrid:DataGrid;
In the class properties.
Looks like I needed to include import mx.core.*; and it now works.
I don't really understand your answer. Am I not binding the dataprovider property by doing:
Application.application.resultsGrid.dataProvider = result.data; ?
I'm from a PHP background and familiar with OOP in that environment so the idioms in Flex are quite strange to me.
as brd664 says, what you are actually doing in
Application.application.resultsGrid.dataProvider = result.data;
is actually an assignment. It's just like assigning a value to variable as in
var a : uint = 1;
Binding gives you a little more structure and allows you to populate multiple components based on a single property update. There's a ton of other benefits from binding and probably too much to cover in this post.
Here is a quick and simple example of how binding works. Note that there is one property that is bindable... when you click the button it sets that property to the value of whatever is in the textInput. This update then causes the bindings to fire and updates anything that has been bound to that property. It's one of flex's biggest features (it's also used extensively in silverlight and wpf and probably a load of other technologies that i'm not aware of). Anyway... have a play with it and see if you can get your component to update from a binding.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
<mx:Script>
<![CDATA[
private var _myData : String
[Bindable]
public function get myData() : String
{
return _myData;
}
public function set myData(value : String) : void
{
_myData = value;
}
private function clickHandler(event : MouseEvent) : void
{
myData = myTextInput.text;
}
]]>
</mx:Script>
<mx:VBox>
<mx:HBox>
<mx:Label text="{myData}" />
<mx:Label text="{myData}" />
<mx:Label text="{myData}" />
</mx:HBox>
<mx:TextInput id="myTextInput" text="TYPE HERE" />
<mx:Button label="CLICK TO BIND" click="clickHandler(event)" />
</mx:VBox>
</mx:Application>
Update: The phrasing of your question confused me :(
If you need to populate the datagrid with from you db, you really should be looking at binding the dataProvider property.

Resources