Using validators in DataGrid - Flex - apache-flex

i have an editable DataGrid, something like:
<mx:Datagrid editable="true" dataProvider="{arrayListPreferences}" id="preferencesGrid">
<mx:columns>
<mx:DataGridColumn header="col1" dataField="preference" editable="false"/>
<mx:DataGridColumn header="col2" dataField="value" editable="true"/>
</mx:columns>
</mx:Datagrid>
When the user edits the data there's a button that he clicks and calls a function that saves the data to a database, and in this function i have to validate the data before sending it. I want to use simple validators (NumberValidator, StringValidator, etc) but i don't know how to set the source of this validators to the specified rows in the second column.

<mx:NumberValidator source="{preferencesGrid.selectedItem}" property="value"
integerError="Enter Integer value"
minValue="18" maxValue="50" domain="int"
trigger="{saveButton}" triggerEvent="click"
valid="saveData();"/>
Set the property of validator to the dataField of the desired column.

<mx:DataGridColumn editable="true" itemRenderer="MyTextInputItemRenderer"/>
public class MyTextInputItemRenderer extends TextInput{
private var validator:StringValidator;
public function MyTextInputItemRenderer(){
validator = new StringValidator;
validator.minLength=0;
validator.property = "text";
validator.source = this;
}
override public function set data(value:Object):void{
super.data = value;
validator.validate();
}
}

Related

Flex Datagrid Column Total

