Changing MXML string labels via XML

On December 11, 2007, in Flex, by Anuj Gakhar

I personally dont like hardcoding things like texts and labels inside any compiled code, reason being , when it needs to be changed for whatever reason, I have to go through the pain of loading the project and making the change and then compiling it again and deploying it again , all for one little change. Its always better to save as many as possible config’s in a separate file (XML being the more appropriate choice).

Each MXML component has loads of attributes. The most commonly used ones being toolTip, text, label and other strings like Validator error messages or some other hardcoded text. So how do we make our application so that we are able to change all these without a re-compile ? Well, one of my friends (must say, very good at Flex) and myself (not so good yet;)) came up with this solution.

I will try and explain the structure of the XML we ended up with. The idea is, whatever the name of your MXML file, the XML must have the same tags in it. e.g. if you have a file called LoadXML.mxml in your Flex application, you need to make a XML file and it should look like this :-

[xml]
<LoadXML>
<label_btnClose>CLOSE ME</label_btnClose>
<label_btnPrint>PRINT ME</label_btnPrint>
</LoadXML>[/xml]

These XML nodes you see, e.g. label_btnClose, the first part (“label”) is the actual property of a component which has an id called “btnClose” inside LoadXML.mxml . You can literally remove all the string properties and hardcoded stuff from your MXML file and put them all in here.

The idea here is to come up with a XML parser function that reads this XML file, looks for anything under MyPreview in XML and parses it in a way that it actually applies the underlying properties to the named components on the fly, in MyPreview.mxml. And that basically means that, once you have compiled your Flex app, you just need to modify your XML to manage how your application’s look n feel or text labels (remember you can actually use this for internationalization as well).

Now, lets create a simple MXML file to implement this.

[xml]
<mx:Script>
<![CDATA[
import classes.PropertyHandler;
private function doInit():void
{
PropertyHandler.addEventListener("fileReady", this.fileLoaded);
PropertyHandler.init();
}
private function fileLoaded(e:Event):void
{
PropertyHandler.applyLangSet(this, this.className);
this.btnMisc.label = PropertyHandler.getControlLang(this.className).miscText;
}
]]>
</mx:Script>
<mx:VBox id="myVBox">
<mx:Button id="btnClose" />
<mx:Button id="btnPrint" />
<mx:Button id="btnMisc" label=""/>
</mx:VBox>[/xml]

As you can see, all it does is create 3 buttons with different ID’s and on initialization, it loads the XML file via a static class called propertyHandler which actually reads the XML files and applies the labels to the buttons. btnClose and btnPrint do have a label property in the XML whereas btnMisc gets its label via an individual property in the XML file. The code should explain it all. Few things to keep in mind though :-

1) PropertyHandler is the main class here which is doing the job, have a look at it.
2) This works only for string properties, not for anything else. So, labels, texts, validator messages would all work fine.
3) Each MXML file you want to use this on, must do a applyLangSet on creationComplete in order for this to work.
4) When you make any changes to XML, restart your browser to see the changes being reflected.

If I missed anything, let me know and I’ll be happy to assist.

Oh, the demo is here , right click to view source.

Tagged with:  

18 Responses to Changing MXML string labels via XML

  1. Anuj Gakhar says:

    similar concept but not really the same. In a ResourceBundle you would still have to write some code to get the string from the ResourceBundle (either in AS or MXML) but in my example, you just give it a ID and rest is handled from the XML.

  2. Lordy says:

    We do a similar thing in our application, but I inverted the control like this

    private static function translateItem(event:FlexEvent,code:String,property:String):void
    {
    var target:* = event.target;
    var translation = translate(code);
    target[property] = translation;
    }

    we do this in our application, because if you change the mxml the xml has to change along with it, here we can change the mxml as much as we want and it will call for translation when we need it. Also it helps skip that small step where the component has to draw a whole set of empty labels, and then fill it in afterwards.

  3. Lordy says:

    Whoops the code for the mxml is

    mx:Button preinitialize=”translateItem(event,’Label_string’,’label’)”

    or

    mx:Label preinitialize=”translateItem(event,’Label_string’,’text)”

  4. Anuj Gakhar says:

    @Lordy,
    nice suggestion, however, you still need to write this piece of code for every property you want to be translated via your function. and it also means that all properties are still hardcoded insie the mxml file. What I was trying to do was to give the mxml component a ID and then manage all its string properties externally from the XML.

  5. Anuj Gakhar says:

    @Adrian, yes David Buhler already pointed that out. My example looks similar to ResourceBundle but its not quite exactly the same. However, ResourceBundle would solve the same purpose as well.

  6. David Buhler says:

    @Anuj

    I’d suggest going with the resource bundle.

    One of the the strong points of CF is its Java integration. You can leverage Java for the i18n internationalization. On the Flex client, you’ll be able to change the labels to accommodate internationalization. By going with the RB, one’s lingo and methodology fit within the common ‘talk’ for this approach.

    DB

  7. Anuj Gakhar says:

    @David,

    You are right . I am not really into Java so never used Resource Bundles before. I think the main advantage of using Resource Bundles would be that it can support more than just strings, like in my example. But I do beleive that if I extend my example to have lets say a french or spanish translated XML file, I could load that up on runtime to accomodate internationliaztion. I guess I was trying to re-invent the wheel but it was worth an exercise and made me learn a lot in the process.

  8. Ernesto says:

    Now,
    how about creating one class with a bindable property, for example:

    function Translate(s:String):String

    And in every label put {TranClass.Translate(xxx)}
    where xxx is the key of the hash defined in XML?

  9. P Buchanan says:

    Thinking out of the box – I like that Anuj. Good job.

  10. Anuj Gakhar says:

    Thanks , P Buchanan. 🙂

  11. Anuj Gakhar says:

    @Ernesto, that would work as would the ResourceBundle but the idea is to not write any code inside the button or label to explicitly tell it to read its string property from somewhere . Infact, my PropertyHandler just reads the IDs, matches them with properties from XML and applies them, neatly , in the background.

  12. Ben says:

    Nice code Anuj! Works perfectly – however it doesn’t seem to effect any of the objects that aren’t initially visible – eg those in an accordion roll. Being a relative newbie to this – is there a quick fix to address all objects visible or not?
    Thanks
    Ben

  13. Anuj Gakhar says:

    Ben, there is a manual assigning as well. you could do something like
    PropertyHandler.getControlLang(this.className).miscText;

  14. Joao Paulo says:

    That is what I was looking for. I really appreciated your piece of code.
    Thank you.

  15. Anuj Gakhar says:

    @Joao, Glad you liked it. Thanks.

  16. Manish says:

    Nice work Anuj
    But better is to use HttpService read xml and using <mx:Repeater create multiple elements as per your xml. It gives you more dynamic code as you can easily change no. of components.

Leave a Reply to Anuj Gakhar Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

© 2011 Anuj Gakhar
%d bloggers like this: