validation in flex datagrid using itemEditor - apache-flex

I have a datagrid which conatains two columns. Datatype and value. Datatype has a combobox with options like char, int, unsigned int, signed int etc.Now i want to have validation on what value is entered in value column. I am using following method .
<mx:DataGridColumn headerText="Value"
dataField="Values"
width="100"
editable="{!this.areVariablesReadOnly}">
<mx:itemEditor> <mx:Component> <mx:TextInput restrict="0-9" maxChars="3" /> </mx:Component> </mx:itemEditor>
</mx:DataGridColumn>
This validates value column's fields only for int values. Now if char is selected , i need to use different itemEditor to validate in a different way.
In short,
if (int)
use ItemEditor1
else if (char)
use ItemEditor2
else if (condition)
use Itemeditor3.
Can anybody point me in correct direction?

The data property (and also dataChange event) will make your life easier.
For example,
(assuming that your Datatype field is type)
In your MXML:
<mx:itemEditor>
<fx:Component>
<local:ValueInput type="{data.type}"/>
</fx:Component>
</mx:itemEditor>
ValueInput.as:
package
{
import mx.controls.TextInput;
public class ValueInput extends TextInput
{
public function set type(value:String):void
{
switch (value)
{
case "char":
restrict = null;
break;
case "int":
restrict = "0-9";
break;
case "hex":
restrict = "0-9A-F";
break;
}
}
}
}
However, I can't say this is the "correct direction". It is just one way of doing it. There can be many other creative ways, and it also depends on developer's coding style.
What you were trying to do was also a fine way. It just takes a bit longer to implement for MX components.
Hope this helps.

Related

How to pass column value to dataTipFunction in AdvancedDataGridColumn Flex

Flex Experts,
I am a newbie here. I am trying to create a conditional tool tip for my contact detail screen. If the contact has 'special-roles' like 'ABC, XYZ' then the tool tip should appear otherwise not. We have AdvancedDataGridColumn and using dataTipFunction to display the tool tip.
I am passing, values of roles & 'special-roles' in dataProvider for all contact objects.
I need to write tool-tip condition for every row(every contact). I am unable to write the condition in dataTipFunction as it has access to only 'item' object. I tried trace and Alert on 'item', but screen goes blank.
I have also tried "showDataTips" which accepts boolean but to no avail. I need a way to pass current row values (all columns) to a function from AdvancedDataGridColumn.
Here is the snapshot of my code. Any help is very much appreciated :)
<view:CopyPasteDataGrid id="contactsHolder"
width="100%"
height="100%"
displayDisclosureIcon="true"
variableRowHeight="true"
defaultLeafIcon="{null}"
folderClosedIcon="{null}"
folderOpenIcon="{null}"
useRollOver="true"
selectable="true"
styleName="PortfolioAdvanced"
designViewDataType="tree"
horizontalCenter="true"
verticalGridLines="false"
horizontalScrollPolicy="off"
dataProvider="{contactDetails}"
headerRelease="onHeaderRelease(event)">
<view:columns>
<mx:AdvancedDataGridColumn dataField="lastName"
sortCompareFunction="lastNameCompare"
headerText="{ApplicationConstants.LAST_NAME_HEADER}"
showDataTips="true" dataTipFunction="buildToolTipForContact"
width="100"/>
<view:rendererProviders>
<mx:AdvancedDataGridRendererProvider dataField="projectContacts"
renderer="com.ihg.hom.common.view.components.render.ContactsRenderer"
columnIndex="0"
columnSpan="0"/>
</view:rendererProviders>
</view:CopyPasteDataGrid>
private function buildToolTipForContact(item:Object):String
{
var myString:String="";
return "hello";
}
I have resolved it using different approach. I used label function. It has access to column object and based current object roles I am setting tool tip. Here is the code for reference.
<mx:AdvancedDataGridColumn dataField="role" sortable="{isRoleSortable}"
labelFunction="getRole"
headerText="Role" sortCompareFunction="sortRole" showDataTips="true" dataTipFunction="buildToolTipForContact"
width="120"/>
private var hasRole:Boolean=false;
private function getRole(item:Object):String
{
// extra code
if(currentRoles.indexOf(specialRole)!=-1)
{
hasRole=true;
}
}
private function buildToolTipForContact(item:Object):String
{
var myStr:String="";
if(hasRole){
myStr="Special Role";
}
return myStr;
}

