HTML content inside TabNavigator - flex4

I have a case where I'm adding tabNavigator tabs dynamically and I can't figure out how to add HTML styling to some of the words.
I really only need BOLD or UNDERLINE on a few words, but I can't get any HTML formatting to work inside the NavigatorContent tag.
Can anyone help me with this? I have been looking for many hours and found nothing.
Here's what I have so far. (the content is being pulled from an external XML file).
<?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"
width="500" height="600" creationComplete="initApp()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<s:HTTPService id="chatlist" result="resultHandler(event)"
url="http://localhost/FlexLiveChat/LiveChat2/chat.xml"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
private function initApp():void
{
chatlist.send();
}
private function resultHandler(event:ResultEvent):void
{
var dp:ArrayCollection = event.result.chatsession.chat as ArrayCollection;
for(var i:int = 0; i < dp.length; i++) {
var t:TextField = new TextField( );
t.htmlText = "This field contains <B>HTML!</B>";
var label:Label = new Label();
label.text = dp.getItemAt(i).message;
var context:NavigatorContent = new NavigatorContent();
context.label = dp.getItemAt(i).chatperson;
context.addElement(label);
tn.addChild(context);
}
}
]]>
</fx:Script>
<s:BorderContainer left="10" right="10" top="10" bottom="10" height="100%" borderVisible="false">
<s:VGroup id="mainBG" x="0" y="0" width="100%" height="100%" textAlign="center">
<mx:TabNavigator id="tn" width="100%" height="100%" color="0x323232">
<!-- Define each panel using a VBox container. -->
<s:NavigatorContent label="Home">
<s:Label text="This panel is always available \n\n container panel 1"/>
<mx:Text text="This is a text control."/>
</s:NavigatorContent>
</mx:TabNavigator>
<s:TextArea width="100%" height="62" textAlign="left"/>
<s:Button label="Post Message"/>
</s:VGroup></s:BorderContainer>
</s:WindowedApplication>

You could use a text flow:
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup 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%"
gap="0">
<fx:Script>
<![CDATA[
import flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.elements.TextFlow;
private const text:String =
"<b>bold text</b><br />" +
"<br />" +
"<u>underlined text</u><br />" +
"<br />" +
"<ul>" +
"<li>list item<br /></li>" +
"<li>list item<br /></li>" +
"<li>list item<br /></li>" +
"</ul>" +
"<a href='http://www.google.com'>a link</a><br />" +
"<br />";
]]>
</fx:Script>
<s:RichEditableText editable="false"
selectable="true"
textFlow="{TextConverter.importToFlow(text, TextConverter.TEXT_FIELD_HTML_FORMAT)}"
buttonMode="true"
width="100%"
height="100%" />
</s:VGroup>
Per your comment, you should abstract the navigator content view in to a component.
Based upon your example:
Your 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"
width="500"
height="600"
creationComplete="initApp()">
<fx:Declarations>
<s:HTTPService id="chatlist"
result="resultHandler(event)"
url="http://localhost/FlexLiveChat/LiveChat2/chat.xml" />
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
private function initApp():void
{
chatlist.send();
}
private function resultHandler(event:ResultEvent):void
{
var dp:ArrayCollection = event.result.chatsession.chat as ArrayCollection;
for (var i:int = 0; i < dp.length; i++)
{
var htmlNavigatorContent:HtmlNavigatorContent = new HtmlNavigatorContent();
// attach result you want in the html text,
// including other properties.
htmlNavigatorContent.htmlText = "This field contains <B>HTML!</B>";
tn.addChild(htmlNavigatorContent);
}
}
]]>
</fx:Script>
<s:BorderContainer left="10"
right="10"
top="10"
bottom="10"
height="100%"
borderVisible="false">
<s:VGroup id="mainBG"
x="0"
y="0"
width="100%"
height="100%"
textAlign="center">
<mx:TabNavigator id="tn"
width="100%"
height="100%"
color="0x323232">
<!-- Define each panel using a VBox container. -->
<s:NavigatorContent label="Home">
<s:Label text="This panel is always available \n\n container panel 1" />
<mx:Text text="This is a text control." />
</s:NavigatorContent>
</mx:TabNavigator>
<s:TextArea width="100%"
height="62"
textAlign="left" />
<s:Button label="Post Message" />
</s:VGroup>
</s:BorderContainer>
</s:WindowedApplication>
Create a MXML Component named: HtmlNavigatorContent
<?xml version="1.0" encoding="utf-8"?>
<s:NavigatorContent 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 flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.elements.TextFlow;
[Bindable]
public var htmlText:String;
]]>
</fx:Script>
<s:RichEditableText editable="false"
selectable="true"
textFlow="{TextConverter.importToFlow(htmlText, TextConverter.TEXT_FIELD_HTML_FORMAT)}"
buttonMode="true"
width="100%"
height="100%" />
</s:NavigatorContent>

Related

Flex 4. Output my component repeatedly

I create a Skin:
<s:Group id="brick">
<s:Rect width="40" height="20">
<s:fill>
<s:SolidColor color="{hostComponent.colorBrick}" />
</s:fill>
</s:Rect>
<s:Rect width="40" height="20">
<s:stroke>
<s:SolidColorStroke color="#000000" />
</s:stroke>
</s:Rect>
</s:Group>
How do I bring this component more than once?
It is a brick. I want create wall.
You can use a loop to create the same component more than once.
Here is your skin BrickSkin.mxml:
<?xml version="1.0"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Metadata>
<![CDATA[
[HostComponent("Brick")]
]]>
</fx:Metadata>
<fx:Script>
<![CDATA[
]]>
</fx:Script>
<s:states>
<s:State name="normal"/>
<s:State name="disabled"/>
</s:states>
<s:Group id="brick">
<s:Rect width="40" height="20">
<s:fill>
<s:SolidColor id="solidColor" />
</s:fill>
</s:Rect>
<s:Rect width="40" height="20">
<s:stroke>
<s:SolidColorStroke color="#000000" />
</s:stroke>
</s:Rect>
</s:Group>
</s:Skin>
Here is your Brick component Brick.as:
package {
import flash.events.Event;
import mx.graphics.SolidColor;
import spark.components.SkinnableContainer;
public class Brick extends SkinnableContainer{
public function Brick() {
super();
}
[SkinPart(required="true")]
public var solidColor:SolidColor;
override protected function partAdded(partName:String, instance:Object):void {
super.partAdded(partName, instance);
if(instance == solidColor)
{
solidColor.color = colorBrick;
}
}
[Bindable]
private var _colorBrick:uint;
[Bindable(event="colorBrickChanged")]
public function get colorBrick():uint {
return _colorBrick;
}
public function set colorBrick(value:uint):void {
if (_colorBrick == value) return;
_colorBrick = value;
dispatchEvent(new Event("colorBrickChanged"));
invalidateProperties();
}
override protected function commitProperties():void {
super.commitProperties();
if(solidColor)
solidColor.color = colorBrick;
}
}
}
You can create BrickCSS.css as below:
#namespace local "*";
local|Brick {
skinClass: ClassReference("BrickSkin");
}
Here is your Main.mxml:
<?xml version="1.0"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
width="100%"
height="100%"
creationComplete="{buildWall()}">
<fx:Style source="BrickCSS.css"/>
<fx:Script><![CDATA[
private function buildWall():void
{
for(var i = 0; i < 200; i++)
{
var brick:Brick = new Brick();
brick.colorBrick = 0xFF0000;
tileGroup.addElement(brick);
}
}
]]></fx:Script>
<s:TileGroup id="tileGroup" width="20%" height="90%" verticalCenter="0" horizontalCenter="0" horizontalGap="0" verticalGap="0" />
</s:Application>
Here is the output snap shot.

Flex Image Disappears

I am actually just learning flex, and i am getting confused with some parts. The problem is that the background image i have set in the skin works fine until i add more elements, it then just becomes a white background rather than laying the elements over the top.
I am starting to think im misunderstanding how this works. I don't understand why i need to have <s:Group id="contentGroup" /> for the image to show in the first place...this just seems like a redundant tag?
Here is the main code and the skin:
<?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" width="800" height="523" maxWidth="800" maxHeight="523" initialize="httpService.send()" showStatusBar="false" backgroundColor="white" backgroundAlpha="1">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
public var returnData:ArrayCollection;
protected function httpService_handler(event:ResultEvent):void{
returnData = event.result.people.person;
}
]]>
</fx:Script>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
</fx:Style>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<s:HTTPService id="httpService" url="" result="httpService_handler(event)" />
</fx:Declarations>
<s:BorderContainer borderVisible="false" mouseDown="nativeWindow.startMove();" skinClass="MainStyle" width="800" height="523" id="container" >
<s:HGroup left="100" top="100" id="newsSlider" width="100" height="100">
<s:Label>
<s:text>Test</s:text>
</s:Label>
</s:HGroup>
</s:BorderContainer>
</s:WindowedApplication>
<?xml version="1.0" encoding="utf-8"?>
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<!-- host component -->
<fx:Metadata>
[HostComponent("spark.components.BorderContainer")]
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="disabled" />
<s:State name="normal" />
</s:states>
<!-- SkinParts
name=contentGroup, type=spark.components.Group, required=false
-->
<s:Group id="contentGroup" width="800" height="523">
<s:BitmapImage id="bg" source="#Embed('/School Catchup/libs/images/App-BG8.png')" scaleMode="stretch" left="0" top="0" right="0" bottom="0" width="800" height="523" />
</s:Group>
</s:Skin>
contentGroup is the only "skinPart" of the SkinnableContainer component, which is the base class for BorderContainer. It's not a required skinpart (the compiler would've thrown you an error otherwise in your previous version where you didn't have the skinpart in your skin).
What is a skinPart?
It's a contract between the host component and its skin. Essentially the host component is instructing the skin (through metadata) that it needs this and this and that element (skin part) in order to function correctly. Some of these elements are absolutely required for the component to function, some are optional.
What is the contentGroup skinpart?
It's the container element to which SkinnableContainer will add its nested elements. As an example:
<s:SkinnableContainer>
<s:Label text="hello"/>
</s:SkinnableContainer>
behind the scenes, the Label instance will be added to the contentGroup skinpart of SkinnableContainer's skin.
So how do I get my example to work?
As you can see from what I explained before, the contentGroup element is just a placeHolder in the skin. If you want to add "chrome" to your custom component, add it outside that Group:
<s:BitmapImage id="bg" source="#Embed('/School Catchup/libs/images/App-BG8.png')" scaleMode="stretch" left="0" top="0" right="0" bottom="0" width="800" height="523" />
<s:Group id="contentGroup" width="800" height="523"/>
This will display the image behind the contentGroup and your Labels will now be added to it without removing the BitmapImage that you declared in there.
This is just a short explanation of the skinning mechanism in the context of your needs. I suggest you do some research on this specific topic to really understand how it works.

Error when passing variable from one Component to another in Flex

I am getting error when trying to pass a variable from one to component to another.
I have a main MXML and 2 components. My files are as follows:
Main 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"
height="100%" width="100%" xmlns:comps="components.*">
<s:layout >
<s:VerticalLayout/>
</s:layout>
<s:Group width="100%" height="100%">
<s:HGroup>
<habilitations:CMS comps="{this}" width="637" height="48"/>
</s:HGroup>
<s:Spacer/>
<s:HGroup height="70%" width="30%">
<comps:Component1 comps="{this}"/>
<comps:Component2 comps="{this}"/>
</s:HGroup>
</s:Application>
Component1
<?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="400" height="100%">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
import mx.controls.Alert;
import mx.events.FlexEvent;
[Bindable]
public var testvar:String ="MYTEST";
[Bindable]
public var mainMXML:MainMXML;
]]>
</fx:Script>
</s:Group>
Component2
<?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="400" height="300">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable]
public var mycomponent1:Component1;
[Bindable]
public var mainMXML:MainMXML;
protected function clickHandler(event:MouseEvent):void
{
Alert.show(new String( mycomponent1.testvar ));
}
]]>
</fx:Script>
<s:Button click="clickHandler(event)"/>
</s:Group>
But I am getting the error :
Error #1009: Cannot access a property or method of a null object reference.
Can anyone help on this?
Give your components Id's
Then you can just go MyComp.SomePublicVar = value
From the second comp you could go Alert.show(parentDocument.parentDocument.MyComp.SomePublicVar);
Something like that ;)

All radioButtons in a radioButtonGroup are selected

Hello,
I have a list in a component mxml which is as follows:
<s:VGroup>
<s:Label text="TESTING" textDecoration="underline"/>
<s:List id="recouvrementModulesList" itemRenderer="renderers.ListRenderer">
<s:dataProvider>
<s:ArrayList>
<fx:String>Test</fx:String>
<fx:String>Test2</fx:String>
<fx:String>Test3</fx:String>
</s:ArrayList>
</s:dataProvider>
</s:List>
</s:VGroup>
My ListRenderer itemrenderer is as follows:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
autoDrawBackground="true">
<fx:Script>
<![CDATA[
]]>
</fx:Script>
<fx:Declarations>
<mx:RadioButtonGroup id="rbg" />
</fx:Declarations>
<s:HGroup horizontalAlign="center" verticalAlign="middle">
<mx:RadioButton id="rb" group="{rbg}" label="{data}"/>
</s:HGroup>
</s:ItemRenderer>
Notice that the radiobutton in the itemrenderer belong to the group "rbg". In this example the List appears with 3 rows (hence 3 radioButtons on each row). However when I selected the radioButtons, each at a time, the selection is allowed to be done for all radioButtons. Logically if it belongs to a group, it should allow only 1 selection, but it is not the case.
Can anyone please help on this issue?
Thanks
Use set data method :
<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">
<fx:Declarations>
<s:RadioButtonGroup id="rbg"/>
</fx:Declarations>
<s:VGroup>
<s:Label text="TESTING" textDecoration="underline"/>
<s:List id="recouvrementModulesList" >
<s:dataProvider>
<s:ArrayList>
<fx:String>Test</fx:String>
<fx:String>Test2</fx:String>
<fx:String>Test3</fx:String>
</s:ArrayList>
</s:dataProvider>
<s:itemRenderer>
<fx:Component>
<mx:HBox>
<fx:Script>
<![CDATA[
override public function set data( value:Object ) : void
{
super.data = value;
rb.label=data.toString();
rb.group=outerDocument.rbg;
}
]]>
</fx:Script>
<s:RadioButton id="rb" />
</mx:HBox>
</fx:Component>
</s:itemRenderer>
</s:List>
</s:VGroup>
Try adding a name attribute to the radio button definition. Its omission could be causing the buttons to be treated individually and not as a single unit.

Hgroup - how can I change order of elements?

When I create an HGroup and add elements to it, it adds the elements from left to right.
How can I change it to add Elements from right to left?
It sounds like you want to have the same controls and code as in usual MXML but with orientation of elements from right to left. So you need Flex SDK 4.1 and its Layout Mirroring feature. You can refer to the documentation how to use it.
This is the quick sample code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark">
<fx:Script>
<![CDATA[
[Bindable]
private var currentDirection:String = "ltr";
]]>
</fx:Script>
<fx:Declarations>
<s:RadioButtonGroup change="currentDirection = selectorsGroup.selectedValue.toString()" id="selectorsGroup" />
</fx:Declarations>
<mx:VBox horizontalCenter="0" verticalCenter="0">
<s:HGroup id="controls" layoutDirection="{currentDirection}">
<s:Button label="1" />
<s:Button label="2" />
</s:HGroup>
<s:HGroup id="selectors">
<s:RadioButton group="{selectorsGroup}" label="LTR" selected="true" value="ltr" />
<s:RadioButton group="{selectorsGroup}" label="RTL" value="rtl" />
</s:HGroup>
</mx:VBox>
</s:Application>

Resources