Is there a way to truly extend a Flex component? - apache-flex

I need to create an extension of a Flex component, which (obviously) means that the new component should be able to be used whenever the parent is used. But I don't see the way to do it, Flex offers two ways of extending a component, by defining an AS class extending the parent or by creating an MXML file that uses the parent component as a root element; in both cases I can’t use nested elements to configure the child as I do for parent.
E. G.
package components {
import mx.controls.AdvancedDataGrid;
public class FixedDataGrid extends AdvancedDataGrid {
public function FixedDataGrid() {
super();
}
}
}
This is Valid MXML
<mx:AdvancedDataGrid>
...
<mx:columns>
...
This is NOT Valid MXML
<mx:FixedDataGrid>
...
<mx:columns>
...
It doesn't seem like a valid is-a relation.

Your FixedDataGrid doesn't exist in the same namespace as the mx components...
you need to specify the correct namespace for it to be legal.
<mx:Application xmlns:components="components.*" ... >
<components:FixedDataGrid>
....
You are doing the mxml equivalent of declaring your component in the components package then complaining you can't reference it as mx.controls.FixedDataGrid

When defining properties via a new MXMLtag, the property must contain be specified in the same namespace as the tag.
So you could do something like this:
<myComp:FixedDataGrid columns="SomeArray">
Without any issues. If you use the MXML tag syntax to define the columns array property, you need to do this:
<myComp:FixedDataGrid >
<myComp:columns>
<mx:AdvancedDataGridColumn />
<mx:AdvancedDataGridColumn />
</myComp:columns>
</myComp:FixedDataGrid >
columns is a property on the AdvancedDataGrid, and therefore must be defined in the same namespace as your custom extension to the AdvancedDataGrid. AdvancedDataGridColumn is a different component, so it would be definined in the mx namespace.
As mentioned by an alternate poster, the 'myComp' namespace must be defined in the top level component of your application. Most of the time Flash Builder will add the namespace automatically for you.

Related

Access the public, bindable variable from one .MXML in another .MXML

I have as a main application setted "main.mxml"
which contains the follow declaration :
[Bindable]
[Embed(source="../images/common/user.png")]
public var userIcon : Class;
I have another module, on which i wish to access it as a button icon.
I have tried with the follow definition, but it doesnt work:
<s:Group width="100%" height="29">
<s:layout>
<s:VerticalLayout horizontalAlign="center"/>
</s:layout>
<s:Button id="buttonLoad" width="80%" label="Loading" icon="{ main.userIcon }"/>
</s:Group>
How to access the declaration inside main.mxml from the other modules ?
The name of MXML class isn't an identifier of its instance (because of it can have a lot of instances). You should think about MXML files as not files but classes. They are absolutely the same as ordinary ActionScript classes. The same rules as in other OOP languages. So if you have main.mxml main is a class name for that class and its package is determined by that MXML file path relative to the source folder (as in ActionScript classes). That's why you should name your MXML classes from the capital letter (Main.mxml but not main.mxml).
If your main.mxml is top level application you can refer it as FlexGlobals.topLevelApplication. But it is not the right way to do things.
The best way is to inject this property to your target class. You can do it using Dependency Injecting Framework/Container like Spring ActionScript or RobotLegs or Parsley. Or you can do it manually by delegating from top application to the class containing piece of code which handles modules. When module is loaded pass this value there.

Binding mxml (as)

I have actionscript file with a binding {someBinding}...
The Main.mxml is where all the action happens. If I set {someBinding} in the "text" of a label component I will have a number.
I have another form.mxml file. Where I want that binding to be in, but it can't find such binding.
I need to have that {someBinding} in that other mxml, the same way as in the Main.mxml
Thanks, Yan
You can't a value in one component (or File) to a value in another component (or file) in the way you seem to be asking. You'll have to expose those related values as properties and set the values.
This type of approach should work:
First add a property to component 2 and make it Bindable. Do this in a Script block, like this:
[Bindable] public var hBoxWidth : int;
Then bind it to something in your MXML of the same component, like this:
<mx:HBox width="{this.hBoxWidth}" />
Now some component will contain this one:
<mx:HBox>
<myCustomComp:customHBox hBoxWidth={this.othervalue} />
</mx:Hbox>
So, when the othervalue changes it will change the hBoxWidth value on the customHBox component which will in turn change the width property on the HBox inside of customHBox.
Does that make sense?
You can create the binding but you have to use ActionScript and you need a reference to the form.mxml file in the main.mxml (or visa versa).
This should give you an ideal of how it might work. Take a look at the syntax for the BindingUtils. bindProperty method. The use of BindingUtils code would be within main.mxml.
BindingUtils.bindProperty(otherForm.someOtherTextComponent, "text", this.someTextComponent, "text");

about data-binding in mxml

I've done a data-binding following a tutorial on the web:
<mx:Script><![CDATA[
public static const selectedChild:Boolean = true;
]]></mx:Script>
<mx:Button label="{resourceManager.getString('resources', 'button.startLab')}"
id="nextStepButton" enabled="{selectedChild}" />
My question is how we can accsess this bindable variable from another mxml file?
Thanks.
As already stated, you can access selectedChild from another class using ClassName.selectedChild, where ClassName is the name of your mxml file.
Please note couple of things though:
selectedChild is not declared as bindable. You should use the [Bindable] metadata tag to make a variable declared in actionscript to be bindable.
selectedChild is declared as const, meaning its value cannot change in between. Thus, you need not use data binding on that field - just assign the value to the enabled field of the button once it is created.
It is declared as static - which means there is only one instance of it for the whole class. If you have another component of the same type, it'll have the same value as this one - as you have declared it as a constant, that might be the behavior you want, but in that case, you need not use data binding.
yes you can
ClassName.variable_name will give you the value

accessing a class within mxml tag

I would like to provide my own sortItemRenderer within an AdvancedDataGrid like so:
<mx:AdvancedDataGrid sortItemRenderer="MyRenderer"></mx:AdvancedDataGrid>
MyRenderer is a class that I wrote, but Flex doesn't see it and gives "defintion not found" error, because it is not within the mx namespace. What is a clean way to make this to work?
You have to provide the fully qualified name for your renderer : if you class is in package myPackage.MyRenderer then sortItemrenderer="myPackage.MyRenderer"

How to know the order of component rendering in Flex

I have a component that has a sub-component they both use a shared variable from the model. The shared variable needs to be set by the parent component before it can be used by the child component. I did like this in the parent component:
<mx:Canvas
xmlns:mx="library://ns.adobe.com/flex/mx"
...
creationComplete="group1_completeHandler(event)" >
....
protected function group1_activateHandler(event:Event):void {
model.myVariable = something;
}
....
<components:myCustomComponent>
...
<components:myCustomComponent>
...
</mx:Canvas>
But for some reason when the code inside myCustomComponent tries to use myVariable for the first time I get a "null" object error. This means I guess that the child component gets rendered before the group1_activateHandler gets called and consequently myVariable gets set.
What should I do to ensure that the parent container initializes the variable before the child component gets created?
You should set the variable in initialize() instead of creationComplete() which is invoked after all components are created and rendered.
I recommend you factor the variable out of the components into a separate code which you can instantiate separately from the actual components. Then use binding to bind your components to this class. This will give you a much cleaner design.

Resources