How to set current page dynamically in flexbook? - actionscript-3

I am using a Flexbook which contains 2 BorderContainer. The code is shown below
<controls:FlexBook id="book" x="20" y="20"
width="100%" height="100%" horizontalCenter="0"
animateCurrentPageIndex="true"
showCornerTease="true" animatePagesOnTurn="true"
activeGrabArea="edge"
edgeAndCornerSize="20"
hardbackPages="false"
hardbackCovers="false"
pageShadowStrength="1"
curveShadowStrength="1"
pageSlope="0"
itemSize="page"
backgroundColor="0xC3D1D9"
borderThickness="0"
borderColor="0xC3D1D9"
cover="{null}"
backCover="{null}"
showPageSlopeAtRest="false"
cacheAsBitmap="true">
<s:BorderContainer id="page1">
<mx:ColumnChart x="0" y="35" id="ccMain" height="90%" width="99%"
cacheAsBitmap="true"
showDataTips="true" dataTipFunction="{getDataTip}" type="clustered" backgroundElements="{bge4}">
<!-- column chart code goes here -->
</mx:ColumnChart>
</s:BorderContainer>
<s:BorderContainer id="page2" creationComplete="productMainPg2.addElement(lineChart)">
<mx:Legend dataProvider="{lineChart}" height="21" x="10" width="95%" color="#b1b7f4"/>
</s:BorderContainer>
This code shows page1 as current page. I want to show the BorderContainer (id= page2) as my current page dynamically on a button click. I tried setting currentPageIndex = 1, but I get a blank page by doing this.

Create a [Bindable] boolean property (i.e. [Bindable] public var isShowingFirstPage:Boolean = true)
Set the BorderContainer's "visible" and "includeInLayout" properties to be contingent on this value. (i.e. ...id="page1" visible="{isShowingFirstPage:Boolean}" includeInLayout="{isShowingFirstPage:Boolean}... for the first one, and ...id="page2" visible="{!isShowingFirstPage:Boolean}" includeInLayout="{!isShowingFirstPage:Boolean}...for the second)
toggle / change that boolean based on some input, user gesture, business logic, whatever and the two container's should display / update accordingly.

Related

Spark List: ensureIndexIsVisible with expanding list itemRenderer

I have a Spark List with an expanding itemRenderer (snippet of it below). It works very well but I am struggling to display the fully expanded list item when calling ensureIndexIsVisible. I've tried various things with validate/invalidate to try to force the List to take the expanded item size into account but either I am doing it wrong or the List component isn't built to handle this.
In the image below, I've called myList.ensureIndexIsVisible(7);Item 7 is expanded and the header scrolled to be visible but most of the expanded item is offscreen.
Anyone know a way to address this?
Update: If the List is specified to have useVirtualLayout="false" then the following works:
myList.validateNow();
myList.ensureIndexIsVisible(expandIndex);
but of course if there are a lot of cells in the List instance then this is a problem.
protected function expandOne_clickHandler(event:MouseEvent):void
{
var expandIndex:Number = Number(expandTarget.text);
data.getItemAt(expandIndex).selected = true;
myList.invalidateDisplayList();
myList.ensureIndexIsVisible(expandIndex);
myList.validateNow();
}
List itemRenderer:
<s:CheckBox id="eventName"
label="{data.eventName}"
top="0" left="0" right="0" bottom="0"
skinClass="skins.SatelliteEventSkin"
selected="{data.selected}"
click="{data.selected = !data.selected}"/>
<s:VGroup includeInLayout="{eventName.selected}"
visible="{eventName.selected}"
top="30" left="10" right="10" bottom="10">
<s:HGroup verticalAlign="middle" width="100%" >
<s:Spacer width="100%"/>
<s:Label text="eventID"/>
<s:Label id="eventID"
width="150"
text="{data.eventID}"/>
</s:HGroup>
etc...
Try to set selectedIndex value or just scroll your List using verticalScrollPosition value -myList.layout.verticalScrollPosition += your_item_height;.

Flex 4.x accordion items child unknown in actionscript

