6 Replies Latest reply on Dec 29, 2011 2:11 PM by owencmcnamara

    Intercept value passed to item editor?

    owencmcnamara

      Hello! I'm trying to intercept the value that is taken from a DataGrid's GridColumn's itemRenderer and applied to the itemEditor, and vice-versa. I need to be able to format this value. However, my project is complex, so I may be focusing on the wrong idea in what I'm trying to accomplish. Please have a look and let me know if there's something else I could try.

       

      I have a Spark DataGrid component (with ID dg) that I am dynamically populating from XML. I create an ArrayCollection from some nodes, and a regular Array from sub-nodes that is added as a property of the ArrayCollection. That ArrayCollection is then used as the dataProvider for the DataGrid.

       

      Here is an example segment of a typical XML node and it's sub-nodes:

       

          <item name="physOrderTable" text="" type="notes">
              <cols>
                  <col id="0" text="Day/Time" />
                  <col id="1" text="Order Type" />
                  <col id="2" text="Physician's Orders" />
                  <col id="3" text="Physician's Signature" />
              </cols>
              <rows>
                  <row id="r0" name="" text="">
                      <col id="0"><![CDATA[Tues 15:24]]></col>
                      <col id="1"><![CDATA[General]]></col>
                      <col id="2"><![CDATA[BMP, CBC, Cardiac Enzymes, ABG, EKG STAT, NS@ 125 mL/hr, Blood Sugar AC & HS, 02 via NC to keep oxygen saturation above 97%]]></col>
                      <col id="3"><![CDATA[J. Nelms]]></col>
                  </row>
              </rows>
          </item>
      

       

      Here is the code that reads through the XML and utilizes it:

       

          protected function sparkDG_creationCompleteHandler(event:FlexEvent):void
          {
              trace("grid created");
              var colsList:XMLList = xml.cols.col;
              var rowsList:XMLList = xml.rows.row;
              colAL = new ArrayList();
              
              for(var i:Number = 0; i < colsList.length(); i++)
              {
                  var gc:GridColumn = new GridColumn();
                  gc.maxWidth = 500;
                  gc.resizable = false;
                  gc.headerText = String(colsList[i].@text);
                  gc.dataField = "col";
                  gc.labelFunction = labelFunc;
                  colAL.addItem(gc);
              }
              
              for each(var row:XML in XML(value).rows.children())
              {
                  var rowArr:Array = new Array();
                  
                  for each(var col:XML in row.children())
                  {
                      if(col == "")
                      {
                          rowArr[Number(col.@id)] = "_";
                      }else{
                          rowArr[Number(col.@id)] = col;
                      }
                  }
                  
                  colAC.addItem({
                      rowID: row.@id,
                      rowName: row.@name,
                      rowText: row.@text,
                      col: rowArr
                  });
              }
              
              dg.columns = colAL;
              dg.dataProvider = colAC;
          }//
      

       

      So I build the header for the DataGrid first, telling it to use the "col" dataField, which corresponds to the .col property of the colAC ArrayCollection. That .col property is the array of values for each cell of that row.

       

      Now this part of code is important, as it displays the relevant index of the .col array by using the .columnIndex:

       

          private function labelFunc(item:Object, column:GridColumn):String
          {
              var displayText:String;
              var valArr:Array = new Array();
              
              if(column.dataField == "col")
              {
                  valArr = item[column.dataField];
                  displayText = String(valArr[column.columnIndex]);
              }
              
              return displayText;
          }//
      

       

      This is the only method I've been able to use to achieve the desired result. This all works fine, if all I want to do is merely display information. But I need to be able to edit the values in each cell, and apply this back to the dataProvider, as I need to rebuild XML with the updated values later.

       

      I have tried everything I can possibly think of to be able to do this. I built my own itemRenderer, then my own itemEditor, then scrapped them because it felt like I was re-inventing the wheel. But was I? I tried reading through the code for the DataGrid, GridColumn, and related classes, but I couldn't find any reference to the itemEditor beyond it being an IFactory. I have no idea where or how it tells that IFactory to be a text input or whatever it is.

       

      Here is my issue:

       

      When I turn on the DataGrid's editing, and double-click a cell, it takes the entire array of the col dataField for that column's cell, converts that array to a string, and displays the entire string in the edit text box. If I cancel the editing, or save the editing, it sets the string to the .col property. Then the labelFunction tries reading that string as an array, and it crashes. I was able to get the typeof the col dataField and converting it to an array if it's a string, but I shouldn't have to.

       

      I need to have it display just the value of the cell for that particular row and column when the instance of the itemEditor is created. When that value is changed, I need it to apply back to that column's index in the .col array of the dataProvider. So, similarly to how it displays information in the labelFunction, I need to edit the information and send it back.

       

      I've seen lots of custom itemEditors and itemRenderers for GridColumns, but these are hard-coded in the MXML. My grid is almost entirely dynamically created, so that's unfortunately not an option for me, as I won't even know how many columns or rows there will be when the DataGrid is created. I tried using rendererIsEditor, but that only seems to be on the MXML instantiation of the GridColumn, as there's only rendererIsEditable in the ActionScript, and it doesn't seem to work (or I don't know how to use it as intended).

       

       

       

      If anyone knows of a way to accomplish this, even just something else I should look at, I would greatly appreciate it!

        • 1. Re: Intercept value passed to item editor?
          Zolotoj Level 3

          Lots of code to go thru ...

          Have you looked into

          override public function prepare():void

          {

          }

          on itemEditor?

          • 2. Re: Intercept value passed to item editor?
            owencmcnamara Level 1

            Thanks for your response! I had seen that function before, but as there was nothing in it, I couldn't figure out if it was useful. Going back, I looked at the comments. I also found this website about item editors: The Item Editing Process

             

            So, according to that, the data variable will contain the .col property of the dataProvider, right? I can trace data out as an object, but when trying to reference it as an array, it doesn't work.

             

            Also according to that website, data is applied to value before prepare() is called, at which point data becomes a string. Doing this test in prepare(), I find that value is already a string. I can do a split() on the string or whatever to set the value how I need it (I think), but my life would be a lot easier if I could reference the cell's data directly and set value based on that.

             

            <?xml version="1.0" encoding="utf-8"?>

            <s:GridItemEditor 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[

                        private var valueArr:Array;

                       

                        override public function prepare():void

                        {

                            trace("prepare called");

                            valueArr = new Array(value);

                            trace("\tdata["+0+"]: "+data[0]);

                            trace("\tdata["+columnIndex+"]: "+data[columnIndex]);

                            trace("\tvalue: "+value);

                            trace("\tvalueArr.length: "+valueArr.length);

                            value = String(valueArr[columnIndex]);

                        }//

                       

                        override public function discard():void

                        {

                            trace("discard called");

                            valueArr[columnIndex] = value;

                            value = valueArr;

                        }//

                    ]]>

                </fx:Script>

            </s:GridItemEditor>

             

            And once that's accomplished, I believe what I did for discard() there should work correctly. What do you think?

            • 3. Re: Intercept value passed to item editor?
              drkstr_1 Level 4

              Just capture the event and preventDefault() on it.

               

              I remember reading in the docs an example that covers this exact use case.

               

              Maybe this one?

               

              http://livedocs.adobe.com/flex/3/html/celleditor_8.html#202084

              • 4. Re: Intercept value passed to item editor?
                owencmcnamara Level 1

                @drkstr_1

                 

                I had come across that before, actually, and used it to keep a column from being edited. I'm not sure how I could use that in this case, as I can't access value or data from the event itself. I'm also still not sure which one is the one I should be paying attention to to capture that cell's specific array source.

                • 5. Re: Intercept value passed to item editor?
                  drkstr_1 Level 4

                  Maybe I do not understand the problem, but is the "Modifying data passed to or received from an item editor" example on that page not what you are looking for?

                  • 6. Re: Intercept value passed to item editor?
                    owencmcnamara Level 1

                    @drkstr_1

                     

                    That seems like a possible solution. Do I not need to worry about the data and value variables for the particular cell being edited? I'm not sure how else I'd be able to reference the array being used, unless I'm referencing it in the dataProvider using the captured event's columnIndex and rowIndex.

                     

                    Also, the example on that page is using the MX DataGrid, whereas I'm using the Spark DataGrid, as indicated in my original post. The functions used in the method you linked to don't exist for the Spark DataGrid, and I'm having difficulty finding equivalents.