Using a ComboBox as ItemEditor in Flex 4

I have a simple DataGrid with data. Of one of the columns, I want to use a ComboBox to edit the field, instead of the standard edit box.
How do I do that? I have tried all kind of things I found on the internet, but they all fail in simply updating the value. I'd say it shouldn't be too hard to do this.
I'm actually in the process of doing this myself, and with the spark:DataGrid it actually gets a bit easier than halo - but both follow the same setup / architecture.
Start with:
spark.components.gridClasses.ComboBoxGridItemEditor;
Depending on the nature of your data setup and/or how prolific this kind of editing will be for your application, you can write it inline as most documentation will suggest within a <fx:component>, or simply subclass this (although behind the scenes these are the same thing - the later being much easier to reuse). The data for the combo in my scenario is a sub selection of a bigger parent object, so I chose to make it easier on myself and add an additional property dataField to mimic other renderer / editors - in what actually shows in just the cell itself (when not in editing mode).
A basic setup looks something more or less like this (at least mine does):
public class AccountComboEditor extends ComboBoxGridItemEditor
{
private _dataField:String;
public function AccountComboEditor()
{
super();
//note - typically you wouldn't do "logic" in the view but it's simplified as an example
addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
}
public function get dataField():String { return _dataField; }
public function set dataField(value:String):void
{
if (_dataField !=value) //dosomeadditionalvalidation();
_dataField = value;
}
override public function prepare():void
{
super.prepare();
if (data && dataField && comboBox) comboBox.labelField = data[dataField];
}
protected function onCreationComplete(event:FlexEvent):void
{
//now setup the dataProvider to your combo box -
//as a simple example mine comse out of a model
dataProvider = model.getCollection();
//this isn't done yet though - now you need a listener on the combo to know
//what item was selected, and then get that data_item (label) back onto this
//editor so it has something to show when the combo itself isn't in
//editor mode
}
}
So the real take away is to setup the labelField of the combobox, either internally in the subclass or externally if you need to expose it as an additional property.
The next part is to use this as part of the mx.core.ClassFactory for the actual data grid. A simple view would look like something similar:
<s:DataGrid>
<fx:Script>
private function getMyEditor(dataField:String):ClassFactory
{
var cf:ClassFactory = new ClassFactory(AccountComboEditor);
cf.properties = {dataField : dataField };
return cf;
}
</fx:Script>
<s:columns>
<mx:ArrayList>
<s:GridColumn itemEditor="{getMyEditor('some_data_property')}" />
</mx:ArrayList>
</s:columns>
</s:DataGrid>
This Creating item renderers... doc will give you more info.
I figured it out. I just wanted a simple drop down box, instead of a text-editing field.
The following code does want I want:
<mx:DataGridColumn dataField="type" headerText="Type" editorDataField="value">
<mx:itemEditor>
<fx:Component>
<mx:ComboBox>
<mx:dataProvider>
<fx:String>Gauge</fx:String>
<fx:String>Graph</fx:String>
<fx:String>Indicator</fx:String>
</mx:dataProvider>
</mx:ComboBox>
</fx:Component>
</mx:itemEditor>
</mx:DataGridColumn>

How to do an if-else on a Flex component, based on the value of an object's member?

When I click a row in the datagrid, the "PeopleDetails" state is loaded. On the details state, I have a checkbox. This checkbox was automatically generated when I created the form. This is because the field in the People table is Boolean.
I actually do not want to have a checkbox, but I want the value Yes/No printed next to the label.
So I write some AS code embedded in the MXML code:
<s:Form includeIn="PeopleDetails">
<s:FormItem label="Is Present?">
<fx:Script>
<![CDATA[
if(person!= null ){
if(person.present==true){
Alert.show("Test - Yes");
}
}
else{
Alert.show("No");
}
]]>
</fx:Script>
<s:CheckBox id="personCheckBox2" enabled="false" selected="{person.present}"/>
</s:FormItem>
</s:Form>
Just for testing purposes, I have Alert popups. Eventually, I would change to printing to screen the values Yes/No.
The problem:
-I do not know how to test whether the attribute present in the object person is true or false.
In the above, I get a FB complaint 1120: Access of Undefined property person.
If I remove the AS code, the checkbox works fine. The checkbox uses person.present to know whether it should be checked or not. Why cannot I use person.present to do the if-else test?
I would appreciate any help on this.
If I'm reading you right, you want a Yes/No value rather than a checkbox, this should do it for you:
Change :
<s:CheckBox id="personCheckBox2" enabled="false" selected="{person.present}"/>
To :
<s:Label text="{(person.present)?'Yes':'No'}"/>
So the new form looks like this :
<s:Form includeIn="PeopleDetails">
<s:FormItem label="Is Present?">
<s:Label text="{(person.present)?'Yes':'No'}"/>
</s:FormItem>
</s:Form>
You can't place ActionScript code on a script manner within Script tag. You can only place properties and methods there following OOP way. So put your code inside a method and call this method as a reaction on some event (creationComplete for example).
I hope the above code is part of an ItemRenderer.
Just move the above Script block code to set data() function as below:
override public function set data( value: Object ): void
{
super.data = value;
if(person != null ){
if(person.present==true){
Alert.show("Test - Yes");
}
}
else{
Alert.show("No");
}
}
Also, I don't think Alert will work in Itemrenderer, so replace it with trace("") statement. Hope it helped.

How do I dynamically populate the options in a combobox inside of a grid based on another row in Flex?

I'm trying to setup a DataGrid that contains a column of combo boxes. The values of the combo boxes are defined by data specific to that row. I cannot get this to work though, I'm asking for a solution to this, either fixing what I have below or a recommendation on a different way.
One of the columns of my DataGrid has an object derived from a ComboBox for an ItemEditor. The itemEditor is set like this:
<mx:DataGridColumn editorDataField="selectedItem" dataField="type" editable="true" >
<mx:itemEditor>
<mx:Component>
<FilterCell:SelectCellBase initialize="set_combo()" grid="{this}"/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
So that when the itemEditor is generated (when the user double clicks on the cell) the data is populated.
Then, the SelectCellBase set_combo() function is defined as such:
public function set_combo( ) : void
{
var type : String = grid.dataProvider[grid.selectedIndex]['type'];
if( 'text' == type )
{
this.dataProvider = text;
}
else
{
this.dataProvider = number;
}
}
This implementation isn't working though because when I try to call grid.selectedIndex this always seems to return -1.
What am I doing wrong, or what better way is there to do this?
Your problem is that when you're inside of an <mx:Component> the scope is local, and no longer set to the outside MXML file. So when you have:
<mx:Component>
<FilterCell:SelectCellBase initialize="set_combo()" grid="{this}"/>
</mx:Component>
the "this" you're referring to is the inline component you've defined, not the base MXML component you're working on. The easy fix is to change it to
<mx:Component>
<FilterCell:SelectCellBase initialize="set_combo()" grid="{outerDocument}"/>
</mx:Component>
the outerDocument variable is automatically set when you're inside of an <mx:Component> tag, and can be used to access anything needed from the parent scope.

Flex DataGrid with ComboBox itemRenderer

