How to pass column value to dataTipFunction in AdvancedDataGridColumn Flex - apache-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;
}

Related

validation in flex datagrid using itemEditor

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.

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>

Adobe Flex: Error#1034 in trying to validate datagrid input

Trying to validate the input in my data grid, I am using a function (taken from an Adobe example).
This is how the grid goes:
<mx:DataGrid id="CashGrid" dataProvider="{cash}" editable="true" itemEditBeginning="allowForEdit(event)" itemEditEnd="formatData(event);" sortableColumns="false">
<mx:columns>
<mx:DataGridColumn textAlign="left" dataField="curName" headerText="Currency" />
<mx:DataGridColumn textAlign="right" dataField="value" headerText="Value" width="150">
</mx:columns>
</mx:DataGrid>
And here is the function from the AS part
public function formatData(event:DataGridEvent):void
{
if (event.reason == DataGridEventReason.CANCELLED)
{
// Do not update cell.
return;
}
var newData:String= TextInput(event.currentTarget.itemEditorInstance).text;
// Determine if the new value is an empty String.
if(newData == "")
{
event.preventDefault();
TextInput(cashGrid.itemEditorInstance).errorString=
"Enter a valid string.";
return;
}
}
Although it works in the source example, in my example, on editing said grid, an error pops up saying
TypeError: Error #1034: Type Coercion failed: cannot convert mx.controls::TextInput#f093c29 to spark.components.TextInput.
Trying to
import mx.controls.TextInput;
tells me
Can not resolve a multiname reference unambiguously. spark.components.TextInput.
I guess there is some confusion with the namespaces, but I have no idea how to make this work.
Help!
Thanks
I cannot reproduce the error with the given code. It's working fine on my end. Please send me the code for allowForEdit(event) as well.
Which SDK version are you using?
What is the root application namespace? Please paste the entire application namespace.

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.

Flex:: How do I prevent in drag and drop, dragging onto self

I have a Flex question. I was wondering, if I have two list boxes, and I want to drag and drop between both of them, how do I prevent the user from dragging onto the same list (thus duplicating the item? I cannot have a situation where that is the case. Thanks guys
Haven't tested it but I guess something like this should work:
Listen to dragStart event on both lists and set a source variable depending on event.target. Now listen to the dragDrop event on both lists and call event.preventDefault() if the source is same as the target.
Here are some simple functions I made while building a working application I used to wrap my head around flex drag and drop. I was looking for a way to have multiple lists with drag and drop functionality that would not interfere with each other. Also, I didn't want to deal with copying list data around.
private function onlyAllowMoveDragOverHandler(event:DragEvent):void {
event.preventDefault();
event.currentTarget.showDropFeedback(event);
DragManager.showFeedback(DragManager.MOVE);
}
private function allowDropOnlyIfInitiatorEqualsComponent(event:DragEvent, component:IUIComponent):void {
event.preventDefault();
if (event.dragInitiator == component) {
DragManager.acceptDragDrop(event.target as IUIComponent);
}
else {
DragManager.showFeedback(DragManager.NONE);
}
}
And I in use in my mxml:
<mx:List
x="10"
y="170"
id="availableLangsList"
dataProvider="{availableLangs}"
width="100"
height="200"
dragEnabled="true"
dragMoveEnabled="true"
dropEnabled="true"
dragOver="onlyAllowMoveDragOverHandler(event);"
dragEnter="allowDropOnlyIfInitiatorEqualsComponent(event, selectedLangsList);"
dragComplete="selectedLangs.refresh();"
/>
<mx:Label x="129" y="153" text="list 4"/>
<mx:List
x="129"
y="170"
id="selectedLangsList"
dataProvider="{selectedLangs}"
width="100"
height="200"
dragEnabled="true"
dragMoveEnabled="true"
dropEnabled="true"
dragOver="onlyAllowMoveDragOverHandler(event);"
dragEnter="allowDropOnlyIfInitiatorEqualsComponent(event, availableLangsList);"
dragComplete="availableLangs.refresh();"
/>
I found the solution, which im not sure would work for anyone else. I basically had in my two lists:
`
<mx:List id="srcList" dataProvider="{_source}"
allowMultipleSelection="true"
enabled="{enabled}"
labelField="{labelField}"
iconFunction="iconFunction"
dragEnabled="true"
dropEnabled="true"
dragDrop="doDragDrop(event);"
width="100%"
height="100%"
/>
</mx:VBox>
<mx:VBox paddingTop="50">
<mx:Button label="->" enabled="{enabled}" click="add()"/>
<mx:Button label="<-" enabled="{enabled}" click="rem()"/>
</mx:VBox>
<mx:VBox width="100%" height="100%">
<mx:Label text="{right_col_heading}" />
<mx:List id="dstList" dataProvider="{_destination}"
allowMultipleSelection="true"
enabled="{enabled}"
dragEnabled="true"
dropEnabled="true"
dragDrop="doDragDrop(event);"
width="100%"
height="100%"
labelField="{labelField}"
iconFunction="iconFunction"
verticalAlign="center"
/>`
I basically added a dragMoveEnabled = "true" to both lists and now basically not re-add to the same list an item of itself, but just move the order (which doesnt matter to me as its a soap send and the back-logic would put it in the correct order anyway).
In my case, I used a HashCollection (which extends ArrayCollection) [just google it, you'll find the component]. The dataprovider is bind to this has collection. You would add items to the collection with: dataprovider.put (key, object) instead of dataprovider.addItem(object).
The "hash" will ensure uniqueness in the collection. SO, even if the user drag-drop something that already exists in the hash, the original value would get replaced with the new object (but it wouldn't matter because it's the same value).
The "key", however, must be unique.... otherwise, the hash idea won't work.
Thanks Brice, Those functions were helpful.
For them to work in Spark Lists just update the first function as follows with createDropIndicator instead of showDropFeedback and stop passing the event.
private function onlyAllowMoveDragOverHandlerS(event:DragEvent):void {
event.preventDefault();
event.currentTarget.createDropIndicator();
DragManager.showFeedback(DragManager.MOVE);
}

Resources