Hi all,

I'm pretty sure that any answers for this one will help a lot of people, 
since the basis of it crosses many complex business applications.

I have existing CF apps (Purchase Requests, Travel Requests, Request 
Approvals, etc.) that contain many-to-many relationships, such as PR 
Number > Charge Strings > Item/Costs, wherein the PR contains one or 
more charge strings, and each charge string can have one or more items. 
I am prototyping Flex versions, but I have come across a little (ha) bit 
of a situation where I am not sure of the best method to proceed.  I 
have a actionscript form for creating a _new_ request, allowing the user 
to add charge strings and associated items dynamically (stripped version 
included below in case someone needs/wants to see how I did this). 

Textually, a request being updated might look like this:

Request 1001

Charge String 1: CS: (combobox)
Item 1: Type (combobox) Cost (Number)...etc.
Item 2: Type (combobox) Cost (Number)...etc.
Item 3: Type (combobox) Cost (Number)...etc.

Charge String 2: (combobox)
Item 1: Type (combobox) Cost (Number)...etc.
Item 2: Type (combobox) Cost (Number)...etc.

Charge String 3: (combobox)
Item 1: Type (combobox) Cost (Number)...etc.

Note that Charge Strings and Items have unique IDs and there is a 
relation between items and charge strings as well as items and the request.

However, a request also has to be available for updates, since they can 
remain in draft status before being submitted for approvals.  The 
situation is this: Because of the possible many-to-many relationship 
between charge strings and related items within a request, I'm not quite 
sure of the best method of populating the form for updates. 
Additionally, the user may add, remove or update items or an existing 
charge string, and add new charge strings with new items

In CF, I only have to make 1 query to get the primary data I need, and I 
can do a nested loop to create the form easily by checking for a change 
in the charge string to know when to display the CS combobox and when to 
display it's associated items. On update, we archive the old charge 
string and item data and insert new rows into SQL Server, rather than 
trying to determine which charge strings and/or items were updated.  
This is for processing speed and the ability to recreate a request at 
any point in time (using version numbers), the latter being necessary 
for auditing the approval/rejection history of a request.

I am not sure if looping is the best method to use in Flex -- 
particularly since the containers are dynamic out of necessity -- nor am 
I positive about the manner in which I should do this, in particular the 
data population/combobox selected items.

(Btw, I started doing this with components, but actionscript was faster 
for me to get it to work...I'll end up going back to that just for code 
reuse but I like to see things work first :-)

----- charge string with estimated cost items code module  (improvements 
or hints appreciated as well) -----

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"; 
creationComplete="addCS();">

<mx:Script>

    <![CDATA[
    import mx.controls.Alert;
    import mx.controls.TextInput;
    import mx.containers.HBox;
    import mx.controls.ComboBox;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import mx.collections.ArrayCollection;
    import mx.utils.ArrayUtil;

    //sample data for charge string combobox; would normally come from 
an RO call
    [Bindable]
    public var CSCollection:ArrayCollection = new 
ArrayCollection([{csUID: 1000, label: "CS1000"},{csUID: 1001, label: 
"CS1001"},{csUID: 1002, label: "CS1002"}]);

    //sample data for estimate type combobox; would normally come from 
an RO call
    [Bindable]
    public var ETCollection:ArrayCollection = new 
ArrayCollection([{etUID: 1000, label: 'Airfare'},{etUID: 1001, label: 
'Meals'},{etUID: 1002, label: 'Other'}]);

    public function addCS():void    {
        var newVBox:VBox = new VBox();
        newVBox.setStyle( "borderColor", "#000000" );
         newVBox.setStyle( "borderStyle", "solid" );   
        newVBox.setStyle("paddingBottom", 5);
        newVBox.setStyle("paddingRight", 5);
        newVBox.setStyle("paddingLeft", 5);
        newVBox.setStyle("paddingTop", 5);
        newVBox.percentWidth = 100;
       
        var newCS:ComboBox = new ComboBox();
        newCS.percentWidth = 100;
        newCS.dataProvider = CSCollection;
        var csCloseBtn:Button = new Button();
        var csAddEstBtn:Button = new Button();
       
        csCloseBtn.label = "Delete this Charge String and Associated 
Estimates";
        
csCloseBtn.addEventListener(MouseEvent.CLICK,csCloseBtnClickListener);
       
        csAddEstBtn.label = "Add Another Estimate to this Charge String";
        
csAddEstBtn.addEventListener(MouseEvent.CLICK,csAddEstBtnClickListener);
   
        var newbtnHbox3:HBox = new HBox();
       
        newbtnHbox3.addChild(newCS);
        newbtnHbox3.addChild(csCloseBtn);
        newbtnHbox3.addChild(csAddEstBtn);
       
        newVBox.addChild(newbtnHbox3);
       
        var eparent:Object = newVBox;
        addEst(eparent);
        csbox.addChild(newVBox);
    }
   
   
    public function csCloseBtnClickListener(e:Event):void
    {
        var ncs:Number = csbox.numChildren;
       
        if (ncs != 1)
        {
        csbox.removeChild(e.target.parent.parent);
        }
        else
        {
        Alert.show("Minimum of One Charge String Required");
        }
    }
   
    public function csAddEstBtnClickListener(e:Event):void
    {
        addEst(e.target.parent.parent);
    }
   
    public function estCloseBtnClickListener(e:Event):void {
        //set a var indicating the hbox that is the estimate row object...
        var thisestChild:DisplayObject = e.target.parent.parent;
        //set a var indicating the parent csbox that contains the 
estimate row object
        var thiscsboxDO:Object = e.target.parent.parent.parent;
        //determine number of estimates: total children in csbox - 1 cs 
& button row
        var nest:Number = e.target.parent.parent.parent.numChildren - 1;
       
        if (nest != 1)
        {
        thiscsboxDO.removeChild(thisestChild);
        }
        else
        {
        Alert.show("Minimum of One Estimate per Charge String Required");
        }
    }
   
    public function addEst(eparent:Object):void
    {
        var newVbox2:VBox = new VBox();
        newVbox2.percentWidth = 50;
        var newEst2 : TextInput = new TextInput();
        newEst2.text = "(estimated cost here)"
        var newcbEst:ComboBox = new ComboBox();
        newcbEst.dataProvider = ETCollection;
        var estCloseBtn:Button = new Button();
        estCloseBtn.label = "Delete this Estimate";
        
estCloseBtn.addEventListener(MouseEvent.CLICK,estCloseBtnClickListener);
       
        var newHbox3:HBox = new HBox();
        newHbox3.addChild(newcbEst);
        newHbox3.addChild(newEst2);
        newHbox3.addChild(estCloseBtn);
        newVbox2.addChild(newHbox3);
       
        eparent.addChild(newVbox2);
    }
   
        ]]>
       
</mx:Script>
  
 <mx:Canvas height="100%" width="100%" id="csestcanvas">

    <mx:Panel title="Charge Strings and Estimated Costs" id="CSEstPanel"
        backgroundColor="#eeeeee"  width="90%" height="{csestcanvas.height}"
        paddingTop="10" paddingLeft="10" paddingRight="10" 
paddingBottom="10">

         <mx:Button id="AddCS"  label="Add a New Charge String" 
click="addCS()"/>
       
            <mx:VBox width="100%" id="csbox" >  
                <!-- this is where all AS containers/controls are added -->
            </mx:VBox>   
       
    </mx:Panel>
   
</mx:Canvas>

</mx:Application>





Reply via email to