I have an Accordion component in Flex that has two children,
at the load of my page, I want to give the textvalue of a textfield in the first children to a textfield in the second children by using actionscript, but its faild
nb : when I click the secode children and I return to pass the textvalue from the first children, the action succeed!
<mx:HBox width="100%" height="310" horizontalAlign="center">
<mx:Accordion id="accordion1" width="100%" height="310" historyManagementEnabled="true">
<!-- child 1--><mx:VBox id="theme_resultat" width="95%" height="95%"
label="Résultat" horizontalAlign="center"
verticalAlign="middle">
<s:HGroup left="0" right="0" bottom="0" width="98%"
horizontalAlign="right">
<s:TextInput id="doc"/>
<mx:Button id="btnAdd" label="Add"
click="add_text(event)"
icon="#Embed('assets/images/add.png')"
paddingLeft="3" paddingRight="3"/>
</s:HGroup>
</mx:VBox>
<!-- child 2--><mx:VBox id="theme_detail" width="95%" height="95%" label="Détail"
verticalAlign="middle">
<mx:VBox width="100%" height="150" horizontalAlign="center">
<s:HGroup>
<mx:FormItem label="Titre:" paddingLeft="5">
<mx:TextInput id="doc_titre"/>
</mx:FormItem>
</s:HGroup>
</mx:VBox>
</mx:VBox>
</mx:Accordion>
</mx:HBox>
protected function add_text(event:MouseEvent):void
{
accordion1.selectedIndex=1;
doc_titre.text = doc.text;
}
}
when I click add I move to the second child, but the (mx:TextInput id="doc_titre") dont have the value of (s:TextInput id="doc"/)
for the second time I return to the child 1 and I click add, then I move to the second child and I find the value of (s:TextInput id="doc") in (mx:TextInput id="doc_titre")
What happens exactly? I think your problem may be caused by the fact that the components on the second children are not created until that view is opened, There are many solution for this, you could write some code in the creation complete oof the second view that will load the correct value, you can use databinding to bind the text inputs to the same string or you can try setting creationPolicy to all.
My answer is based on my above assumption so if I am wrong please give more details.
Check this http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf69084-7cb8.html#WS2db454920e96a9e51e63e3d11c0bf69084-7ae5 and try setting the creationPolicy to all then let us know if the problem is solved
Use createDefferedContent() instead:
for (var i:int = 0; i < accordion.numChildren; i++)
{
(accordion.getElementAt(i) as NavigatorContent).createDeferredContent();
}
This method creates the children and their components in the background. Don't use creationPolicy as I did since this causes memory-related issues.

s:CheckBox - getting selected value

<fx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
if (cbAlwaysOnTop.selected) { // <<<<<< I get the error #1009 here
} else {
}
}
]]>
</fx:Script>
<mx:TabNavigator x="0" y="0" width="100%" height="100%">
<s:NavigatorContent label="Translate" width="100%" height="100%">
<s:Button label="test" click="button1_clickHandler(event)"/>
</s:NavigatorContent>
<s:NavigatorContent label="Settings" width="100%" height="100%">
<s:CheckBox x="10" y="22" label="always on top" selected="true" click="checkbox1_clickHandler(event)" id="cbAlwaysOnTop"/>
</s:NavigatorContent>
</mx:TabNavigator>
When I press the button I get the error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
What am I doing wrong?
It works if I first switch to the 2nd tabpage and then back and press the button.
You are probably in the wrong context and not have a reference to cbAlwaysOnTop.
Where is your button and where do you have the handling code?
Edit: ah, with your comment on the bottom I think I know what's going on, seems that NavigatorContent is only creating its contents when you navigate there, so if you try to access the CheckBox inside without first opening the tab, it hasn't been created and throwing you a null reference error.
Since I guess you want the settings to persist, the solution would be to create a PresentationModel class and bind the CheckBox value, so you can both save it between sessions and retrieve without relying on a UI element. Read this great article to understand what you need to do: http://riarockstars.com/2011/03/16/presentation-model-and-multiple-screens-part-1/
Ok, I found an easy solution to this using:
creationPolicy="all"
Using this in:
<mx:TabNavigator id="x1" x="0" y="0" width="100%" height="100%" creationPolicy="all">
would solve the problem.

Flex 4 - Dragging from list - dragsource.dataForFormat("itemsByIndex") is null

