Is there a way to make sure the selected item is visible in the Spark DataGrid?
.
Context
I have a data grid bound to an array collection. I receive remotely a service that gives me a ID (string) of an object that is in the collection. Using just the string I loop through the collection to find the item that matches the string. I find the object by it's ID. Now I have the object I want to select in the datagrid. I can set the
dataGrid.selectedItem = object;
Now I need to make sure it's visible. I do not have the row or column index.
.
Update
Using the answer below I've complimented it with this function:
/**
* Ensures the item is visible (for spark data grid)
**/
public function ensureItemIsVisibleInSparkDataGrid(datagrid:spark.components.DataGrid, item:Object):void {
var list:IList = datagrid.dataProvider;
var length:int = list.length;
var itemFound:Boolean;
var object:Object;
var index:int;
for (var i:int;i<length;i++) {
object = list.getItemAt(i);
if (object==item) {
itemFound = true;
index = i;
break;
}
}
if (itemFound) {
datagrid.ensureCellIsVisible(index);
}
}
Yes, it's called ensureCellIsVisible(). You need to know that row and column of the item in question. To get this to work you'd need to listen for the selectionChange event then calculate the row and column of the currently selected item.
Related
I have a datagrid control in my mxml file:
Now in my AS file, in the result function when obtaining data from DB, I can create columns dynamically. Let's say I create 1 column (client name):
private function GetDebtors_Result(event:ResultEvent):void
{
var arrayCol:Array = new Array();
var xmlSrc:XML = new XML("<main></main>");
var xmlTmp:XML;
var colClientname:DataGridColumn;
//Build an XML from DB data received (could as well use "event.result" directly to act as dataprovider for the datagrid, but I needed to break it down here)
for each(var o:Object in event.result)
{
xmlTmp = <row>
<CLIENTNAME>{o.CLIENTNAME}</CLIENTNAME>
</row>;
xmlSrc.appendChild(xmlTmp);
}
//Create the column CLIENTNAME
colClientname = new DataGridColumn("CLIENTNAME");
colClientname.headerText = "Client Name";
//Add the newly created column in the "Column" array.
arrayCol.push(colClientname);
//Use the "Column" array to set the columns of the datagrid.
dgSearch.columns = arrayCol;
//Populate the datagrid with the XML data.
dgSearch.dataProvider = xmlSrc.row;
}
This works well.
Now comes the issue: I need to add a second column which will contain checkboxes. They will be selected or deselected depending on the data from database. I'll show how I've done it by updating the same "GetDebtors_Result" function as above (added lines are commented as "// ADDED"):
private function GetDebtors_Result(event:ResultEvent):void
{
var arrayCol:Array = new Array();
var xmlSrc:XML = new XML("<main></main>");
var xmlTmp:XML;
var colClientname:DataGridColumn;
var colSel:DataGridColumn; // **ADDED**
//Build an XML from DB data received (could as well use "event.result" directly to act as dataprovider for the datagrid, but I needed to break it down here)
for each(var o:Object in event.result)
{
xmlTmp = <row>
<CLIENTNAME>{o.CLIENTNAME}</CLIENTNAME>
<SELECTED>{(o.SELECTED == 1)?true:false}</SELECTED> //**ADDED**
</row>;
xmlSrc.appendChild(xmlTmp);
}
//Create the column CLIENTNAME
colClientname = new DataGridColumn("CLIENTNAME");
colClientname.headerText = "Client Name";
//Create the column SELECTED
colSel = new DataGridColumn("SELECTED"); // **ADDED**
colSel.headerText = ""; // **ADDED**
colSel.itemRenderer = new ClassFactory(mx.controls.CheckBox); // **ADDED**
colSel.dataField = "SELECTED"; // **ADDED**
//Add the newly created column in the "Column" array.
arrayCol.push(colClientname);
//Add the "selection" column in the "Column" array.
arrayCol.push(colSel); // **ADDED**
//Use the "Column" array to set the columns of the datagrid.
dgSearch.columns = arrayCol;
//Populate the datagrid with the XML data.
dgSearch.dataProvider = xmlSrc.row;
}
Problem #1: The checkbox column appears, I can check and uncheck the checkboxes, but they are not checked/unchecked respective to DB data when loaded.
Problem #2: How do I associate a function to the checkboxes, for instance one which will update the XML so that I can save the new data to the DB?
Anybody got the solution? Thank you in advance.
Seems to be a very old question that I saw today.
Hopefully you would have found out the solution by now, just in-case if anyone has same problem:
While adding a checkbox to column- just instantiate it 1st:
var chkTempCheck: Checkbox = new CheckBox();
Then set all the properties required:
chkTempCheck.selected = o.dBColumnToDecideCheckUnCheck
here 'o' is the Object you are using from event.result.
This will work for sure!
The initial scenario was: all columns were defined in the mxml file. The checkbox column used itemrenderer and was working properly. I was using the same datagrid in 3 different cases - only thing was that some columns were set visible/invisible depending on the 'views'. The problem was when shifting 'views' and populate the grid and shift 'views' again, the column widths kept increasing exponentially. I excluded the checkbox column and everything worked fine; columns widths were ok. I included the checkbox column back and tried setting the column widths in AS file and the column-increasing-exponentially problem was fixed but the column widths were never the same when populating grid in view A and when populating grid in view B. ...So I ventured out in trying to set the columns in AS file just after obtaining DB data. Hope you can find yourself in those situations. Thanks for helping.
I have an ArrayCollection filled with 'o' objects. This AC should be the dataProvider of a DataGrid. After setting the dp: dgMT.dataProvider=acDataGrid the DataGrid contains only the last item of the arrayCollection.
Code:
[Bindable]
public var acDataGrid:ArrayCollection = new ArrayCollection();
protected function ddlLanguage_changeHandler(event:IndexChangeEvent):void{
gcTranslate.headerText=Globals.acLanguages.getItemAt(ddlLanguage.selectedIndex,0).toString();
Globals.acActValues=convertXmlToArrayCollection(File.applicationDirectory.resolvePath("xmls"+File.separator+Globals.acFileNames.getItemAt(ddlLanguage.selectedIndex,0)));
Globals.acDataGrid.removeAll();
var o:DataGridObject = new DataGridObject();
var i:int=0;
var angol:Object;
for each(angol in Globals.acValues){
o.en=angol.value;
o.name=angol.name;
if(i<Globals.acActValues.length && o.name==Globals.acActValues.getItemAt(i,0).name){
o.translation=Globals.acActValues.getItemAt(i,0).value;
}
else{
o.translation="";
Globals.acActValues.addItemAt("",i);
}
acDataGrid.addItemAt(o,i);
trace("NAME: "+acDataGrid.getItemAt(i,0).name+" VAL:"+acDataGrid.getItemAt(i,0).en+"TRANS: "+acDataGrid.getItemAt(i,0).translation);
// the values are different!
i++;
}
dgMT.dataProvider=acDataGrid;//setting the dataProvider
}
How could I reach that the DataGrid's rows are filled with the correct values?
Thank you!
You're instantiating o just once, outside of the for loop. Which means your just changing the values of that instance's properties and adding that same instance to the dataprovider over and over. You should instead create a new instance on every iteration.
To fix this, simply move the instantiation of o inside the for loop:
for each(angol in Globals.acValues){
var o:DataGridObject = new DataGridObject();
...
}
I have created one dojo datagrid. Every column has a formatter attached to it. When grid is generated the formatter is called. Now I want it so that if a user selects any row the formatter will be called and some strings should be attached to the selected row's column element.
Like grid is like this :
COLUMN
-------
a
b
c
and now user selects the 2nd row, the grid should change to :
COLUMN
-------
a
b SELECTED
c
Currently I implemented it like this :
if(this.grid.selection.selectedIndex !== -1){
retrun value + "SELECTED";
}else{
return value;
}
Can you please suggest a some good way of doing this? Please note that "SELECTED" string should not be added to the grid store.
The formatted is not hooked into clicking / selection of rows. It is solely performed when the contents (value) of a cell is set. Instead you'd want to move focus over to onRowClicked - an event on the grid component. It works like this:
grid.onRowClick = onRowClickHandler;
I wouldnt know which of following samples would put you closest to your goal but onRowClickHandler could be setup as such:
function onRowClickHandler(evt) {
var rows = this.selection.getSelected();
// perform cell rendering here
dojo.forEach(rows, function(row) {
// this row is an item though.. you will have row._O as its index
});
}
OR
function onRowClickHandler(e) {
var cellClicked = this.focus.cell
cellClicked.formatter();
}
However you may find that there are not much references to the viewable data anywhere in the grid component.. You could use following query selectors to find cell data and update the viewed html by calling formatter on each value. You would need to capture a previous selection for 'teardown' of your custom setting of values though.
var prevSelectedRows = [];
function onRowClickHandler(evt) {
var idx = this.selection.selectedIndex,
rawRow = dojo.query(".dojoxGridRow:nth-child("+(idx+1)+")", this.domNode)[0],
self = this;
// perform resetting of viewable values
dojo.forEach(prevSelectedRows, function(raw) {
dojo.query('.dojoxGridCell', raw).forEach(function(cellDOM, i) {
cellDOM.innerHTML = cellDOM.innerHTML.replace("SELECTED", "");
});
});
prevSelectedRows = []; // reset prev selection
// look into grid.view.content for methods on this
// perform setting of viewable values (SELECTED)
dojo.query('.dojoxGridCell', rawRow).forEach(function(cellDOM, i) {
// this function might be of interest, lets see how it looks in console
console.log(self.layout.cells[i].formatter);
cellDOM.innerHTML = cellDOM.innerHTML + "SELECTED"
});
prevSelectedRows.push(rawRow);
}
So this is driving me crazy. I've got an advanced data grid with a dataprovider that's an array collection w/ hierarchical data. Each object (including the children) has an id field. I'm trying to drag and drop data from within the ADG. When this happens, I need to grab the id off the drop target and change the dragged object's parentid field. Here's what I've got:
public function topAccountsGrid_dragDropHandler(event:DragEvent):void{
//In this function, you need to make the move, update the field in salesforce, and refresh the salesforce data...
if(checkActivateAccountManageMode.selected == true) {
var dragObj:Array = event.dragSource.dataForFormat("treeDataGridItems") as Array;
var newParentId:String = event.currentTarget['Id'];
dragObj[0].ParentId = newParentId;
} else {
return;
}
app.wrapper.save(dragObj[0],
new mx.rpc.Responder(
function():void {
refreshData();
},
function():void{_status = "apex error!";}
)
);
}
I can access the data I'm draggin (hence changing parentId) but not the currentTarget. I think the hierarchical data is part of the problem, but I can't find much in the documentation? Any thoughts?
event.currentTarget is not a node, it's the ADG itself. However, it's quite easy to get the information you want, since the ADG stores that data internally (as mx_internal).
I'm using the following code snippets (tested with Flex SDK 4.1) in a dragOver handler, but I guess it will work in a dragDrop handler too.
protected function myGrid_dragDropHandler(event:DragEvent):void
{
// Get the dragged items. This could either be an Array, a Vector or NULL.
var draggedItems:Object = getDraggedItems(event.dragSource);
if (!draggedItems)
return;
// That's our ADG where the event handler is registered.
var dropTarget:AdvancedDataGrid = AdvancedDataGrid(event.currentTarget);
// Get the internal information about the dropTarget from the ADG.
var dropData:Object = mx_internal::dropTarget._dropData;
// In case the dataProvider is hierarchical, get the internal hierarchicalData aka rootModel.
var hierarchicalData:IHierarchicalData = dropTarget.mx_internal::_rootModel;
var targetParent:Object = null;
// If it's a hierarchical data structure and the dropData could be retrieved
// then get the parent node to which the draggedItems are going to be added.
if (hierarchicalData && dropData)
targetParent = dropData.parent;
for each (var draggedItem:Object in draggedItems)
{
// do something with the draggedItem
}
}
protected function getDraggedItems(dragSource:DragSource):Object
{
if (dragSource.hasFormat("treeDataGridItems"))
return dragSource.dataForFormat("treeDataGridItems") as Array;
if (dragSource.hasFormat("items"))
return dragSource.dataForFormat("items") as Array;
if (dragSource.hasFormat("itemsByIndex"))
return dragSource.dataForFormat("itemsByIndex") as Vector.<Object>;
return null;
}
var dropData:Object = mx_internal::dropTarget._dropData;
should be
var dropData:Object = dropTarget.mx_internal::_dropData;
Try this.
I've gotten a checkbox header renderer to work well with flat DPs, but a
hierarchical collection view is another story. On click, I want it to select all
checkboxes in a given column. Here is my code:
var dp:HierarchicalCollectionView = _dataGrid.dataProvider as
HierarchicalCollectionView;
var testDp:GroupingCollection = dp.source as GroupingCollection;
var rawDp:ArrayCollection = testDp.source as ArrayCollection;
for(var i:int=0 ; i < rawDp.length ; i++){
rawDp[i][_dataField] = cb.selected;
}
It selects all checkboxes on the 2nd level of data, but doesn't select the top
level of data. What am I missing here? I can't seem to find it.
Any tips are greatly appreciated. Thank you.
For hierarchical data you have to use a cursor which iterates over all levels of the hierarchical data.
var dp:IHierarchicalCollectionView = _dataGrid.hierarchicalCollectionView;
var cursor:IViewCursor= dp.createCursor();
while (!cursor.afterLast)
{
cursor.current[_dataField] = cb.selected;
cursor.moveNext();
}
Howerver, this works only with nodes that have previously been opened. So either expand all nodes with _dataGrid.expandAll() (you can collapse them afterwards since the nodes only have to be opened once) or iterate your hierarchical data manually:
function setCheckBoxValue(children:ArrayCollection, value:Boolean):void
{
for each (var child:Object in children)
{
if (child.hasOwnProperty("children") && child["children"])
setCheckBoxValue(child["children"], value);
child[_dataField] = value;
}
}
var myDataProvider:HierarchicalData = /* your data provider */;
// Call it like this...
setCheckBoxValue(myDataProvider.source, cb.selected);
Update: To answer your second question...
Create a new CheckBoxColumn which extends AdvancedDataGridColumn. You can use it to preconfigure your headerRenderer and itemRenderer.
In your custom item renderer you get hold of your column like this:grid = AdvancedDataGrid(listData.owner);
column = grid.columns[listData.columnIndex] as CheckBoxColumn;
Do the same in your header renderer.
Whenever the CheckBox value in one of your item renderers changes dispatch a event through your column. Something like: column.dispatchEvent(new Event("checkBoxValueChanged"));
Your header render should add an event listener to the column for the "checkBoxValueChanged" event (or whatever you call it). Whenever that event is fired loop through your data provider and update the headers CheckBox accordingly.
In theory that should work. HTH