Flex TabbedViewNavigator deactivate event in a view - apache-flex

I have a TabbedView application it looks like this:
<s:TabbedViewNavigator width="100%" height="100%" left="0" bottom="0" right="0">
<s:ViewNavigator label="viewA" firstView="views.viewA" width="100%" height="100%"/>
<s:ViewNavigator label="viewB" firstView="views.viewB" width="100%" height="100%"/>
</s:TabbedViewNavigator>
This will create a buttonbar with two buttons at the bottom of the application.
Now I can easily switch between viewA and viewB.
When I define a button in viewA to trigger a CallOut (component in flex) is will appear nice and smooth.
I also created a close button to close the CallOut.
callout.close();
So far so good.
The problem will exist when I use the button to open the CallOut pane in viewA.
Then switch to viewB, the CallOut pane still exists on the screen and did not close.
So I tried these events:
viewDeactivate or/and deactivate
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
viewDeactivate="viewDeactivates()"
deactivate="viewDeactivates()"> <!-- or this -->
But it seems that there is no event when switching between tabs viewA and viewB.
viewDeactivate or deactivate didn't do anything.
I could use a eventlistener on the TabbedViewNavigator and then close the CallOut component if exists in viewA or viewB in the TabbedViewNavigatorView, but this is not a nice way to program, especially when you have multiple CallOut components.
Does anyone know, if there is a good solution for this problem?
Would helped me a lot, thanks in advance!

You need to pass an event argument into the function for it to work!
viewDeactivate="viewDeactivates(event)"
then
private function viewDeactivates(event:Event):void
{
callout.close();
}

Related

Setting focus on a TextField when application starts when there are two states

I have next application header:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()" creationPolicy="all" enterState="focusManager.setFocus(employeeIDTextInput);">
public function init():void {
focusManager.showFocusIndicator = true;
focusManager.showFocus();
focusManager.setFocus(theTextInput);
}
And theTextInput is on the default state. But when application starts theTextField is focused (a blue rectangle is around theTextField) but the cursor isn't inside theTextField. But in the next state I have anotherTextInput and when you switch between states both text inputs are focused correctly as you expect and the cursor appears inside every one of them correctly.
<mx:State name="secondState" enterState="{focusManager.setFocus(anotherTextInput)}">
My question is, Why when application starts the cursor isn't inside theTextInput as commanded on init() function?
Thank you for your answer
I solved it, That problem was because this is a component and is called from a main menu, and the creationComplete event is dispatched just in the moment when the menu is created just before the component appears in screen. What I did was to attach an event handler to show event and that is.
<mx:Canvas width="100%" height="100%" xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init()" creationPolicy="all"
show="focusManager.setFocus(employeeIDTextInput)"
>
Thank you very much to every one who ask my question...

Creating First Application of Flex "How to Change Button label", learning resources for Flex from Flash background

I'm just getting started switching from flash to flex for the better components. I am trying the simple experiment of adding a button and then changing the label. This code does not work. It does not recognize myButton. In flash I could access a button instance after adding it using the instance name. Can't you do this in flex?
Thanks
<s:Button x="50" y="42" label="Button" id="myButton"/>
<fx:Script>
<![CDATA[
myButton.label="winning";
]]>
</fx:Script>
Flex have an Event based structure you can not just put command/expression in script block
it should be wrapped in function
like
private function changelabel():Void
{
myButton.label="winning";
}
and you need to call this function on an event like Click event of Button as
<s:Button x="50" y="42" label="Button" id="myButton" click="{changelabel()}"/>
You should read Migrating a Flash application to Flex
and to take a look in Flex you should vist Flex Developer Center
Hopes that helps

FLEX: How to reference a MXML class from an AS3 external class file?

I have a mxml class where I place a list and a couple of buttons.
I'd like two things:
To access to the list from a class that is an external file.
To add my as3 class as child (visual element) since I need to get the "stage" (global property).
I woudnt't like to embed too much code into mxml through <![CDATA[]]>.
So, example of mxml
<?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="800" minHeight="600" width="800" visible="true">
<fx:Style source="Main.css"/>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
private var menuController:CMenuController= new CMenuController();
]]>
</fx:Script>
<s:List x="598.35" y="100.55" width="178" height="324" id="ListBox">
<s:layout>
<s:VerticalLayout/>
</s:layout>
</s:List>
</s:Application>
Thus, I'd like to access to ListBox from CMenuController as I was typing in CDATA. Besides, I need to be able to add Sprites and Shapes trough addChild() method in CMenuController.
You have to add Sprites and Shapes to UIComponent first and then add this to the Flex code.
To access the Flex code from external as3 class have a reference in the as3 class. Like this:
menuController.listReference = LISTID;
I don't think you get the concept of separating visual elements from the application logic. What you're trying to accomplish is considered very bad form since it makes for spaghetti code.
What you should do is instead use a data-driven approach by create an ArrayCollection of whatever you want to show in the List (which could be a property of MenuController). Then add a custom item renderer to do whatever you need it to. Kind of like this:
<s:List dataProvider="{menuController.yourListData}" itemRenderer="YourCustomItemRenderer" />
Within the item renderer, you can display whatever you want depending on the data of yourListData. I recommend you read on how item renderer works as well as try to find examples of data driven Flex applications.

adobe flash buider (flex4): Error #2025 or Error: addChild() is not available in this class. Instead, use addElement()