Thanks in advance for anyone who tries to help me out,
I am working with Flex 4 and am trying to get Drag and Drop working between Lists and between a List and non-list component.
I have a custom itemRenderer which has an image and a label.
Graphically everything works great but the data that is attached to the item I am dragging comes up in dragSource as null every time.
Here is my code:
<s:List dataProvider="{userInventory}" itemRenderer="renderers.InventoryItemRenderer" width="198" height="294" y="34" dragEnabled="true" dragMoveEnabled="true" >
<s:layout>
<s:TileLayout />
</s:layout>
</s:List>
</s:BorderContainer>
<!-- /User Inventory -->
<s:BorderContainer dragEnter="fndragEnterHandler(event);"
dragOver="fndragOverHandler(event);"
dragDrop="fndragDropHandler(event);" includeIn="crib" x="243" y="206" width="200" height="200">
<s:Label x="10" y="10" text="This is supposed to be a baby" width="178" height="24"/>
<s:Label x="10" y="39" text="State:" width="42" height="19"/>
<s:Label x="59" y="37" width="80" height="24" id="baby_state"/>
</s:BorderContainer>
private function fndragEnterHandler(event:DragEvent):void
{
DragManager.acceptDragDrop(IUIComponent(event.currentTarget));
}
private function fndragOverHandler(event:DragEvent):void
{
DragManager.showFeedback(DragManager.MOVE);
}
private function dragOverCopyHandler(event:DragEvent):void {
event.preventDefault();
//if (event.dragSource.hasFormat("itemsByIndex"))
DragManager.showFeedback(DragManager.COPY);
}
private function fndragDropHandler(event:DragEvent):void
{
//event.preventDefault();
monsterDebugger.trace(this, event.dragSource, null, "DRAG DROP");
var items:Vector = event.dragSource.dataForFormat("itemsByIndex") as Vector;
var baby:Array = babyObject.source;
monsterDebugger.trace(this, items, null, "DRAG DROP");
items[0].baby_id = baby[0]['Baby']['id'];
var item:Object = new Object();
item.id = items[0].id;
item.baby_id = items[0].baby_id;
item.effect = JSON.decode(items[0].effect);
sendAction(item, "baby", userFbData.id, "use_item_on_baby");
//TextInput(event.currentTarget).text=itemsArray[0].label;
}
And here is my itemRenderer:
<mx:Image x="14" y="19" source="{data.image}" width="50" height="50" smoothBitmapContent="true"/>
<s:Label x="0" y="-1" text="{data.name}" fontFamily="Verdana" fontSize="12" color="#696565" width="80" height="21"/>
The items Vector in the drop handler comes back null every time and I can't quite figure out why.
I thought at first that it was because that particular case is not dragging from List to List, but I tried it that way also and the dragSource.dataForFormat("itemsByIndex") continues to return null.
If anyone can point me in the right direction I would greatly appreciate it, I've been banging my head against this for two days!
you cast to Vector may already nullify the dragsource data. so try with
var items:* = event.dragSource.dataForFormat("itemsByIndex");

How to access other panels in Flex 3 ViewStack?

I have a ViewStack with 2 panels:
<mx:ViewStack id="viewstack1" height="243">
<mx:Panel id="gridPanel">
<mx:DataGrid id="grid" right="10" left="10" top="10" bottom="10" width="300" height="150" itemClick="showDetails(event)">
<mx:columns>
<mx:DataGridColumn headerText="ID" dataField="Id"/>
<mx:DataGridColumn headerText="Summary" dataField="Summary"/>
</mx:columns>
</mx:DataGrid>
</mx:Panel>
<mx:Panel id="detailsPanel">
<mx:HBox width="100%" height="100%">
<mx:VBox height="100%" width="228" id="detailsVbox">
<mx:Label text="Label" id="itemTitle"/>
<mx:Text text="Text" id="itemSummary"/>
<mx:DataGrid height="97">
<mx:columns>
<mx:DataGridColumn headerText="Property" dataField="col1"/>
<mx:DataGridColumn headerText="Value" dataField="col2"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
<mx:Image source="images/BackButton.png" width="50" height="50" click="viewstack1.selectedChild = gridPanel"/>
</mx:HBox>
</mx:Panel>
</mx:ViewStack>
I want to have the user click a grid item in the first panel and then load the data in a panel in the second panel. I can grab the value of the index for the clicked item in the itemClicked handler, but how do I access the detailsPanel to set the values based on the row info from the Grid?
I'm not sure if this is what you want, but you can do something like this:
private function showDetails(event:ListEvent):void {
itemTitle.text = event.itemRenderer.data.Id;
itemSummary.text = event.itemRenderer.data.Summary;
//assuming that the datagrid ID from the details panel is: detailsDatagrid
detailsDatagrid.dataProvider = event.itemRenderer.data.Properties;
viewstack1.selectedChild = detailsPanel;
}
In order for this to work you will also have to add a creation policy to the viewstack.
<mx:ViewStack id="viewstack1" height="243" creationPolicy="all">
This way all panels are going to be created when the viewstack is created (by default they are created only when they are needed). This ensures that you will have a reference the detailsPanel, itemTitle, itemSummary, etc... before the panel is visible.
As for me the best way is to use data binding. Just introduce additional field
[Bindable]
private var detailsDataProvider:ArrayCollection;
And fill it with details in showDetails method. If details data need to be obtained asynchronously (from server, for example) you can reset current details value until data received:
detailsDataProvider = null;
And then populate it with server data.
The final changes are in details data grid:
<mx:DataGrid height="97" dataProvider="{detailsDataProvider}">
Hope it helps.
Here this code will explain 'stackview' simple example. Using this can call panel as same.