I have a data grid that that has a title, price, qty and total column. The title, price and qty data is loaded from an xml file and the total is populated with a labelFunction to multiply the price by the qty.
I'm able to populate the total for each row with a labelFunction by returning a string to the row under the total column, but I'm having trouble figuring out how to get the overall total for the total column. I'd like to get the overall total and display it in a textBox/somewhere else outside of the datagrid.
I'm able to get the total by using the updateEsimate function, but it'll only send the total using itemEditEnd on the datagrid (which means i'd have to click on eat qty row for it to tally up) and I'd like it to give me the total automatically once it loads.
Help Please!
(some sample code)
public function updateEstimate(event:DataGridEvent):void
{
// TODO Auto-generated method stub
var sum:Number = 0;
for(var i:int=0; i<orderGrid.dataProvider.length ; i++) {
sum += Number(orderGrid.dataProvider.getItemAt(i).total);
totaltxt.text = sum.toString();
}
totaltxt.text = sum.toString();
}
public function getTotal(item:Object, column:DataGridColumn):String
{
var sum:Number = item.price * item.quantity;
return sum.toString();
}
<mx:XMLListCollection id="xmlProdListColl"
source="{productXML.lastResult.offer}"
/>
</fx:Declarations>
<mx:DataGrid id="orderGrid" x="44" y="0" width="640" height="155"
dataProvider="{xmlProdListColl}"
doubleClickEnabled="true" editable="true"
itemEditEnd="orderGrid_itemEditEndHandler(event); updateEstimate(event)">
<mx:columns>
<mx:DataGridColumn headerText="Title" dataField="title" editable="false"/>
<mx:DataGridColumn headerText="Price" dataField="price" editable="false"/>
<mx:DataGridColumn headerText="Quantity" dataField="quantity"/>
<mx:DataGridColumn headerText="Total" labelFunction="getTotal" editable="false"/>
</mx:columns>
</mx:DataGrid>
<s:RichText id="totaltxt" width="147" height="84" fontSize="18" text="" textAlign="center"
verticalAlign="middle" />
From what i see you calculate the totals in getTotal() to display the totals but are not settings the "total" property in the actual object. And it is the total property that you use in updateEstimate(). So whenever you would edit the quantities you still would see correct total in the datagrid but the value in the textfield would remain the same
I am not a big fan of binded dataProviders because you never know when data is available and it's hard to modify it (like we need it here). I prefer my own dataProvider variables that are strong typed and that I can modify as I wish :)
So I would do it this way:
I assume, your XML looks somethign like this and you don't have the "total" value in it:
<root>
<lastResult>
<offer>
<title>Title</title>
<price>20</price>
<quantity>1</quantity>
</offer>
<offer>
<title>Title 2</title>
<price>30</price>
<quantity>2</quantity>
</offer>
</lastResult>
At some point in your code you will have your XML. This is where you modify it adding a total property and pass the dataProvider to the grid:
private var _orderDataProvider:XMLListCollection;
private function gotData():void
{
var list:XMLList = new XMLList(productXML.lastResult.offer);
_orderDataProvider = new XMLListCollection(list);
updateEstimate(); // call this before we assign the dataprovider to the grid, so we will have totals in items
orderGrid.dataProvider = _orderDataProvider;
}
public function updateEstimate(event:DataGridEvent = null):void
{
// update all totals in all items and the "Estimated total" in one go
var sum:Number = 0;
for (var i:int = 0; i < _orderDataProvider.length; i++)
{
var item:Object = _orderDataProvider.getItemAt(i);
item.total = item.quantity * item.price;
sum += Number(_orderDataProvider.getItemAt(i).total);
}
totaltxt.text = sum.toString();
}
MXML:
<mx:DataGrid id="orderGrid"
x="44"
y="0"
width="640"
height="155"
doubleClickEnabled="true"
editable="true"
itemEditEnd="updateEstimate(event)">
<mx:columns>
<mx:DataGridColumn headerText="Title"
dataField="title"
editable="false"/>
<mx:DataGridColumn headerText="Price"
dataField="price"
editable="false"/>
<mx:DataGridColumn headerText="Quantity"
dataField="quantity"/>
<mx:DataGridColumn headerText="Total"
dataField="total"
editable="false"/>
</mx:columns>
</mx:DataGrid>
<s:RichText id="totaltxt"
width="147"
height="84"
fontSize="18"
text=""
textAlign="center"
verticalAlign="middle"/>
Now as you see this is not the ideal code because we update totals in ALL items every time on edit although you edit only one entry but we don't have to mess with several functions, so as long as you don't have 1000 entries in your list it should be fine.
You can use the CollectionEvent on the XMLListCollection instead. This will get dispatched at the beginning and when any updates are made to the data:
public function updateEstimate(event:CollectionEvent):void{
// your update code
}
<mx:XMLListCollection id="xmlProdListColl"
collectionChange="updateEstimate(event)"
source="{productXML.lastResult.offer}"/>

Flex - Adding a New Line in a DataGridColumn

To start with, I am very new to Flex.
I have a ComboBox that is filled in with choices from the database. Underneath that is a Flex Datagrid with DataGridColumns (mx:located below). I would like to figure out a way that when a selection is made from the comboxbox and the add button is clicked, it populates the next line in the datagrid column based off what was selected. Any thoughts on how this can be done? Maybe I should not use a combobox, just populate the datagridcolumn, not for sure, any hep would be great.
ComboBox Choices - Apples, Oranges, & Pears
Each choice is linked with attributes.
(Apples) nameSpace, countrySpace, infoSpace
(Oranges) nameSpace, countrySpace, infoSpace
(Pears) nameSpace, countrySpace, infoSpace
public var ta1:ArrayCollection = new ArrayCollection();
//Is there a better way of writing this?
public function addDataGridColumn():void
{
var list:ArrayCollection = templateAttributes;
var att:TemplateAttribute = new TemplateAttribute();
(templateProp.dataProvider as ArrayCollection).addItem(att);
}
<mx:HBox>
<mx:ComboBox dataProvider="{templateAttributes}" width="300" prompt="Select a Template Attribute" enabled="{userInEditMode}" labelField="attributeName" />
<mx:Button id="addButton" click="addDataGridColumn();" styleName="addButtonOff" enabled="{userInEditMode}" label="ADD" />
</mx:HBox>
<mx:DataGrid id="templateProp" dataProvider="{templateAttributes}" width="100%" height="100%" editable="true">
<mx:columns>
<mx:DataGridColumn id="nameSpace" dataField="nameSpace" headerText="Name" width="25" editable="{userInEditMode}"/>
<mx:DataGridColumn id="valueSpace" dataField="valueSpace" headerText="Value" width="25" editable="{userInEditMode}" />
<mx:DataGridColumn id="countrySpace" dataField="countrySpace" headerText="Main Country" width="25" editable="{userInEditMode}" />
<mx:DataGridColumn id="infoSpace" dataField="infoSpace" headerText="Information" width="25" editable="false"/>
<mx:DataGridColumn id="infoSpace" dataField="infoSpace" headerText="Information" width="25" editable="false"/>
</mx:columns>
</mx:DataGrid>
Rewriting that function would only shave off a line of code:
public function addRow() : void {
var att:TA= new TA();
att.attributeName = "abc";
(template1.dataProvider as ArrayCollection).addItem(att);
I dunno what TA is, but if you wanted it to be even shorter, you could make TA take attributeName in its constructor. Then you could do this:
public function addRow(attributeName:String) : void {
(template1.dataProvider as ArrayCollection).addItem(new TA(attributeName));
}

Get data from datagrid in a view to a label

<mx:DataGrid id="dgAutoFill" x="11" y="234" width="934" dataProvider="{rssHln.lastResult.rss.channel.item}">
<mx:columns>
<mx:DataGridColumn dataField="title" headerText="Titel"/>
<mx:DataGridColumn dataField="description" headerText="Omschrijving"/>
<mx:DataGridColumn dataField="pubDate" headerText="Publicatiedatum"/>
<mx:DataGridColumn dataField="link" headerText="Link"/>
</mx:columns>
</mx:DataGrid>
I'm trying to get the title from the selecteditem from this datagrid (which is filled by a rss-feed) in a label. I've searched for ways, but I can't find how I should get this done.
This is the eventhandler I've added to the datagrid, and the function:
dgAutoFill.addEventListener(ListEvent.ITEM_CLICK, showDetails);
public function showDetails(event:ListEvent):void {
lblTitle.text = ?;
}
I think you want to create an click event handler, like this:
protected function showDetails(event:ListEvent):void{
myLabel.text = dgAutoFill.selectedItem.title;
}

Accessing DataGridColumn item renderer variable

Within a DataGrid, I have a DataGridColumn that uses a custom component as the item renderer. Within the component, I have an ArrayCollection that stores a set of value objects. My problem is that I cannot access the ArrayCollection values from outside of the item renderer component. Does anyone know how it would be possible to do this? I have posted a code snippet below.
<mx:Script>
<![CDATA[
// Cannot access arrFiles from here.
]]>
</mx:Script>
<mx:DataGrid editable="true">
<mx:columns>
<mx:DataGridColumn id="dgcUpload" width="130" headerText="Uploaded Files"
editable="false">
<mx:itemRenderer>
<mx:Component>
<mx:VBox>
<mx:Script>
<![CDATA[
[Bindable]public var arrFiles:ArrayCollection = new ArrayCollection();
]]>
</mx:Script>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>
Is this possible?
Thank you in advance for any assistance,
Orville
I would create a custom MXML Box component as the rendered with a label (myLabel) as a child. Set the data provider for the DataGrid to the array. In the custom MXML component override the set data method which is called each time the data is rendered for each row and set the label to the current value passed in:
override public function set data(value:Object):void{
myLabel.text = value.myTextForLabel;
}
If the field in the ArrayCollection (myArrayCollection) is always the same for the label, then just set the DataGrid data provider to the ArrayCollection and the dataField property of the column to the appropriate value (myText):
<mx:DataGrid editable="true" dataProvider="myArrayCollection">
<mx:columns>
<mx:DataGridColumn id="dgcUpload" width="130" dataField="myText" headerText="Uploaded Files"
editable="false">
</mx:columns>
</mx:DataGrid>
It is possible depending on how you want to access it. You can access the property of a specific item being rendered by the itemRenderer by calling the itemToItemRenderer function on the datagrid. That gives you an instance of that specific itemRenderer and you can call the arrFiles variable for that item.
Here's an example
protected function datagrid1_clickHandler(event:MouseEvent):void
{
var obj:Object = dgcUpload.itemToItemRenderer(dgcUpload.selectedItem);
var newArray:ArrayCollection = obj.arrFiles;
}
I call that when something is clicked on the DataGrid and I want to access the arrFiles variable for the selected item.
Is that what you're looking for?
=Ryan

Is it possible to store an array in a DataGridColumn in Flex?

I have a datagrid column with a button that opens a modal dialog box allowing the user to upload multiple files. In the code below, the browseAndUpload() method does that. When the user finished uploading files and closes the upload box the closeUpload() method is called. I know for a fact that the uploaded files are being copied into arrFiles.
The problem I am having is that the repeater will not show the files in arrFiles. Here is the code:
<mx:DataGridColumn id="dgcUpload" width="42" headerText="Uploaded Files"
editable="false">
<mx:itemRenderer>
<mx:Component>
<mx:VBox>
<mx:Script>
<![CDATA[
[Bindable]public var arrFiles:ArrayCollection = new ArrayCollection();
public var fileUpload:FileUpload = new FileUpload();
private function browseAndUpload(event:MouseEvent):void
{
fileUpload = FileUpload(PopUpManager.createPopUp(this, FileUpload, true));
fileUpload.addEventListener(CloseEvent.CLOSE, closeUpload);
fileUpload["btnClose"].addEventListener("click", closeUpload);
}
private function closeUpload(event:Event):void
{
arrFiles = fileUpload.arrFiles;
}
]]>
</mx:Script>
<mx:HBox paddingLeft="3" paddingRight="3">
<mx:Button width="36" label="..." click="browseAndUpload(event)"/>
</mx:HBox>
<mx:Repeater id="rpFiles" dataProvider="{arrFiles}">
<mx:Label text="{FileVO(rpFiles.currentItem).name}"/>
</mx:Repeater>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Thank you in advance for any insight,
Orville
Got it! I made the following changes:
private function closeUpload(event:Event):void
{
arrFiles = fileUpload.arrFiles;
rpFiles.dataProvider = arrFiles;
}
<mx:Repeater id="rpFiles">
<mx:Label text="{FileVO(rpFiles.currentItem).name}"/>
</mx:Repeater>
You are assigning fileUpload.arrFiles directly to arrFiles. Is the former an Array or ArrayCollection? You might need to do arrFiles = new ArrayCollection(fileUpload.arrFiles);
That being said, I hate flex binding and generally avoid it because it can be unreliable. In your case, I'd write my own AS3 component that implements the ItemRenderer and then assign the repeater's dataprovider manually when it changes. You will have more control over the behavior if you do it that way. And a much easier time debugging.

Resources