asdg>> technotes>> consolidate data providers

Version: Flash Player: v6.0.79.0, Flash Authoring: MX 2004
Date Added: June 4, 2004

Scenario:
A List component instance currently has a data provider that contains five items. The third item in the List is selected. A completely new set of items for the list is loaded externally. The new set must be displayed in the List component. The new set contains some new items and some items are already in the List's existing data provider. Furthermore, some of the items in the List's existing data provider are no longer part of the new item set. Importantly, the item currently selected in the List (the third item in the existing data provider) is also in the new item set.

Issue:
Completely replacing the existing data provider with the new set of loaded items successfully updates the List component, but the selection is lost. Recording the selection before installing the new set of items and then restoring the selection causes a flicker in the List component (when the selection is briefly lost and then restored).

Solution:
Compare the existing data provider with the new item set and consolidate the two as follows:

  • add items that are in the new item set but not in the existing data provider
  • retain items that are in both the new item set and the existing data provider
  • remove items from the existing data provider that are no longer in the new item set

By operating on the existing data provider directly instead of completely replacing it, we retain the List selection without screen flickering (assuming that the selected item is part of the new item set).

Implementation
The following function, consolidateProviders(), provides the services described under Solution, above.


  /**
   * Merges an existing data provider with a new data provider. At the end of
   * the operation, the existing data provider has all the items that appear 
   * _both_ in itself _and_ in the new data provider. Use this method to update
   * a List component's contents without losing the current selection.
   *
   * @param   newDP       The new data provider.
   * @param   currentDP   The data provider to be updated.
   * @param   field       The field to use when comparing items in the
   *                      data providers (usually "data" or "label").
   */
  function consolidateProviders (newDP:Array, currentDP:Array, field:String) {
    // Prevent error due to insufficient data or circular reference.
    if (newDP == null || currentDP == null 
        || field == null || newDP == currentDP) {
      return;
    }

    // Get a snapshot of the current data provider.
    var oldDP:Array = currentDP.slice(0);

    // Variables for consolidation loops.
    var itemExists:Boolean;
    var itemIsGone:Boolean;
    var i:Number;
    var j:Number;
    var k:Number;

    // Add any new items that aren't already in the old list.
    // (Use prefix decrement for speed...)
    for (i = newDP.length; --i >= 0;) {
      itemExists = false;
      for (j = oldDP.length; --j >= 0;) {
        if (newDP[i][field] === oldDP[j][field]) {
          itemExists = true;
          break;
        }
      }
      if (!itemExists) {
        currentDP.addItem(newDP[i]);
      }
    }

    // Now remove any old items that aren't in the new list.
    // (Use prefix decrement for speed...)
    for (i = oldDP.length; --i >= 0;) {
      itemIsGone = true;
      for (j = newDP.length; --j >= 0;) {
        if (newDP[j][field] === oldDP[i][field]) {
          itemIsGone = false;
          break;
        }
      }
      if (itemIsGone) {
        // Find and remove the item.
        for (k = currentDP.length; --k >= 0;) {
          if (currentDP[k][field] === oldDP[i][field]) {
            currentDP.removeItemAt(k);
          }
        }
      }
    }
  }

The following code shows the usage of the consolidateProviders() function:

// Create a new data provider.
var newProvider:Array = [{label:"four", data:4}, 
            {label:"two", data:2}, {label:"five", data:5}];

// Consolidate the new data provider with an existing one, using 
// the "data" field to compare items for "sameness".
consolidateProviders(newProvider, someList.dataProvider, "data");

>> Download the consolidateProviders() function and example