I'm a complete newbie to Flex, so apologies for my dumbness. I've searched for an answer but haven't found anything that seems to be doing the trick.
What I'm trying to do: port this example http://www.adobe.com/devnet/air/flex/articles/flex_air_codebase_print.html
to Flash Builder 4.
All seems to be fine but for one thing. When I use the original code for the Air 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"
creationComplete="onApplicationComplete()">
<fx:Script>
<![CDATA[
private static const neededForCompilation:AirGeneralImplementation = null;
private function onApplicationComplete():void
{
var can:MainCanvas = new MainCanvas();
this.addChild(can);
can.labelMessage = "Loaded in an AIR Application ";
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:WindowedApplication>
I get this run time error
Error: addChild() is not available in
this class. Instead, use addElement()
or modify the skin, if you have one.
at
spark.components.supportClasses::SkinnableComponent/addChild()[E:\dev\4.0.0\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:1038]
If I substitute the code with
this.addElement(can);
Everything loads well but the first time I try to press any of the buttons on the main canvas I get the following run time error
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/getChildIndex()
at mx.managers::SystemManager/getChildIndex()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:1665]
at mx.managers.systemClasses::ActiveWindowManager/mouseDownHandler()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\systemClasses\ActiveWindowManager.as:437]
here's the super simple code for the main canvas
<?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"
creationComplete="init();">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script source="main.as" />
<mx:Label id="lblMessage" text="The UI from the shared Flex app BothCode" x="433" y="112"/>
<s:Button x="433" y="141" click="saveFile();" label="Save File"/>
<s:Button x="601" y="141" click="GeneralFactory.getGeneralInstance().airOnlyFunctionality();" label="Air Only"/>
</s:Application>
Any help would be immensely appreciated. And any pointers to how to setup a project that can compile in both Air and Flash while sharing the same code, all for Flex 4, would also be immensely appreciated.
thank you!
I ran into the same problem using that tutorial for Flex 4. I did the same thing as you and used the <s:Application> component for the Main Canvas. However the tutorial uses a <mx:VBox>, the solution I found was to change the Main Canvas from an <s:Application> to an <s:Group>. The problem seems to be embedding an Application within an Application.
The code on that link was written using the flex 3.5 sdk or below. You are using the new flex 4 sdk ( which is the default for Flash Builder ).
You can do the following:
1. step into the code do any necessary changes to make it work for flex 4 sdk.
2. setup a new project using the flex 3 sdk ( select "Use a specific SDK" and choose the Flex 3 from the dropdown box in the "New Project" window)
I would suggest going for the second option, make it work and once you've stepped a little deeper into flex 4 you can do the 1st option.
Cheers.

Flex - Checking for change in fields under a tab

I'm developing a flex application with 4 tabs. When the user switches a tab I want to reset the previous tab to its initial state. Also I need to alert the user, if he hasn't saved the changes he made if any, will be lost.
I'm planning to set a variable in the Model, and set/reset it if any change happens in a field under a tab. But how do I monitor this? Is there any listener available for this?
Also how do I check and reset the state of the previous tab? The contents that come under the tab is from components only.
[EDIT]
My questions are:
How do I check if the user has made any edits in the current tab? Some fields are generated dynamically too.
I'm calling a function in the onchange event of TabNavigator and asks the user if he really want to switch the tab.I want the other tab to load its contents only if the user clicks Yes to the Alert box I'm popping up. But now the confirmation box pops up, and the contents are loaded into the other tab and if the user clicks No it goes back to the other tab. How do I prevent the action of loading the contents of the other tab at all till the user presses Yes?
Please provide your valuable inputs.
Answer to question 1 is as follows;
Use a Boolean variable to track if a user has edited data. When the user selects a tab set this variable to false. Listen for the change event on all fields within the tab. Set the change event handler for all fields to be a method which sets the Boolean to true. For the dynamic fields, add the same change event handler that the other fields have. Do this as soon as you create each dynamic field. See the code below;
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private var userChangedData:Boolean=false
function onUserChangedData()
{
trace("onUserChangedData")
userChangedData=true
}
function onTabChanged()
{
trace("ontabchanged")
trace(userChangedData)
userChangedData=false
}
]]>
</mx:Script>
<mx:Panel title="TabNavigator Container Example"
height="90%"
width="90%"
paddingTop="10"
paddingLeft="10"
paddingRight="10"
paddingBottom="10">
<mx:TabNavigator id="tn"
width="100%"
height="100%"
change="onTabChanged()">
<!-- Define each panel using a VBox container. -->
<mx:VBox label="Panel 1">
<mx:Label text="TabNavigator container panel 1"/>
<mx:TextInput text="default"
change="onUserChangedData()"/>
<mx:CheckBox label="check something"
change="onUserChangedData()"/>
</mx:VBox>
<mx:VBox label="Panel 2">
<mx:Label text="TabNavigator container panel 2"/>
</mx:VBox>
<mx:VBox label="Panel 3">
<mx:Label text="TabNavigator container panel 3"/>
</mx:VBox>
</mx:TabNavigator>
</mx:Panel>
For 1) you could dispatch an Event every time a user edits a field. The event can be handled by a command which will update some properties in your model with the right info about what got updated. Then whoever cares in your view can bind to those properties.
For 2) in the onChange() handler call event.preventDefault(). Then you can programatically select the next tab only if the user clicks Yes.
I don't have the reputation to add comments yet, but to answer your question:
"Is it possible to add a global onchange/onkeypress method that hooks to the complete application and sets the boolean? Otherwise I'll have to edit at multiple places to add the onchange event. – Basani"
Yes, have each place that needs to signal that "something changed" dispatch an Event. Then have a Command watching for dispatches of that event. That Command can do all the processing you need, including setting the userDataChanged boolean in the model.
It sounds like you're using Cairngorm based on how you tagged the question, so this should be easily supported.

Resources