Wednesday, July 27, 2011

Spark Data Grid Tab Focus Control

After spending so many months customizing the AdvancedDataGrid, I'm now interested to see if I can migrate many of those customizations to the Spark DataGrid. One of my first challenges is to see if I can improve my focus control - specifically tab navigation.

To review, here is the use case I'm trying to achieve (BTW it works in spark, and only partially works in ADG). My data is a product, and I have two occasionally editable fields related to this product: Quantity and Price (my role is a sales associate - so I can negotiate on prices). The product as a whole is only editable if it is in stock; I cannot change quantity or price if it is out of stock. Price is only editable if and handful of business rules apply (margin, vendor, etc). I want to be able to tab to the editable fields.

The problem with the ADG was that in it's "findNextEditableItemRenderer" loop, it only checked the data (ie, inStock). There was no way to tell what column it was looking at.

I was quite pleased with the spark DataGrid and its nice separation of concerns. I love that there is a separate DataGridEditor. And I was happy to discover that there was a simple PUBLIC method on DataGrid that I could tap into to do everything that I wanted (So far).

That public method is startItemEditorSession(rowIndex:int, columnIndex:int):Boolean. SWEET!

That problem is resolved in the spark dataGrid.
You can see the example here. In this example, the top grid is the regular one and the bottom grid is the modified one. I'm using the alpha property instead of enabled to prove that focus is indeed under my control (MUH HA HA HA - <evil laugh>).

The key is that within the startItemEditorSession, you
  • convert the rowindex to the data via the getItemAt on the dataprovider
  • convert the columnIndex to the column
  • validate the data as well as the data[column.datafield] properties
  • return the boolean if editing should happen.

    And here is the code

    public class FocusSparkDataGrid extends DataGrid 
     {
      private var _isDataEditableHelper:IIsDataEditable
      
      public function FocusSparkDataGrid()
      {
       super();
      }
      
    
      public function get isDataEditableHelper():IIsDataEditable
      {
       return _isDataEditableHelper;
      }
    
      public function set isDataEditableHelper(value:IIsDataEditable):void
      {
       _isDataEditableHelper = value;
      }
    
      override public function startItemEditorSession(rowIndex:int, columnIndex:int):Boolean
      {
       var dataIsEditable:Boolean = isDataEditable(rowIndex,columnIndex);
       if (dataIsEditable)
       {
        var editingStarted:Boolean = super.startItemEditorSession(rowIndex,columnIndex);
        return editingStarted
       }
       return false;
      }
    
      
      protected function isDataEditable(rowIndex:int, columnIndex:int):Boolean
      {
       if (isDataEditableHelper != null)
       {
        var dataItem:Object = dataProvider.getItemAt(rowIndex);
        var column:GridColumn = GridColumn(columns.getItemAt(columnIndex));
        var dataField:String = column.dataField;
        return isDataEditableHelper.isDataEditableForProperty(dataItem,dataField)
       }
       return false;
      }
    }
    
    

    public class IsProductVOEditable implements IIsDataEditable
     {
      public function IsProductVOEditable()
      {
      }
      
      public function isDataEditableForProperty(data:Object, property:String=""):Boolean
      {
       var vo:ProductVO = ProductVO(data);
       if (vo.inStock)
       {
        if (property == "price")
        {
         return vo.priceEditable;
        }
        return true;
       }
       return false;
      }
     }