I'm going spare trying to figure out the "correct" way to embed a ComboBox inside a Flex (3.4) DataGrid. By Rights (e.g. according to this page http://blog.flexmonkeypatches.com/2008/02/18/simple-datagrid-combobox-as-item-editor-example/) it should be easy, but I can't for the life of me make this work.
The difference I have to the example linked above is that my display value (what the user sees) is different to the id value I want to select on and store in my data provider.
So what I have is:
<mx:DataGridColumn headerText="Type" width="200" dataField="TransactionTypeID" editorDataField="value" textAlign="center" editable="true" rendererIsEditor="true">
<mx:itemRenderer>
<mx:Component>
<mx:ComboBox dataProvider="{parentDocument.transactionTypesData}"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Where transactionTypesData has both 'data' and 'label' fields (as per what the ComboBox - why on earth it doesn't provide both a labelField and idField I'll never know).
Anyway, the above MXML code doesn't work in two ways:
The combo box does not show up with any selected item.
After selecting an item, it does not store back that selected item to the datastore.
So, has anyone got a similar situation working?
While Jeff's answer is a partial answer for one approach for this (see http://flex.gunua.com/?p=119 for a complete example of this being used to good effect), it isn't as general as I wanted.
Thankfully, I finally found some great help on Experts Exchange (the answers by hobbit72) describes how to create a custom component that works in a grid as a ItemRenderer.
I've extended that code to also support using the combo box as an ItemEditor as well. The full component is as follows:
<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox
xmlns:mx="http://www.adobe.com/2006/mxml"
dataChange="setSelected()"
change="onSelectionChange(event)"
focusEnabled="true">
<mx:Script>
<![CDATA[
import mx.events.DataGridEvent;
import mx.events.ListEvent;
import mx.controls.dataGridClasses.DataGridListData;
private var _ownerData:Object;
private var _lookupField:String = "value";
// When using this component as an itemEditor rather than an itemRenderer
// then set ' editorDataField="selectedItemKey"' on the column to
// ensure that changes to the ComboBox are propogated.
[Bindable] public var selectedItemKey:Object;
public function set lookupField (value:String) : void {
if(value) {
_lookupField = value;
setSelected();
}
}
override public function set data (value:Object) : void {
if(value) {
_ownerData = value;
setSelected();
}
}
override public function get data() : Object {
return _ownerData;
}
private function setSelected() : void {
if (dataProvider && _ownerData) {
var col:DataGridListData = DataGridListData(listData);
for each (var dp:Object in dataProvider) {
if (dp[_lookupField] == _ownerData[col.dataField]) {
selectedItem = dp;
selectedItemKey = _ownerData[col.dataField];
return;
}
}
}
selectedItem = null;
}
private function onSelectionChange (e:ListEvent) : void {
if (selectedItem && _ownerData) {
var col:DataGridListData = DataGridListData(listData);
_ownerData[col.dataField] = selectedItem[_lookupField];
selectedItemKey = selectedItem[_lookupField];
}
}
]]>
</mx:Script>
</mx:ComboBox>
Using this component is straight forward. As an ItemRenderer:
<mx:DataGridColumn headerText="Child" dataField="PersonID" editable="false" textAlign="center">
<mx:itemRenderer>
<mx:Component>
<fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
Using this component is straight forward. And as an ItemEditor:
<mx:DataGridColumn labelFunction="lookupChildName" headerText="Child" dataField="PersonID" editable="true" editorDataField="selectedItemKey">
<mx:itemEditor>
<mx:Component>
<fx:GridComboBox dataProvider="{parentDocument.childrenData}" labelField="Name" lookupField="PersonID" change="dispatchEvent(new mx.events.DataGridEvent(mx.events.DataGridEvent.ITEM_FOCUS_OUT, true, true))"/>
</mx:Component>
</mx:itemEditor>
</mx:DataGridColumn>
Note that when using it as an ItemEditor, a custom labelFunction (that looks up the Name from the PersonID in my case) must be used, otherwise you only see the key in the grid when the field isn't being edited (not a problem if your keys/values are the same).
Note that in my case, I wanted the item focus out event to propogate up to provide immediate feedback to the user (my DataGrid has itemFocusOut="handleChange()"), hence the change event creating an ITEM_FOCUS_OUT event.
Note that there are probably simpler ways to have a ComboBox as an ItemEditor when you don't mind the ComboBox only shown when the user clicks on the cell to edit. The approach I wanted was a generic way to show a combo box in a DataGrid for all rows, and being editable and with decent event propogation.
The easiest way to add itemRenderers to DataGrids is to make a custom MXML component. In your case make a canvas, HBox, or VBox as the custom component and add the combobox as a child.Set the dataProvider on the dataGrid itself and assign the itemRenderer to the column, and then override the set data function of the itemRenderer to access all data from the given data provider for that instance as seen below:
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
override public function set data(value:Object):void{
trace(value.data);
trace(value.name);
}
]]>
</mx:Script>
<mx:ComboBox width="100%" height="100%" id="myComboBox"/>
</mx:HBox>
This method will be called for each instance of the itemRenderer
In my case I used a spark datagrid where one of the columns has an ItemRenderer that utilises a DropDownListBox. My problem was that when my item list change, the DropDownLists doesn't get updated with the new dataProvider. To solve this, I had to pass the dataProvider for the DropDownListBox as part of the data (of the ItemRenderer), and then by overriding the setter of the data to just assign the DropDownlListBox's dataProvider. Probably a bit of overhead, but if someone have a better solution, please let me know:
<s:GridItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
override public function set data(v : Object) : void {
super.data = v;
if (v == null)
return;
dropDown.dataProvider = data.dataProvider;
}
]]>
</fx:Script>
<s:DropDownList id="dropDown" width="100%" height="100%" dataProvider="{data.dataProvider}" labelField="name"/>

Resources