Uploaded image for project: 'Apache Flex'
  1. Apache Flex
  2. FLEX-19149

Data provider reference of ListBase inheriting component is reset during layout.

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Duplicate
    • Adobe Flex SDK 3.3 (Release)
    • None
    • None
    • Affected OS(s): All OS Platforms
      Language Found: English

    Description

      Application to reproduce:
      1. Create a new Application with the following MXML source: (the simple conditions are: Initially empty dataProvider collection, a List using it, and that list as a child of a FormItem or any other component that uses baselinePosition in the layout phase).

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

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

      [Bindable]
      public var collection:ArrayCollection = new ArrayCollection();

      private function addSomeItems():void

      { collection.addItem('item1'); collection.addItem('item2'); collection.addItem('item3'); collection.addItem('item4'); }

      private function resetDataProvider():void

      { list.dataProvider = collection; }

      ]]
      >
      </mx:Script>

      <mx:Form x="0" y="0" width="100%" height="100%">
      <mx:FormItem label="List" width="100%">
      <mx:List id="list" dataProvider="

      {collection}

      " width="100%"/>
      </mx:FormItem>
      <mx:FormItem label="Button" width="100%">
      <!-- Click this to add items to the collection already set as the dataProvider for the list. -->
      <mx:Button label="Add Items to Provider. Items should show, but do not." click="addSomeItems()" />
      <!-- Now click this to reset the reference - which we should not have to do. -->
      <mx:Button label="Re-set dataProvider reference correctly. Items will now show up." click="resetDataProvider()" />
      </mx:FormItem>
      </mx:Form>
      </mx:Application>

      2. Click the first button and note that no items are added to the List, even though items were added to the dataProvider collection with which it was initialized.
      3. Click the second button to set the dataProvider reference correctly again.

      Actual Results:
      Items within the dataProvider are not shown if the dataProvider is initially empty on layout.

      Expected Results:
      Reference to the same dataProvider is preserved and any added items are shown immediately by the nature of binding.

      Workaround (if any):
      The only workaround is to: Subclass the List component you want to lay out, and override the get baselinePosition getter to 1) Backup the dataProvider reference in a local var; 2) Get super.baselinePosition, then 3) restore the dataProvider reference and return the super's baselinePosition value.

      Cause and solution:

      The issue is not apparent in a simple example. The true issue is when a dataProvider starts out with 0 length and is later filled or has any items added (which any List should handle just fine with binding). Unfortunately, the getter for baselinePosition does not preserve the dataProvider object reference itself if it is empty, as can be seen here: (ListBase.getBaselinePosition:1085 in Flex 3.3)

      var isNull:Boolean = dataProvider == null;
      var isEmpty:Boolean = dataProvider != null && dataProvider.length == 0;
      if (isNull || isEmpty)

      { dataProvider = [ null ]; validateNow(); }

      It should be very clear what is wrong from these few lines. The dataProvider reference is destroyed if it is empty.

      If the dataProvider is empty, then it is reset to an array with a single null item. This is never undone, thus the original reference to the dataProvider is lost if it's set before the layout within a FormItem, and any items added to the initialized dataProvider will not be shown in the grid - because the dataProvider is not the same!

      I am not certain how get baselinePosition should operate without an item in the provider, but it should surely keep the reference to the old provider and set it back so as not to be destructive to the initialized value. It was very unexpected to see my dataProvider set in this manner, hopefully this can be fixed ASAP. Until then I will be overloading this method in my own DataGrid and saving/setting my dataProvider value on either side.

      Essentially the method get baselinePosition assumes that the only thing that's important about a dataProvider is what's in it, as it restores it to a new Array reference after it's done with its calculations. This is flat out wrong - the reference to the original dataProvider must be preserved.

      Attachments

        Activity

          People

            adobejira Adobe JIRA
            adobejira Adobe JIRA
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: