Good news: Flex 2.0.1 now supports CSS styling within textArea components, so the following workaround is no longer needed. I'll keep this article posted for posterity. -- Rob
The Flex 2 TextArea control won't currently let you apply a CSS stylesheet to it to format its HTML text content. Here's a workaround you can use for now until there's a more official solution.
If you try to set the styleSheet
property of a standard TextArea control you get runtime error #2009: "This method cannot be used on a text field with a style sheet." That effectively prevents you from styling the HTML in a TextArea control.
You could of course apply a CSS stylesheet to a standard ActionScript 3.0 TextField (flash.text.TextField), but to make that work in Flex 2 you would have to build your own component and manage text scrolling yourself. That's not a task for the meek.
This workaround gives you the convenience of using a standard Flex TextArea plus the ability to style up its contents using CSS.
Thanks go out to Alex Harui from the Flex engineering team at Adobe for providing the initial code.
The workaround consists of two new classes, one of which, StyledUITextField, extends the UITextField class and overrides its getTextStyles()
method. The other class, StyledTextArea, extends the TextArea class and uses the StyledUITextField class in place of the usual UITextField class.
You can use the StyledTextArea control wherever you would normally use a TextArea control, like this:
<comp:StyledTextArea id="styledTxt" width="100%" height="100%" condenseWhite="true" />
To apply a CSS stylesheet to the StyledTextArea, you first create a flash.text.StyleSheet object and then set the styleSheet
property of the StyledTextArea component, like this:
var ss:StyleSheet = new flash.text.StyleSheet();
// define and set styles in the stylesheet here
this.styledTxt.styleSheet = this.ss;
Here is the code for a small test application that uses the StyledTextArea component. You can download the source files here: StyledTextArea.zip (2.5K)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:comp="com.flashlit.shared.component.*"
layout="vertical"
creationComplete="initApp()">
<mx:Script>
<![CDATA[
public var loremIpsum:String = "<h1>Lorem ipsum</h1> \
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p><br /> \
<h2>Dolor sit amet</h2> \
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \
Etiam eget erat ut neque <a href='#' target='_blank'>imperdiet venenatis</a>. \
Nam rutrum, elit eu nonummy lobortis.</p>";
public var ss:StyleSheet = new StyleSheet();
public function initApp():void
{
// show the link HTML
this.linkLbl.htmlText = "From <a href='http://www.flashlit.com' target='_blank'><u>FlashLit.</u></a>";
// create styles in the stylesheet
defineStyles();
// apply the stylesheet to the StyledTextArea control
this.styledTxt.styleSheet = this.ss;
// set the text
this.styledTxt.htmlText = loremIpsum;
}
public function defineStyles():void
{
var h1:Object = new Object();
h1.fontFamily = "Verdana, Arial, Geneva, sans";
h1.fontWeight = "bold";
h1.color = "#6600CC";
h1.fontSize = 20;
h1.leading = 10;
var h2:Object = new Object();
h2.fontFamily = "Verdana, Arial, Geneva, sans";
h2.fontWeight = "bold";
h2.color = "#666666";
h2.fontSize = 16;
h2.leading = 4;
var para:Object = new Object();
para.fontFamily = "Georgia, Times New Roman, serif";
para.fontStyle = "normal";
para.leading = 4;
para.fontSize = 12;
para.display = "block";
var a:Object = new Object();
para.fontFamily = "Georgia, Times New Roman, serif";
a.fontStyle = "normal";
a.leading = 4;
a.fontSize = 12;
a.color = "#0066FF";
a.textDecoration = "underline";
ss.setStyle("h1", h1);
ss.setStyle("h2", h2);
ss.setStyle("p", para);
ss.setStyle("a", a);
}
]]>
</mx:Script>
<mx:Label id="titleLbl" text="StyledTextArea Test" fontSize="18" styleName="appTitle" />
<mx:Text id="linkLbl" text="" fontSize="12"/>
<comp:StyledTextArea id="styledTxt" width="100%" height="100%" condenseWhite="true" />
</mx:Application>
Note that you would still get runtime error #2009 if you try to bind the styleSheet property in the MXML declaration, like this: styleSheet="{this.ss}"
. To avoid that error you need to set the styleSheet
property using ActionScript as shown above.
There are probably some limitations to using this StyledTextArea class. I haven't yet tested it in scenarios involving giant files, complex HTML formatting, or text entry. Still I figure that more than a few people might be wondering how to do this now, and a quick workaround is better than none.
As always I'm open to any suggestions for improving the code.
Finally, here is the test application in action:
This works pretty good, but the textField property of the resulting StyledTextArea is lost on the compiler (i.e. there are errors in the compiler when trying to compile something like:
styledTxt.textField.getTextFormat(beginIdx,endIdx);
So I modified the StyledTextArea class to the following (and can use theTextField in place of textField):
package com.flashlit.shared.component
{
import flash.text.TextFieldAutoSize;
import flash.text.TextFieldType;
import mx.controls.TextArea;
import flash.text.TextField;
/**
* This class provides a simple workaround to let you set
* the property of a TextArea control.
*/
public class StyledTextArea extends TextArea
{
/**
* Overrides the TextArea.createChildren()
* method to use a StyledUITextField object instead of
* a UITextField object.
*/
public var theTextField:TextField;
override protected function createChildren():void
{
textField = new StyledUITextField();
textField.autoSize = TextFieldAutoSize.NONE;
textField.enabled = enabled;
textField.ignorePadding = true;
textField.multiline = true;
textField.selectable = true;
textField.styleName = this;
textField.tabEnabled = true;
textField.type = TextFieldType.INPUT;
textField.useRichTextClipboard = true;
textField.wordWrap = true;
addChild(textField);
theTextField = textField;
super.createChildren();
}
}
}
Posted by: K___H | 08 August 2006 at 11:20 AM
KH,
That's a great addition. It gets around the problem of not being able to reference the internal textField property of a TextArea.
You could also do this without creating another variable by adding this function to the StyledTextArea class:
public function getTextField():UITextField
{
return this.textField;
}
Then you can do something like this:
styledTxt.getTextField().getTextFormat(beginIdx,endIdx);
Thanks for the suggestion!
Posted by: Rob Dixon | 10 August 2006 at 01:05 AM
One note. If you extend UITextField and override the validateNow() method:
override public function validateNow():void {
}
you will be able to still apply the stylesheet and not get the annoying error when the text stylesheet gets applied. I dont know if this totally solves the problem in all cases as you're essentially not running the validateNow method but just with a stub.
Best,
Austin
Posted by: Austin K | 05 September 2006 at 03:44 PM
Great job on this very handy component! I've started testing it for a content manager I'm trying to put together in Flex 2. One of the big drawbacks is not having a handy way to preview content a user is entering. No WYSIWYG HTML editor for flash that I know of...
One addition I made was to build a default stylesheet class so that this can be useful as soon as its included into an application.
From your example, it looks something like this:
package mypackage
{
import flash.text.StyleSheet;
public class PreviewHTMLStyles extends StyleSheet
{
function PreviewHTMLStyles():void {
var h1:Object = new Object();
h1.fontFamily = "Verdana, Arial, Geneva, sans";
h1.fontWeight = "bold";
h1.color = "#000000";
h1.fontSize = 20;
h1.leading = 10;
var h2:Object = new Object();
h2.fontFamily = "Verdana, Arial, Geneva, sans";
h2.fontWeight = "bold";
h2.color = "#333333";
h2.fontSize = 16;
h2.leading = 4;
var para:Object = new Object();
para.fontFamily = "Georgia, Times New Roman, serif";
para.fontStyle = "normal";
para.leading = 4;
para.fontSize = 12;
para.color = "#666666";
para.display = "block";
var a:Object = new Object();
para.fontFamily = "Georgia, Times New Roman, serif";
a.fontStyle = "normal";
a.leading = 4;
a.fontSize = 12;
a.color = "#0066FF";
a.textDecoration = "underline";
setStyle("h1", h1);
setStyle("h2", h2);
setStyle("p", para);
setStyle("a", a);
}
}
}
Thanks a lot once again for releasing this!
Posted by: Steve | 14 September 2006 at 11:08 AM
Rob,
thanks for your great workaround. I have been looking around the Flex community to find a solution for styling Textareas with CSS, especially with the pseudo format "a:hover".
Now I can add a "HoverStyle"-object as described above
[CODE]
var aHover:Object = new Object();
aHover.color = "#DD6600";
[/CODE]
and set this style to your text-component
[CODE]
ss.setStyle("a:hover", aHover);
[/CODE]
It work's excellent :-)
Thanks again!
sectore
--
http://www.websector.de/
Posted by: sectore | 25 October 2006 at 01:20 PM
I am in love with this workaround, finally we can assign CSS Stylesheet to HTML Text inside mx:TextArea component.
Although this workaround does not yet work when the StyledTextArea is dynamically added in the runtime to the container via addChild :(
Posted by: JabbyPanda | 15 December 2006 at 08:08 AM
OK, I applied
override public function validateNow():void {
}
to StyledUITextField and now StyledTextArea can be dynamically added at the runtime to the container via addChild :)
Posted by: JabbyPanda | 15 December 2006 at 08:57 AM
It is possible to write something by user in this StyledTextArea?
Posted by: | 10 January 2007 at 05:05 AM
why in StyledTextArea can't write?
are there anybody know ?
Posted by: Nikolay Nedev | 18 January 2007 at 12:57 AM
What is the way to to this?? I want this in th RichTextEditor.
"Good news: Flex 2.0.1 now supports CSS styling within textArea components, so the following workaround is no longer needed. I'll keep this article posted for posterity. -- Rob"
Posted by: Maikel Sibbald | 19 March 2007 at 03:13 AM
Thanks for your comments. Alas the Rich Text Editor component does not support stylesheets. If you have a Rich Text Editor instance called "editor" for example, and you try to apply a stylesheet like this, you'll get error #2009:
editor.textArea.styleSheet = myStyleSheet;
There's a simple reason: if you have CSS applied to a field, and someone edits the text, how do you know which style to apply to the new text? It's a tricky problem and tools like Dreamweaver have solved it, but the Rich Text Editor component alone cannot.
This is the same reason why a TextArea's editable property is automatically set to false when you assign something to its styleSheet property.
Having said that, there is a hack that lets you edit text in a field that has a stylesheet already set. After setting the styleSheet and displaying the results, you can set the .styleSheet property to null and set the .editable property to true. Then you can type inside the styled TextArea.
It's a hollow victory though. You can type, but you can't apply individual styles. When you detach the stylesheet and start editing, it starts treating the styles as TextFormat styles as opposed to CSS styles.
For example, let's say your original text uses an H1 HTML tag, and you have set up a H1 CSS style declaration. It will show up nicely styled after you apply the stylesheet to the TextArea, but later when you set the .styleSheet property to null and .editable to true, the .htmlText content changes. Instead of using the H1 style it changes to use a combination of a TEXTFORMAT tag, a P tag, and a FONT tag. In other words it changes from using a CSS model to a Flash TextFormat model. And once it's done that, you lose all onnection to the original H1 CSS style.
So you can see that there doesn't seem to be an easy way to edit text in a TextArea or a Rich Text Editor control without losing CSS formatting information.
Because this is such a hack I won't post the code right now, but if you really need it let me know.
Posted by: Rob Dixon | 21 March 2007 at 11:03 PM
Gread job!
How can I do the same with a Text component, which extends Label?
Posted by: zah | 24 March 2007 at 12:18 PM
Hi, I'm not able to make it work on a TextArea. Check out: http://www.adobe.com/cfusion/webforums/forum/messageview.cfm?forumid=60&catid=585&threadid=1257217&enterthread=y
It keeps throwing a #2009 error.
Posted by: Jeroen | 05 April 2007 at 06:04 AM
hi
i want to change the design of rich text editor component in flex 3. pls email me the method and if possible mail me the code.
thanx in advance
- [email protected]
Posted by: vaibhav | 23 August 2007 at 10:55 PM
I am looking for a similar fix with Actionscript 3.0. Any ideas where I might find one? Thanks and best regards, Andre
Posted by: Andre | 20 December 2007 at 03:15 AM
Thanks. override validateNow perfectly workaround problem.
Posted by: Canbey | 24 January 2008 at 05:28 AM
Can be seen at http://www.alokartvizit.com/
Posted by: Canbey | 24 January 2008 at 05:36 AM
Hi, first of all lemme thanks you for this wonderful contribution. Actually I am using your StyledTextArea on one of my project and is working great, tough, I got some problems when trying to embed fonts: the result is that they don't display in my (yours) StyledTextArea comp. Actually I have understand that i cannot apply a style to the StyledTextArea but i have to use the css file that i am parsing to get my desidered font. Below is the code i am using to parsing xml and css into the StyledTextArea.
private function loadCSS():void
{
var loader2:URLLoader = new URLLoader();
loader2.addEventListener(Event.COMPLETE, completeCSSHandler)
var request:URLRequest = new URLRequest("../css/text.css");
try {
loader2.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
}
private function loadXML():void
{
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, completeHandler)
var request:URLRequest = new URLRequest("../text/text.xml");
try {
loader.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
}
private function completeCSSHandler(event):void
{
var loader:URLLoader = URLLoader(event.target);
var css:StyleSheet = new StyleSheet();
css.parseCSS(loader.data);
ta.styleSheet = css;
}
private function completeHandler(event):void
{
var loader:URLLoader = URLLoader(event.target);
ta.htmlText = loader.data;
}
and this is my text.css file:
@font-face {
fontFamily: "myTTF";
src:url("../fonts/myTTF.ttf");
}
a {
text-decoration:underline;
color:#FF0000;
}
big {
font-size:24;
margin-bottom:-20;
}
formatted {
fontFamily: myTTF;
font-size:12;
text-align: justify;
color: #808080;
}
and finally this is my text.xml
hello world
hello world
hello world
lots of text in here
I am wondering if it would be possible to embed the font to the StyledTextArea so that it always uses myTTF so that i do not have to worry trying to embed the font later.
I can actually get it to work if i remove the StyledTextArea comp and use a regular TextArea by removing the parsing of the stylesheet and declaring into a block what i have into my text.css file.
Of course in that way I am also loosing all the html and tag formatting i am declaring at runtime:(
Any support on this would be highly appreciated.Thanks in advance!
Posted by: Yortz | 19 February 2008 at 11:00 AM
A solution for as3 css textarea is here:
http://www.sharedknowhow.com/2008/07/fixed-flash-textarea-css-incompatibility/
Posted by: Timdj | 08 July 2008 at 10:00 AM
Hi all,
I facing a problem in applying CSS in the custom component.
1. I am having the css file.
2. Created the component in action script.
3. Now I need to apply the css for the created custom components with the external css file.
How to apply the css to the components.
Please let me know
Thanks and Regards
Balaji
Posted by: Balaji | 27 August 2008 at 11:21 PM
Any support on this would be highly appreciated.Thanks in advance!
Posted by: dedikodu | 25 December 2008 at 11:46 PM
thanks for the code. css love really: D
Posted by: haşere ilaçlama | 27 March 2009 at 02:18 AM
Hi,
I want to make the textarea as editable with applied css
Thanks
Posted by: Rishi | 27 September 2010 at 08:05 AM
I know you probably get a lot of comments like this cheap wedding dresses, but just wanted to let you know that I really appreciate the work you have put into the blog. I was wondering if I could put a link on my blog because I am sure my followers would love to read it wedding party dresses. Let me know.
Posted by: cheap bras | 16 February 2012 at 01:07 AM