mxml null reference - apache-flex

I have an example custom mxml component CustomRadio
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RadioButton id="radio" />
<mx:Script>
public override function set label(value:String):void {
this.radio.label = value;
}
public override function get label():String {
return this.radio.label;
}
</mx:Script>
</mx:VBox>
and an application
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">
<local:CustomRadio label="xxx" />
</mx:WindowedApplication>
And I get Null reference arror in set label saying this.radio is null. Why ?

The RadioButton tag needs to encompass the Script tag. The way you have it now, the script tag is part of the VBox only. Since you are using the 'this' pointer, it's referring to the VBox.

Related

Yet another Flex custom events in components question

I can't seem to get one of the most basic uses of events working in Flex 4. I've followed multiple tutorials and looked everywhere. From what I can tell, I'm doing everything right, so there must be some stupid mistake somewhere.
I have a main application file that contains a button. On clicking the button, it fires a custom event which I want my listener in my child component to catch. The event IS firing. The child component event listener is NOT catching that event. No clue why. The custom event is copy-pasted from Adobe's tutorial (minus the custom namespace and comments).
Main Application
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
applicationComplete="init()" xmlns:local="*">
<fx:Metadata>
[Event(name="enableChanged", type="EnableChangeEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import EnableChangeEvent;
import TestComponent;
private function doDispatchEvent(event:MouseEvent):void {
if(dispatchEvent(new EnableChangeEvent(EnableChangeEvent.ENABLE_CHANGED, true)))
{
statusLabel.text = "Event was dispatched";
}
}
public function init():void {
myButton.addEventListener(MouseEvent.CLICK, doDispatchEvent);
}
]]>
</fx:Script>
<s:Button x="95" y="83" label="Button" id="myButton" />
<s:Label x="230" y="83" text="" id="statusLabel" />
<local:TestComponent x="95" y="150" width="300" height="400" />
</s:WindowedApplication>
Child Component (Test)
<?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="100%" height="100%"
initialize="init();">
<fx:Script>
<![CDATA[
import EnableChangeEvent;
private function doFinalAction(event:EnableChangeEvent):void {
myLabel.text = "Custom Event Recieved";
}
private function init():void {
addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}
]]>
</fx:Script>
<s:Label width="300" height="50" text="Should change on click" id="myLabel" />
</s:Group>
Custom Event (from Adobe)
package {
import flash.events.Event;
public class EnableChangeEvent extends Event
{
public function EnableChangeEvent(type:String, isEnabled:Boolean=false) {
super(type);
this.isEnabled = isEnabled;
}
public static const ENABLE_CHANGED:String = "enableChanged";
public var isEnabled:Boolean;
override public function clone():Event {
return new EnableChangeEvent(type, isEnabled);
}
}
}
Timofei Davydik's answer it correct. Since the Application object dispatches the event, if you want your TestComponent object to catch it, you have to add a listener to a reference of the Application object from within your TestComponent. You can use the TestComponent object's inherited property "parentApplication" to get a reference to the Application object`.
Change the following code in TestComponent.mxml:
private function init():void
{
this.parentApplication.addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}// end function
[UPDATE]
Personally I feel like your going about using events the wrong way, so I made a similar flex application to demonstrate how to use events in flex.
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:components="components.*"
xmlns:events="events.*"
applicationComplete="init()">
<fx:Script>
<![CDATA[
import events.EnableChangeEvent;
public function init():void
{
label1.text = "Application Complete!";
}// end function
private function onTestButtonEnableChanged(e:EnableChangeEvent):void
{
label2.text = "Enabled = " + e.isEnabled;
}// end function
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout horizontalAlign="center" paddingTop="50" />
</s:layout>
<components:TestButton id="testButton" label="CLICK!" enableChanged="onTestButtonEnableChanged(event)" />
<s:Label id="label1"/>
<s:Label id="label2"/>
</s:WindowedApplication>
TestButton.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:Button xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
click="onClick()">
<fx:Metadata>
[Event(name="enableChanged", type="events.EnableChangeEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import events.EnableChangeEvent
private var isEnabled:Boolean;
private function onClick():void
{
isEnabled = !isEnabled;
dispatchEvent(new EnableChangeEvent(EnableChangeEvent.ENABLE_CHANGED, isEnabled));
}// end function
]]>
</fx:Script>
</s:Button>
The main difference between the applications is that the Button object, in this case the TestButton object, dispatches the EnableChangeEvent event when clicked. While dispatching the event we can parse the boolean value for the _isEnabled property of TestButton to the event. Before, the value is inverted using the line isEnabled = !isEnabled. Now we can make use of handling the event using the mxml declaration of the TestButton object with the xml attribute enableChanged.
Also instead of following tutorials you might want to try a book like the one i'm reading. It's called "Adobe Flash Builder 4 and Flex 4 Bible" by David Gassner which you can get as a paperback book or a book for your kindle.
#Taurayi is correct, but to get you current code working with just one change, edit the init of Test Component to look like the following:
private function init():void
{
FlexGlobals.topLevelApplication.addEventListener(EnableChangeEvent.ENABLE_CHANGED, doFinalAction);
}
Your application object dispatches the custom event. Why do you expect your group to "catch" this event? It won't. Custom events have neither capturing nor bubbling phase. So, only listeners added to your application object will listen to this event.

Flash Builder 4: Error #1009 in when Button is wrapped in BorderContainer

This is really bugging me, but I have a component where a Button is wrapped in BorderContainer. I'm passing a custom property to the component at run-time to change the label of the button but Flex is reporting the following error:
Cannot access a property or method of a null object reference
When the error occurs, Flex highlights the following code:
myButton.label = value;
Here's the app:
// MyApp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:local="*">
<local:MyComp id="myButton" label="My Button"/>
</s:WindowedApplication>
// MyComp.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer 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">
<fx:Script>
<![CDATA[
private var _label:String;
public function get label():String
{
return _label;
}
public function set label(value:String):void
{
_label = value;
myButton.label = value;
}
]]>
</fx:Script>
<s:Button id="myButton" label="Test"/>
</s:BorderContainer>
Any help would be greatly appreciated. Thanks in advance.
The myButton Object is not already created if the setter function for the label property is called the first time. Assign the new label value to myButton.label in commitProperties().
You should read About creating advanced components (most notably "About the component instantiation life cycle") to understand why.

Setting up content children for custom mxml component

I am trying to develop a custom component to act as a divider.
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Canvas id="left"/>
<mx:Canvas id="right"/>
</mx:HBox>
I would like to use this component to assign objects like this:
<Divider>
<left>
<mx:label text="Stuff I want to put in the left canvas"/>
<mx:label text="etc..."/>
<mx:label text="etc..."/>
</left>
<right>
<mx:label text="Stuff I want to put in the right canvas"/>
<mx:label text="etc..."/>
<mx:label text="etc..."/>
</right >
</Divider>
Unfortunately, this does not work. I get a compiler error saying :
In initializer for 'left': multiple initializer values for target type mx.containers.Canvas.
What am I missing ?
I ended up finding the solution reading the following from the Adobe website.
Using the technique described as template component, you can specify an array of a certain type of objects. I ended up rewriting my component as follow:
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" initialize="init()">
<mx:Script>
<![CDATA[
[ArrayElementType("mx.core.UIComponent")]
public var right:Array;
[ArrayElementType("mx.core.UIComponent")]
public var left:Array;
protected function init():void
{
var i:int;
for (i = 0; i < left.length; i++)
leftCanvas.addChild(left[i]);
for (i = 0; i < right.length; i++)
rightCanvas.addChild(right[i]);
}
]]>
</mx:Script>
<mx:Canvas id="rightCanvas"/>
<mx:Canvas id="leftCanvas"/>
</mx:HBox>
It now works as intended.

Image as Label with Checkbox in Flex

I want to use an image in my checkbox as label, anybody know how ?
When I tried doing the same thing with a RadioButton a while back, I ended up having to create my own component. This is what I did:
IconRadioButton.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.RadioButtonGroup;
[Bindable]
public var imgLabel:Class;
[Bindable]
public var groupName:RadioButtonGroup;
[Bindable]
public var selected:Boolean;
[Bindable]
public var value:String;
]]>
</mx:Script>
<mx:RadioButton
id="radioBtn"
group="{groupName}"
groupName="{groupName}"
selected="{selected}"
label=""
value="{value}"
visible="{visible}"
includeInLayout="{includeInLayout}" />
<mx:Image source="{imgLabel}" click="{radioBtn.selected = true}" />
</mx:HBox>
Then you could use it like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:controls="com.example.controls.*">
<controls:IconRadioButton
groupName="{group}"
imgLabel="{AssetsFactory.getInstance().iconCCVisa}"
value="{CreditCardTypes.VISA}" />
...
Hope that maybe gets you started or gives you some ideas.
To use image as label, use the following code.
<mx:HBox width="100%">
<mx:RadioButton groupName="Yield"/>
<mx:Image source="#Embed('/scripts/btn_highest.png')"/>
</mx:HBox>

Combobox Dataprovider - Only gets labelField from XML not the associated ID

Back again this time working with data providers.
Well i been doing a bit of training with Flex, and I've searched, and i managed to get a ComboBox being populated through XML data. Its works pretty well, he gets the LabelField for each item from XML, but the ID associated to each item he doesn't get then from the XML.
Code:
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="355" height="465" creationComplete="getPaises.send();"
xmlns:ns1="com.*" title="Perfil" fontWeight="normal">
<mx:HTTPService id="getPaises" url="com-handler/paises.php" result="paisesHandler()"/>
<mx:Script>
<![CDATA[
private function paisesHandler():void
{
pais.dataProvider = getPaises.lastResult.paises.pais;
pais.data = "id";
pais.labelField = "nome";
}
]]>
</mx:Script>
<mx:ComboBox x="121" y="328" width="200" id="pais">
</mx:ComboBox>
</mx:TitleWindow>
And now the ouput XML from PHP:
<?xml version="1.0" encoding="utf-8"?>
<paises>
<pais>
<id>1</id>
<nome>Portugal</nome>
</pais>
<pais>
<id>2</id>
<nome>Espanha</nome>
</pais>
</paises
Well this is what it happens, i does gets the Country names from the XML
(<nome></nome>) but he doesn't place the associated ID (<id</id>).
I now that because i placed a Label bindable to the ComboBox.selectedIndex
<mx:Label x="121" y="403" text="{pais.selectedIndex}"/>
And as you also see i used pais.data = "id"; that according to examples i saw in the web, it should include the ID from XML to each item NOME in the ComboBox.
I new to Flex, so probably didn't expressed things the right way.
Any help is appreciated. Thanks.
You don't need this line:
pais.data = "id";
change the label to
<mx:Label x="121" y="403" text="{pais.selectedItem.id}"/>
EDIT: The code can be simplified to
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="355" height="465" creationComplete="getPaises.send();"
xmlns:ns1="com.*" title="Perfil" fontWeight="normal">
<mx:HTTPService id="getPaises" url="com-handler/paises.php" resultFormat="e4x"/>
<mx:ComboBox x="121" y="328" width="200" id="pais" labelField="nome"
dataProvider="{XML(getPaises.lastResult).pais}"/>
</mx:TitleWindow>
Edited the data provider. Thanks

Resources