3 Replies Latest reply on Jul 25, 2006 6:14 PM by jpwrunyan

    Problem copying items in a DataGrid

    jpwrunyan Level 1
      I have made a function to copy (completely -- no reference passing) items in my DataGrid's dataProvider. This is especially important because the grid is editable so I have to avoid copy references.
      I found the clone function in the AS docs and am using it. My items seem to clone fine. For example, if I copy/clone one item, then edit it, the original remains the same.

      However, the grid itself is acting VERY strange. I cannot select the rows of copies individually. If I roll over the original copy, or its clone, the grid highlights and will only select the whichever is last in the list. It is very difficult to describe this problem so I have attached a code snippet below.

      If anyone can shed light as to why DataGrid is behaving this way or a work-around I would be very grateful. I did not have this problem in Flex 1.5 and am at a complete loss.

      <?xml version="1.0" encoding="utf-8"?>
      <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="vertical">

      <mx:Script>
      <![CDATA[
      import mx.controls.DataGrid;
      import mx.collections.ArrayCollection;

      [Bindable]
      private var dummyData:Array = [{label:"blorch", data:1}, {label:"blorch2", data:2}, {label:"blorch3", data:3}];

      public static function clone(source:Object):* {
      var ba:ByteArray = new ByteArray();
      ba.writeObject(source);
      ba.position = 0;
      return ba.readObject();
      }

      public static function copyItems(source_dg:DataGrid, copy_array:Array):Array {
      if (!copy_array) {
      return null;
      }
      return copyDPItems(ArrayCollection(source_dg.dataProvider), copy_array);
      }

      public static function copyDPItems(source_dp:ArrayCollection, copy_array:Array):Array {
      if (!copy_array) {
      return null;
      }
      var result_array:Array = new Array();
      for (var i:int = copy_array.length; --i>=0; ) {
      source_dp.addItemAt(clone(source_dp.getItemAt(copy_array )), copy_array+1);
      result_array.push(copy_array +(i+1));
      }
      return result_array;
      }

      private function doCopy():void {
      var copyIndices:Array = dg.selectedIndices;
      var copiedIndices:Array = copyItems(dg, copyIndices);
      for (var i:uint = 0; i<copiedIndices.length; i++) {
      if (String(dg.dataProvider[copiedIndices
      ].label).slice(-2) != "_c") {
      dg.dataProvider[copiedIndices ].label+="_c";
      }
      }
      }
      ]]>
      </mx:Script>
      <mx:DataGrid id="dg" dataProvider="{dummyData}" editable="true">
      </mx:DataGrid>
      <mx:Button label="copy selected items" click="doCopy()" />
      </mx:Application>
        • 1. Problem copying items in a DataGrid
          dimival Level 1
          Your snippet is not working, it is throwing an error here:

          Error /catalogo/prueba.mxml:32
          Implicit coercion of a value of type Array to an unrelated type int.

          31: for (var i:int = copy_array.length; --i>=0; ) {
          32: source_dp.addItemAt(clone(source_dp.getItemAt(copy_array)), copy_array+1);
          33: result_array.push(copy_array+(i+1));

          In line 32 in the getItemAt() function you are passing an array instead of an integer, i think you meant:
          getItemAt( i ) or getItemAt(copy_array[ i ]). As a matter of fact you are passing the copy_array where an integer was expected 3 times in the function copyDPItems.
          Please tell me what you meant really in this function so i can test your snippet
          • 2. Problem copying items in a DataGrid
            jpwrunyan Level 1
            I just now noticed, but the forum changed my "[ i ]" into an italic. So you're right, it does need the "[ i ]". I will replace "i" with "n" and repost the code. Sorry I didn't catch that it did that when I posted.

            Ok, here is a working code snippet (no italics!):

            After a night's rest, I am starting to think this might be some kind of bug with ArrayCollection or DataGrid... is there a "hidden" row identifier that is getting copied by the indescrimenate clone function? I cannot think of any reason why it should behave this way. Still, I have to find some way to implement this functionality. Thanks for any time you spend looking at this code.

            <?xml version="1.0" encoding="utf-8"?>
            <mx:Application xmlns:mx=" http://www.adobe.com/2006/mxml" layout="vertical">

            <mx:Script>
            <![CDATA[
            import mx.controls.DataGrid;
            import mx.collections.ArrayCollection;

            [Bindable]
            private var dummyData:Array = [{label:"blorch", data:1}, {label:"blorch2", data:2}, {label:"blorch3", data:3}];

            public static function clone(source:Object):* {
            var ba:ByteArray = new ByteArray();
            ba.writeObject(source);
            ba.position = 0;
            return ba.readObject();
            }

            public static function copyItems(source_dg:DataGrid, copy_array:Array):Array {
            if (!copy_array) {
            return null;
            }
            return copyDPItems(ArrayCollection(source_dg.dataProvider), copy_array);
            }

            public static function copyDPItems(source_dp:ArrayCollection, copy_array:Array):Array {
            if (!copy_array) {
            return null;
            }
            var result_array:Array = new Array();
            for (var n:int = copy_array.length; --n>=0; ) {
            source_dp.addItemAt(clone(source_dp.getItemAt(copy_array[n])), copy_array[n]+1);
            result_array.push(copy_array[n]+(n+1));
            }
            return result_array;
            }

            private function doCopy():void {
            var copyIndices:Array = dg.selectedIndices;
            var copiedIndices:Array = copyItems(dg, copyIndices);
            for (var n:uint = 0; n<copiedIndices.length; n++) {
            if (String(dg.dataProvider[copiedIndices[n]].label).slice(-2) != "_c") {
            dg.dataProvider[copiedIndices[n]].label+="_c";
            }
            }
            }
            ]]>
            </mx:Script>
            <mx:DataGrid id="dg" dataProvider="{dummyData}" editable="true">
            </mx:DataGrid>
            <mx:Button label="copy selected items" click="doCopy()" />
            </mx:Application>
            • 3. Problem copying items in a DataGrid
              jpwrunyan Level 1
              Ok, I have found the culprit, if you replace the clone function above with this one it becomes obvious:
              public static function clone(source:Object):Object {
              /*
              var ba:ByteArray = new ByteArray();
              ba.writeObject(source);
              ba.position = 0;
              return ba.readObject();
              */
              var copy_obj:Object = new Object();
              var s:String = "";
              for (var p:String in source) {
              s+="copy "+p+": "+source[p]+"\n";
              copy_obj[p] = source[p];
              }
              Alert.show(s);
              return copy_obj;
              }

              There is a property called "mx_internal_uid" that is getting copied along with everything else. This is what is making DataGrid treat the cloned data as if it were the same. Not exactly sure what the logical reasoning is behind this but anyway, I made a minor modification (albeit "hacky" one) and got things working:

              public static function copyDPItems(source_dp:ArrayCollection, copy_array:Array):Array {
              if (!copy_array) {
              return null;
              }
              var result_array:Array = new Array();
              for (var n:int = copy_array.length; --n>=0; ) {
              var copy_obj:Object = clone(source_dp.getItemAt(copy_array[n]));
              copy_obj.mx_internal_uid = UIDUtil.createUID();
              source_dp.addItemAt(copy_obj, copy_array[n]+1);
              result_array.push(copy_array[n]+(n+1));
              }
              return result_array;
              }

              Consequently, the warning about uid is in the docs at:
              Flex 2 Developer's Guide > Building User Interfaces for Flex Applications > Using Data Providers and Collections > About data providers and collections