Can i create multiple itemrenderer for a datagrid column in flex? - apache-flex

I actually wanted to create an itemrenderer which will contain below code :
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="0" height="0" >
<mx:Label text="{data.xval}" />
<mx:Spacer width="100%" />
<mx:Image source="edit.gif" width="16" toolTip="Edit" />
</mx:HBox>
Now when i click on the image datgrid column should be editable, for that i am using a textinput as an itemeditor. Now i also want to highlight all those cell for this datagrid column which are having data more than 8 characters. I am able to do this separately using 2 different itemrenderers. but i want to get this all together. Can anyone pls help me to do this? Can we have multiple itemrenderer for any datagrid column?
Please let me know if my question is not clear to you?
Thanking you in advance.

One way to do it is to create a function that returns the name of the style that you want to use for highlighting, and call that function by databinding to the style property of your HBox. For example, if you had one css class named highlight and one named normal, you could use this function:
public function highlight(data:String):String
{
if(data.length >= 8)
{
return "highlight";
}
return "normal";
}
And call it like this:
<mx:HBox styleName="{highlight(data.xval)}">
...
</mx:HBox>

Related

Flex 4 spark datagrid selected row change with tab

I'm trying to change the selected row in a spark data grid when tabbing passed the last column. In other words, I'd like to highlighted row to follow the active cell.
Any ideas?
Thank You.
Here's how i went about it.
I have my selectionChange and caretChange events on the grid doing the same function.
<s:DataGrid id="my_rates_grid" x="0" y="0" width="100%" height="100%"
creationComplete="my_rates_grid_creationCompleteHandler(event)"
editable="true" alternatingRowColors="[#FFFFFF, #e9f1f6]"
gridItemEditorSessionSave="my_rates_grid_gridItemEditorSessionSaveHandler(event)"
requestedRowCount="4"
selectionChange="my_rates_grid_selectionChangeHandler(event)"
caretChange="my_rates_grid_selectionChangeHandler(event)">
Then in that my_rates_grid_selectionChangeHandler function (note i had to change its param type to generic type Event)
protected function my_rates_grid_selectionChangeHandler(event:Event):void
{
if(my_rates_grid.editorRowIndex >= 0){
trace("it's happening");
my_rates_grid.setSelectedIndex(my_rates_grid.editorRowIndex);
}
}
so everytime i tabbed it would follow and the save feature captures my new values as well.

Repeater not working fine when passed a dataprovider (array) having a single element

I am using a Repeater in an Accordian which does not appear to see a single element in userArray. If I add another entry to userArray then the Repeater works fine.
Thoughts??
private function currUsersServiceHandler(event:ResultEvent):void{
if (event.result.currentUsers != null)
{
if (event.result.currentUsers.user is ArrayCollection) // if more than one elements are present
{
usersArray = event.result.currentUsers.user;
}
else if (event.result.currentUsers is ObjectProxy)
{ //FIXIT usersArray populate by following line has some issue
usersArray = new ArrayCollection(ArrayUtil.toArray(event.result.currentUsers));
}
}
}
<mx:HTTPService id="currUsersService" url="currUsers.xml" result="currUsersServiceHandler(event)"/>
<mx:Accordion includeIn="UserList" x="10" y="10" width="554" height="242" >
<mx:Repeater id="rep" dataProvider="{usersArray}">
<mx:Canvas width="100%" height="100%" label="{rep.currentItem.firstName}" >
<mx:HBox>
<s:Label text="{rep.currentItem.firstName}"/>
<s:Label text="{rep.currentItem.lastName}"/>
<mx:/HBox>
</mx:Canvas>
</mx:Repeater>
</mx:Accordian>
Edit:
There is another thing I have just noticed i.e. that the accordian does show a single tab (when Array has a single element) but it's not labeled with the first name which I am setting. If I enter another user, two tabs appear and both are labeled with names I am setting. The first tab appears labeled too then.
It makes no sense to me that this would not work with 1 item in the dataProvider, but would work with two.
That said, tThis approach strikes me as convoluted and I tend to stay away from using repeaters at all. I would suggest a different approach.
First create a component to display your data. You can reuse you're existing code. Conceptually something like this:
<mx:Canvas width="100%" height="100%" >
<mx:Script><[[
public var user : Object;
]]></mx:Script>
<mx:HBox>
<s:Label text="{user.firstName}"/>
<s:Label text="{user.lastName}"/>
<mx:/HBox>
</mx:Canvas>
Then in your original component create the new instance of the component in ActionScript:
for each(var myUserObject : Object in usersArray){
var newUserDisplayObject : UserDisplayObject = new UserDisplayObject();
newUserDisplayObject.user = myUserObject;
newUserDisplayObject.label = myUserObject.firstName
accordian.addChild(newUserDisplayObject);
}

Adding a child to a VBox component (FLEX)

First of all I wanted to thank in advance to everyone that reads this post.
I'm having a problem when adding a child to a VBox component. Is it not the same thing?:
List Item:
<mx:Script>
<![CDATA[
public function addChildren():void {
var f:FaqItem=new FaqItem();
f.id="newUsersAssistance";
this.cont.addChild(f);
}
]]>
</mx:Script>
<mx:VBox id="cont" width="100%" borderThickness="0" verticalGap="0"/>
and:
<mx:VBox id="cont" width="100%" borderThickness="0" verticalGap="0">
<view:FaqItem id="newUsersAssistance" />
</mx:VBox>
I am injecting two properties (question and answer) to the FaqItem component from an auxiliar file (using BabelFX) that depends on the id of the FaqItem, but it is only working when I choose the second option. If I use the first option, I get a child but with the text in question and answer fields is empty. I need to use the first option.
Is there anything I am doing wrong?
Thanks again for everything
Kind Regards
i don't think you will be able use the id property of the dynamically added component to do Injection. I suggest you keep some bindable variables to bind the value to the dynamic FaqItem.

Prevent displaying of some data in last row of Flex Datagrid

I have some DataGrid with editable rows, which has also an option to add new row 'dynamically'. I mean, last row has some default data (e.g. "CLICK HERE TO ADD NEW ROW") and when user clicks on it, he can edit that value and new row will be eventually inserted.
However, I also have a column in same DataGrid which doesn't come from DataGrid's DataProvider. That column is used to delete specific row and it should only display clickable image with associated mouse click action (within custom itemRenderer).
I would like to display that image on every row except that last one.
Here is my DataGridColumn code so far:
<mx:DataGridColumn width="20" editable="false">
<mx:itemRenderer>
<mx:Component>
<mx:VBox creationComplete="cc()">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
public function cc():void{
delImg.source = "assets/images/delete-icon.png";
}
]]>
</mx:Script>
<mx:Image id="delImg" smoothBitmapContent="true" width="15" height="15" click="outerDocument.confirmDelete(event)"/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
I suppose I should put some condition in my cc function and somehow compare current row's index or something with my dataProvider's length... I'm not really sure how to do that since I cannot get rowIndex property because I'm not working with DataGridEvent here...
Please help me with this one and thank you very much for any help! :)
A VBox does not implement IDropInListItemRenderer. A IDropInListItemRenderer gives you the "listData" property (which is of type "DataGridListData"). Furthermore, "listData.owner" will be the DataGrid object, and "listData.rowIndex" gives you the rowIndex property.

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