addItems method

void addItems(
  1. List<T> newItems, {
  2. K? parentKey,
  3. bool prepend = true,
})

Adds multiple items.

When parentKey is provided, items are added as children of that parent. Throws ArgumentError if any key already exists or if parentKey is unknown.

Implementation

void addItems(List<T> newItems, {K? parentKey, bool prepend = true}) {
  if (newItems.isEmpty) return;

  TListItem<T, K>? parent;
  if (parentKey != null) {
    parent = _itemsMap[parentKey];
    if (parent == null) {
      throw ArgumentError.value(parentKey, 'parentKey', 'Provided parent key does not exist');
    }
  }
  final level = parent != null ? parent.level + 1 : 0;

  // Validate all keys up front so a duplicate-key throw mid-loop can't leave
  // _itemsMap partially mutated (atomicity guarantee).
  for (final item in newItems) {
    final key = itemKey(item);
    if (_itemsMap.containsKey(key)) {
      throw ArgumentError.value(key, 'key', 'Item already exists');
    }
  }

  final newElements = [
    for (final item in newItems) _registerRecursive(item, parentKey: parent?.key, level: level, prepend: prepend),
  ];

  // Keep the parent's childrenKeys in sync — without this, expansion/descendant
  // traversal never discovers the new items.
  if (parent != null) {
    final newKeys = newElements.map((e) => e.key).toList();
    final existing = parent.childrenKeys ?? const [];
    // Avoid spread-into-list — on web (DDC) spreads can produce JSArray<dynamic>.
    final merged = <K>[];
    if (prepend) {
      merged.addAll(newKeys);
      merged.addAll(existing);
    } else {
      merged.addAll(existing);
      merged.addAll(newKeys);
    }
    _itemsMap[parent.key] = itemFactory(parent.data, parentKey: parent.parentKey, childrenKeys: merged, level: parent.level);
    // Sync the updated parent back into _localPaginationItems and displayItems.
    _syncParentInLocalAndDisplay(parent.key);
  }

  final newDisplayItems = _spliceNewItems(parent, newElements, prepend);

  updateState(who: 'addItems', displayItems: newDisplayItems, totalItems: value.totalItems + newItems.length);
}