Walks like a duck, talks like a duck

By Apache on Sunday 30 May 2010 23:20 - Comments (3)
Categories: Flex, Geekstuff, Work, Views: 12.340

Some of you may already be familiar with duck typing from other languages like groovy.

If not you can ready about it here: http://en.wikipedia.org/wiki/Duck_typing

Anyway, I was working on a presentation, and in my example I was selecting Product-objects. And I didn't want to immediatly create InvoiceItems because 1) I didn't have an invoice object yet 2) it would require a really complex structure where I'm selecting Products and then when it's selected and/or the amount goes above 0 convert it to a different type of object and have the item renderer deal with it ... again complex solutions.

Then I remembered an idea I had on friday for an extension of the datagrid control without having to invasively extend the object to support certain action you want your custom component to have, like checkbox selection, custom background color for a row, etc

What I came up with was using the ObjectProxy class to wrap a real domain object but next to it takes any property you set on it. So you can store whatever ui state data on the object that behaves exactly like the business object, also when iterating over all the object properties or serializing the object.

I know you can just declare a class dynamic in actionscript, but this isn't what you want on a real domain object, it has fixed properties and you usually want to persist it in the end.

Little example how it looks

XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<s:List width="100%" height="100%" allowMultipleSelection="true">
        <s:dataProvider>
            <util:DynamicElementArrayList origSource="{AppModel.products}" id="dynList" />
        </s:dataProvider>
        <s:itemRenderer>
            <fx:Component>
                <s:ItemRenderer>
                    <s:HGroup width="100%" height="25" verticalAlign="middle" doubleClickEnabled="true" doubleClick="data.amount++">
                        <s:CheckBox selected="@{data.selected}" /> 
                        <s:Label text="{data.name}" /><mx:Spacer width="100%" /><s:Label text="{data.price}" />
                        <s:ComboBox selectedItem="@{data.amount}" requireSelection="true">
                            <s:ArrayCollection>
                                <fx:Array>
                                    <fx:Number>1</fx:Number>
                                    <fx:Number>2</fx:Number>
                                    <fx:Number>3</fx:Number>
                                    <fx:Number>4</fx:Number>
                                    <fx:Number>5</fx:Number>
                                </fx:Array>
                            </s:ArrayCollection>
                        </s:ComboBox>
                    </s:HGroup>
                </s:ItemRenderer>
            </fx:Component>
        </s:itemRenderer>
    </s:List>



The dynamicElementArrayList will just wrap each object inside a DynamicElement class.

And the core of the DynamicElement are these 2 simple overrides:

Flash ActionScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
flash_proxy override function getProperty(name:*):* {
            if (wrappedObject.hasOwnProperty(name))
            {
                return super.getProperty(name);
            } else {
                return dynamicProperties[name];
            }
        }
        
        flash_proxy override function setProperty(name:*, value:*):void {
            var oldValue: *;
            if (wrappedObject.hasOwnProperty(name))
            {
                oldValue = wrappedObject[name]; 
                super.setProperty(name, value);
            } else {
                oldValue = dynamicProperties[name];
                dynamicProperties[name] = value;
            }
            
            // binding
            this.dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, null, this, oldValue, value, this));
        }



Similar things can be done in php using __get() and __set(), and probably in other languages as well.

In the end it allows me to have this screen backed by regular old domain objects, but I can also get/set the metadata I need for the ui, without having to create new classes every time.

http://tweakers.net/ext/f/0R7pI6hMfL8tuLPEAOxB2wqo/full.png

can be handled as, where obj.selected and obj.amount are not on the original object, and the ObjectUtil.toString does not show the new dynamic properties and also identifies the object class as the original domain class.

Flash ActionScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for each (var obj: Object in dynList)
                {
                    trace("----------------------------");
                    if (obj.selected)
                    {
                        trace(ObjectUtil.toString(obj));
                        trace("amount: " + obj.amount);
                    }
                    else
                    {
                        trace("not selected:");
                        trace(ObjectUtil.toString(obj));
                    }
                    
                }



http://codecaster.nl/got/rmb/star1.gifhttp://codecaster.nl/got/rmb/star2.gifhttp://codecaster.nl/got/rmb/star3.gifhttp://codecaster.nl/got/rmb/star4.gifhttp://codecaster.nl/got/rmb/star5.gifhttp://codecaster.nl/got/rmb/stats.gif

Volgende: AAARGH BASE! 09-'10 AAARGH BASE!
Volgende: Flex - little black book 04-'10 Flex - little black book

Comments


By Tweakers user MMaI, Monday 31 May 2010 11:19

hartelijk dank voor het herinneren waarom ik gene XML datastores gebruik!

By Tweakers user gang-ster, Monday 31 May 2010 12:53

If it takes more than 10 lines of code to do the above something is deeply wrong.

By Tweakers user Apache, Monday 31 May 2010 13:06

@MMal: de data komt van een java backend en word gewoon gedeserialiseerd naar een objectgraph. Dat is de UI declaratie die hier in mxml staat.

Het draait em op het feit dat je je objectgraph in je ui wil gebruiken maar ook vaak ui state per object wil opslaan, en dit zonder telkens hardcoded wrappers te gaan schrijven.

Vb: class Product hierboven is een java bean met [name,price] maar hier wilde ik [name,price,selected,amount] selected & amount zijn tijdelijke properties en zelfs specifiek voor 1 bepaald ui component zonder dat je nieuwe wrappers moet maken.

@gang-ster: in een volledige dynamische taal gaat dit vast sneller/korter, in Java ben ik nu al eenmaal gewoon om een mooi net gedefinieerd model, persistancy model, etc te hebben, ik vind dit al zeer flexibel aan de ui kant ;)

Je wil niet weten hoe pijnlijk iets als dit is in bvb JSF, nieuwe DTO + conversie's in backing bean.

Comments are closed