Preventing ViewStack from Changing Index - actionscript-3

I have a ViewStack, with a bunch of NavigatorContainers in. Each NavigatorContainer contains a different category of settings for the application.
I would like to be able to display a popup prompting the user if they try to leave the current NavigatorContainer without saving the changes they have made to the container's settings.
What would be ideal is something like the 'changing' event in the List component, whereby you are able to cancel or defer the event. Calling preventDefault() on the change event in ViewStack doesn't prevent the index change from happening.
Is there a way of doing this with a minimum of hoop-jumping?
Thanks

It depends what is changing your viewstack. For example if you have ButtonBar as view changer, then you can easily write like this:
protected function btnBar_changingHandler(event:IndexChangeEvent):void
{
event.preventDefault();
//enter code here
}
and
<s:VGroup width="100%" height="100%" horizontalAlign="center">
<s:ButtonBar id="btnBar" dataProvider="{viewStack}" requireSelection="true" changing="btnBar_changingHandler(event)">
<s:layout>
<s:ButtonBarHorizontalLayout gap="2" />
</s:layout>
</s:ButtonBar>
<mx:ViewStack id="viewStack" width="100%" height="100%">
<s:NavigatorContent width="100%" height="100%" label="First View">
<comp:FirstView/>
</s:NavigatorContent>
<s:NavigatorContent width="100%" height="100%" label="Second View">
<comp:SecondView/>
</s:NavigatorContent>
</mx:ViewStack>
</s:VGroup>

If nothing dreadful happens on index change, why not keep a current index and then in your change event just pop them back and give your alert?

Related

Scroller in the first accordion item in Flex does not appear

I have created an accordion to store images on categories. Everything is ok when I add a new element to an item, the scroller appears. The image address is saved in an txt file. However, when I open the application again the scroller does not appear. This is strange as it happens only in the first item of the accordion. If I add more elements to the other items (from the second further) everything works alright.
Does anybody have any idea why??
Hard to say without seeing your code.
Sample of using accordion with images inside which you can try
(scrollbars are visible for both tabs):
<?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">
<mx:Accordion height="500"
width="100%">
<s:NavigatorContent label="Tab 1"
height="100%"
width="100%">
<s:Scroller height="100%"
width="100%">
<s:Group>
<s:Image source="http://d1c739w2xm33i4.cloudfront.net/2.2/top_image.jpg"/>
</s:Group>
</s:Scroller>
</s:NavigatorContent>
<s:NavigatorContent label="Tab 2"
height="100%"
width="100%">
<s:Scroller height="100%"
width="100%">
<s:Group>
<s:Image source="http://eofdreams.com/data_images/dreams/image/image-07.jpg"/>
</s:Group>
</s:Scroller>
</s:NavigatorContent>
</mx:Accordion>
</s:Application>
In accordion just write resizetocontent = true; It will work
Hope it will help

Problems with adding Spark elements to a MX wrapper

So I made a simplified version of the code I'm working on ...
I have a custom Flex component that has following structure (based on the s:HGroup):
<s:HGroup 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%" >
<fx:Script>
<![CDATA[
import spark.components.Button;
public function addButton():void{
var myButton:Button = new Button(); 
            myButton.label = "New Button"; 
buttonContent.addElement(myButton);
}
]]>
</fx:Script>
<mx:HDividedBox width="100%" height="100%">
<s:VGroup width="100%" height="100%" gap="5">
<s:VGroup width="100%" height="100%">
</s:VGroup>
<s:Group width="100%" height="100%">
<s:Group left="5" top="15" bottom="5" right="5" id="buttonContent" />
</s:Group>
</s:VGroup>
<s:VGroup width="100%" height="100%">
</s:VGroup>
</mx:HDividedBox>
Inside this component I make use a the mx:HDividedBox component since there is no Sparkalternative...
So when I call the function addButton(), my intend is to add a custom Spark DataGrid (in this example a simple s:Button made with code) to the Spark Group with id buttonContent. I noticed that this button isn't added to the Groupwith id buttonContent.
When I commented out the mx:HDividedBox the Spark button was added like it should...
I suppose there is some conflict rising between the Sparkand mx display formats.
Has anyone had the same problem? Or know a usable solution / work around?
Any tips are welcome! Thanks!
Try adding an "id" field to the HDividedBox. Flex has had issues with not recognizing elements when their parents don't have an id in the past, this might be a regression issue?
(Would've added as a comment, but I don't have the access yet..)
Your exemple works on my computer.
Which flex SDK version are you using ?
Are you really using "100%" width and height in you real code ? (DividedBox are tricky with sizes, if you don't set resizeToContent to true then the dividedBox will not resize itself if the content changes)

Trigger ButtonBar Click

I have a weird thing going on with my skins. I'm hoping to fix it by doing a workaround that involves triggering the click of a sparks buttonbar button, but I'm not exactly sure how to do that.
Here's my button bar code
<s:ButtonBar id="tabs" dataProvider="{vs}"
skinClass="skins.hatchedbuttonbarskins.TabBarSkin"
depth="100" width="80%" visible="true"
bottom="0" horizontalCenter="0" height="25" />
<mx:ViewStack id="vs" width="95%" height="625"
borderVisible="true" horizontalCenter="0">
<s:NavigatorContent width="80%" height="100%"
label="My Label"
skinClass="skins.lg.TabNavigatorContent">
<lists:ListCenter myLists="{this}" myButtons="{tabs}"/>
</s:NavigatorContent>
...
There are three more navigatorcontent objects after this one.
In ListCenter.mxml, I want to trigger a click of the tabs button bar buttons. Here's the action script call I'm making.
myButtons[1].dispatchEvent(new MouseEvent(MouseEvent.CLICK));
It's giving me the following error:
Error #1069: Property 1 not found on spark.components.ButtonBar and there is no default value.
How do I access the button objects?
I'm not sure what you are trying to achieve, but you can try to change the ButtonBar.selectedIndex like this:
myButtons.selectedIndex = 1;
If you really want to access buttons, then use:
var btnBarBtn:ButtonBarButton = myButtons.dataGroup.getElementAt(0) as ButtonBarButton;
Or you can describe your skin problem, maybe there is another way to solve it.

Horizontal Layout: mx vs spark - Resizing children

In Flex 3, I used to be able to take 2 panels, lay them out with 100% width settings in an HBox. If I changed the width property of the first panel to something smaller, let's say 20%, the second would automatically update and fill in the space that used to be taken up by the first as the first resized down.
I notice in spark, this doesn't happen. I have an app with a HorizontalLayout, and a resizable panel control on the left and a panel on the right that has width="100%." When I resize my left-side panel down, the right side panel doesn't do anything. So I end up with a clean resizable panel, a bunch of wasted space, and my right-side panel just sitting there.
What I expect is that since the right-side panel has a width="100%" then if the panel to its left is resized, then there would be a corresponding growth in the right-side panel to fill in.
I've tried to manually trigger validation on properties and size without effect. I'm wondering what changed in the HorizontalLayout that no longer allows this technique to work. I would also like to know what solutions are available?
Here's some chomp chomp:
<mx:Application>
<mx:Script>
<![CDATA[
protected function resizeClick(event:MouseEvent):void
{
pnl1.percentWidth = 10; // When this would execute, pnl2 would automatically
// fill in the space previously held by pnl1.
}
]]>
</mx:Script>
<mx:HBox width="100%" height="100%">
<mx:Panel id="pnl1" width="40%" height="100%"> // Uses 40%
<mx:Button id="resizeButton" click="resizeClick(event)"/>
</mx:Panel>
<mx:Panel id="pnl2" width="100%" height="100%"/> // Fills in the rest of the available space
</mx:HBox>
</mx:Application>
Flex 4.5 doesn't automatically update the size of pnl2 when the size of pnl1 changes. I would think that since a HorizontalLayout is being used, that both children would update when the width of one of them was changed. But that just doesn't seem to be the case. I know I can create two states to accomplish this, but I was thinking that I shouldn't have to for something so trivial.
This sample works fine and illustrates correct changes of sizes:
<?xml version="1.0" encoding="utf-8"?>
<s:Application minHeight="600" minWidth="955" xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:s="library://ns.adobe.com/flex/spark">
<s:VGroup height="100%" width="100%">
<s:HSlider change="firstPanel.percentWidth = event.currentTarget.value" maximum="100" minimum="0"
value="{firstPanel.percentWidth}" />
<s:HGroup height="100%" width="100%">
<s:Panel height="100%" id="firstPanel" minWidth="0" width="40%" />
<s:Panel height="100%" width="100%" />
</s:HGroup>
</s:VGroup>
</s:Application>
So this is how I eventually solved this problem. I should have been a little more specific in my post to explain that Panel 1 is actually a "collapsible" panel that modifies its own size whenever its header button is clicked. The example above does work, but since there is no numeric control on the view to "tell" the panel.percentWidth property how much to change, I set my collapsible panel up to dispatch custom events that are handled by the wrapper. The custom events basically indicate what is happening to the collapsible panel. From there, I can handle the events separately and then control the size of Panel 2.
The solution is actually rather simple and I was hoping for something a little more "behind the scenes" but this worked fine.
<s:Application initialize="initApp(event)">
<fx:Script>
<![CDATA[
protected function initApp(event:FlexEvent):void
{
this.addEventListener("PanelCollapse", panelHandler);
this.addEventListener("PanelNormal", panelHandler);
}
protected function panelHandler(event:Event):void
{
switch(event.type)
{
case "PanelCollapse":
pnl2.percentWidth = 100;
break;
case "PanelNormal":
pnl2.percentWidth = 60;
break;
}
}
]]>
</fx:Script>
<comp:CollapsiblePanel id="pnl1" width="40%" height="100%">
</mx:Panel>
<s:Panel id="pnl2" width="100%" height="100%"/> // Fills in the rest of the available space
</s:Application>

Multiple initializer values for default property, 'viewport' of type 'spark.core.IViewport'

Please, can anyone help me out on this : the piece of code below was working fine until i decided to add a scroller for better view and suddenly, i get the error:
"Multiple initializer values for default property, 'viewport' of type 'spark.core.IViewport'"
Thanks
[CODE]
<s:Scroller
width="100%"
height="100%"
>
<s:Group id="basicDataGroup" includeIn="initial">
<s:HGroup id="buttonGroup"
x="250"
paddingTop="20"
gap="15">
<s:Button id="addBT" label="{resourceManager.getString('aggregationUI','add')}" click="addBT_clickHandler(event)"/>
<s:Button id="delBT" label="{resourceManager.getString('aggregationUI','delete')}"/>
</s:HGroup>
<s:DropDownList id="languageCombo"
prompt="{resourceManager.getString('aggregationUI','lang')}"
dataProvider="{new ArrayCollection([{locale:'fr_FI',label:'France'}, {locale:'en_US', label:'English'}])}"
change="languageChange(event)"
width="100"
x="473"
y="20"/>
<components:SearchComponent id="searchModel" searchClick="searchModel_searchClickHandler(event)"/>
<components:DataComponent id="basicData"
x="250"
y="50"/>
</s:Group>
<s:Group id="newModelGroup" includeIn="newModel">
<components:NewDataComponent id="newModelData"/>
</s:Group>
</s:Scroller>
[/CODE]
A scroller can only be a viewport to one component. In your scroller, you have basicDataGroup and newModelGroup. Even though you have states so they don't both exist at the same time, I don't think Flex is that coordinated to know that. Instead, wrap those two Groups in one Group, and make that parent Group the Scroller's viewport.
Hope that helps,
Ryan