Overview
The FlexJS DataGrid demonstrates the composition direction of FlexJS. The DataGrid is composed of a ButtonBar component (to act as the header row) and a set of List components for the columns. The lists are kept in a Container with a ScrollableViewport so they scroll together. The DataGrid keeps selections synchronized between the lists.
A typical DataGrid declaration in an application would be:
<js:DataGrid id="dataGrid" width="100%" height="100%" className="MyDataGrid" rowHeight="60"> <js:beads> <js:ConstantBinding sourceID="applicationModel" sourcePropertyName="productList" destinationPropertyName="dataProvider" /> </js:beads> <js:columns> <js:DataGridColumn label="First" dataField="image" itemRenderer="products.ImageItemRenderer"/> <js:DataGridColumn label="Second" dataField="title" /> <js:DataGridColumn label="Third" dataField="sales"/> </js:columns> </js:DataGrid>
The ConstantBinding bead associates the application model's productList data with the dataProvider property of the DataGridModel. Each column of the DataGrid is defined by the DataGridColumn element, giving a title to the column and identifying the field within the dataProvider to use for the column. Optionally, a DataGridColumn can specify a custom itemRenderer (the one here displays an image) and set a specific width (not shown) for the column.
In addition to the ConstantBinding bead, the DataGrid uses other beads internally, as identified by the DataGrid style declaration in the defaults.css file:
DataGrid { IDataGridPresentationModel: ClassReference("org.apache.flex.html.beads.models.DataGridPresentationModel"); IBeadView: ClassReference("org.apache.flex.html.beads.DataGridView"); IBeadModel: ClassReference("org.apache.flex.html.beads.models.DataGridModel"); IItemRendererClassFactory: ClassReference("org.apache.flex.core.ItemRendererClassFactory"); IItemRenderer: ClassReference("org.apache.flex.html.supportClasses.StringItemRenderer"); background-color: #FFFFFF; }
IDataGridPresentationModel. This is not an actual "model" bead but does describe the data needed to present the DataGrid. This includes the labels for each column and the height of each row. Other presentation models could include column widths, sort order, or anything else you might need.
IBeadView: This bead assembles the user interface out of a ButtonBar and Lists (one per column). The DataGridPresentationModel's array of column labels is the dataProvider for the ButtonBar. A List is created for each of those labels and all of the Lists share the same dataProvider as the DataGrid.
IBeadModel: This bead contains the dataProvider used by the lists. Applications use a binding bead (e.g., ConstantBinding) to map the application's data model to the DataGridModel.
IItemRendererClassFactory: This bead is used to generated instances of the itemRenderer for each list.
IItemRenderer: This bead names the default class to use for itemRenderers in the list. This can be overridden by the itemRenderer property of the DataGridColumn.
Adding DataGrid Beads
public function DataGridLinesBead() { // Set default separator line stroke. var lineStroke:SolidColorStroke = new SolidColorStroke(); lineStroke.color = 0x333333; lineStroke.alpha = 1.0; lineStroke.weight = 1; stroke = lineStroke; }
- The Constructor is called first. You can create additional elements here, but do not add them to the display list. You can also set default property values.
- Properties set. Any properties that appear in MXML will be set at this point.
- The strand setter is called. After a bead has been created and its properties set, the strand is given to the bead. You can also create UI elements here and add the elements created here (or in the Constructor) to the strand as its children. If your bead needs to respond to changes in the strand, such as changes to its size, set up event listeners for those events in the strand setter.
- "beadsAdded" dispatched. Once a strand's beads have all been added and their strand setters called, the FlexJS framework dispatches the "beadsAdded" event on the strand. If you are writing a bead that needs to find or use other beads, set up an event listener for this event in the strand setter. When this event is called, you can continue setting up your bead and seek out other beads using the strand's getBeadByType() function.
- Size change events. As the UI is built and layouts are run, the strand will be sized and dispatch events: "sizeChanged", "widthChanged", "heightChanged". One or more of these events may be sent and they may be sent at any time during the life of the strand and application.
public function set strand(value:IStrand):void { _strand = value; _overlay = new GraphicsContainer(); IEventDispatcher(_strand).addEventListener("beadsAdded", handleBeadsAdded); }
private function handleBeadsAdded(event:Event):void { var host:UIBase = _strand as UIBase; var n:int = host.numElements; for (var i:int=0; i < n; i++) { var child:UIBase = host.getElementAt(i) as UIBase; if (child.id == "dataGridListArea") { _area = child; _area.addElement(_overlay); break; } } // Now set up listeners to handle changes in the size of the DataGrid. IEventDispatcher(_strand).addEventListener("sizeChanged", drawLines); IEventDispatcher(_strand).addEventListener("widthChanged", drawLines); IEventDispatcher(_strand).addEventListener("heightChanged", drawLines); // Also set up a listener on the model to know when the dataProvider has // changed which might affect the number of rows/columns and thus the // grid lines. var model:IBeadModel = _strand.getBeadByType(IBeadModel) as IBeadModel; IEventDispatcher(model).addEventListener("dataProviderChanged", drawLines); }
private function drawLines(event:Event):void { var sharedModel:IDataGridModel = _strand.getBeadByType(IBeadModel) as IDataGridModel; var presentationModel:DataGridPresentationModel = _strand.getBeadByType(DataGridPresentationModel) as DataGridPresentationModel; var layoutParent:ILayoutHost = _area.getBeadByType(ILayoutHost) as ILayoutHost; var contentView:IParentIUIBase = layoutParent.contentView as IParentIUIBase; var columns:Array = sharedModel.columns; var arrayList:ArrayList = sharedModel.dataProvider as ArrayList; var rowHeight:Number = presentationModel.rowHeight; var totalHeight:Number = arrayList.length * rowHeight; var columnWidth:Number = _area.width / columns.length; // translate the stroke to a fill since rectangles are used for the grid // lines and not lines. var lineFill:SolidColor = new SolidColor(); var weight:Number = 1; lineFill.color = (stroke as SolidColorStroke).color; lineFill.alpha = (stroke as SolidColorStroke).alpha; weight = (stroke as SolidColorStroke).weight; _overlay.fill = lineFill; columnWidth = (columns[0] as DataGridColumn).columnWidth; var xpos:Number = isNaN(columnWidth) ? _area.width / columns.length : columnWidth; _overlay.removeAllElements(); // draw the verticals for (var i:int=1; i < columns.length; i++) { _overlay.drawRect(xpos, 0, weight, totalHeight); columnWidth = (columns[i] as DataGridColumn).columnWidth; xpos += isNaN(columnWidth) ? _area.width / columns.length : columnWidth; } var n:int = arrayList.length; // draw the horizontals for (i=1; i < n+1; i++) { _overlay.drawRect(0, i*rowHeight, _area.width, weight); } }
<js:DataGrid id="dataGrid" width="100%" height="100%" className="MyDataGrid" rowHeight="60"> <js:beads> <beads1:DataGridLinesBead> <beads1:stroke> <js:SolidColorStroke color="#FF0000" /> </beads1:stroke> </beads1:DataGridLinesBead> <js:DataProviderChangeNotifier sourceID="applicationModel" propertyName="productList" /> <js:ConstantBinding sourceID="applicationModel" sourcePropertyName="productList" destinationPropertyName="dataProvider" /> </js:beads> <js:columns> <js:DataGridColumn label="First" dataField="image" itemRenderer="products.ImageItemRenderer"/> <js:DataGridColumn label="Second" dataField="title" /> <js:DataGridColumn label="Third" dataField="sales"/> </js:columns> </js:DataGrid>