Archive for December, 2006

On Holiday for Last Week of Year

I will be on holiday during the last week of the year (25-Dec-2006 through 29-Dec-2006). I’ll be back in the office 2-Jan-2007.

Have safe holidays and I look forward to new adventures next year.

Inline itemRenderer

itemRenderers that change data

I recently had the pleasure of working with one of our customers, Ryan Green of Davita, who agreed to share this bit of code. I like it because it is straightforward, yet contains many interesting bits. I’ve made some alterations from Ryan’s original code for this example.

Download this example here

I’ve had questions from people who have put Buttons or some other interactive component into a cell of a DataGrid and wanted to know how to get the button to change the DataGrid. A common use is a trashcan to delete the record. Here’s one approach which shows a simple order catalog. Clicking on the "add to cart" link on a row decrements the quantity in stock. When the quantity reaches zero the link becomes disabled and changes to "out of stock".

Let’s start with the DataGrid definition. You’ll see an in-line itemRenderer, which for this case is a neat solution. You can also use a custom component with the same code.

<mx:DataGrid id="grid" dataProvider="{dp}" selectable="false" y="45" horizontalCenter="0"
                     width="390" height="169">
     <mx:columns>
           <mx:DataGridColumn headerText="Product" dataField="product"/>
           <mx:DataGridColumn headerText="Quantity" dataField="quantity"/>
           <mx:DataGridColumn headerText="Order" dataField="action" >
                  <mx:itemRenderer>
                        <mx:Component>
                                  <mx:LinkButton label="{data.action}"
                                                         
enabled="{data.quantity > 0}"
                                                         
click="sendEvent()">
                                        <mx:Script>
                                        <![CDATA[

                                                private function sendEvent() : void
                                               {
                                                      dispatchEvent( new CustomEvent(data) );
                                                }

                                        ]]>
                                       </mx:Script>
                                </mx:LinkButton>

                        </mx:Component>
                  </mx:itemRenderer>
           </mx:DataGridColumn>
      </mx:columns>
</mx:DataGrid>

This looks like:

The itemRenderer for the last column is a LinkButton. The label for the LinkButton is taken from the value of the record’s "action" field. The LinkButton is enabled only when the value in the "quantity" field is greater than zero. When clicked, the LinkButton calls the sendEvent() method in its Script block.

Note: The itemRenderer is a LinkButton but you can also use a Container, such as Canvas, and place the LinkButton inside it plus any other components that are relevant to your data.

The click event handler, sendEvent, dispatches ChartEvent (a custom event). The CartEvent is given the data record from the row.

Note: In case itemRenderers are new for you, most Flex components, including those used for itemRenderers, have a data property. This property is set with the current record of the dataProvider corresponding to the row of the itemRenderer instance.

This is the CartEvent class:

public class CartEvent extends Event
{
      static public const ADD_TO_CART:String = "addToChart";

      public function CartEvent(data:Object, bubbles:Boolean=true, cancelable:Boolean=false)
      {
           super(ADD_TO_CART, bubbles, cancelable);
           this.data = data;
      }
      public var data:Object;
}

Not much to it really. The event type is "addToCart". This is not an event the DataGrid dispatches. So how do you listen for this event and use it? The key is the bubbles value of the event: it is set to true by default in the CartEvent constructor function. This means you can set an event listener on any component "above" the itemRenderer – the DataGrid or the Application – whichever makes sense for you.

Since the DataGrid does not it offically support "addToCart" you cannot put it as an attribute on the <mx:DataGrid> tag. But you can assign an event handler for it in ActionScript:

grid.addEventListener(CartEvent.ADD_TO_CART, customHandler);

with the customHander() function:

private function customHandler( event:CartEvent ) : void
{
      // the data record is included in the event; it can be modified and
      // put back into the dataProvider where it will be picked up by the
      // DataGrid

      event.data.quantity -= 1;
      dp.itemUpdated(event.data,"quantity");
      if( event.data.quantity <= 0 ) {
           event.data.action = "out of stock";
           dp.itemUpdated(event.data,"action");
      }
}

When the LinkButton in a row is clicked, it dispatches the CartEvent which is handled by the customHandler() function. The function decrements the value in "quantity" of the given data record and the dataProvider is updated. Should the value hit zero, the text in the "action" field is changed to "out of stock" and also updated in the dataProvider.

Clicking on the "add to cart" link for the Sprokets product enough times reduces its count to zero, changing the LinkButton to "out of stock" and disabling it.

Notice that when the data is being updated the property name is also given to the itemUpdated() method. By doing this you ensure that only that field is changed. Should the dataProvider collection have a Sort on it, and that field is not part of the sort, updating the dataProvider will not cause a sort to occur.

There are a number of variations on this example. For instance, the CartEvent could pass the row index instead of the data itself. Then the customHandler has to extract the data from the dataProvider using the index. In some circumstances the index will probably be more useful than the data. Or maybe you’ll need both.

What about itemClick?

Now you might think that you can just do all this with the itemClick event. And you are right. Using itemClick you can get which row and which field was clicked. You can update the data and the change will be reflected in the DataGrid.

But the beauty of the approach shown here is that you have an interactive cell – a LinkButton in this case, but it could be more complex. Consider this approach if you have the need for a custom itemRenderer.

Masked TextInput

There’s a new control available on Adobe Exchange – masked text input. Here’s the link to the FlexTeam blog:

http://weblogs.macromedia.com/flexteam/archives/2006/11/component_maske.cfm