handleRemoveMore method

void handleRemoveMore(
  1. String componentName,
  2. int indexToRemove
)

Implementation

void handleRemoveMore(String componentName, int indexToRemove) {
  var formDefinition = formDefinitions[componentName];
  if (formDefinition == null) return;

  // Prevent deletion if first index is mandatory
  if (indexToRemove == 0 && (formDefinition.mandatoryFirstIndex ?? false)) {
    return;
  }

  // Decrement startWithIndex
  formDefinition.startWithIndex = (formDefinition.startWithIndex ?? 0) - 1;

  // Get all fields for the section to be deleted
  final fieldsToDelete = extractFields(formDefinition, index: indexToRemove);
  if (fieldsToDelete.isEmpty) return;

  // Extract the base path pattern from the first field (supports nested arrays)
  final basePathPattern =
      deriveRepeatableBasePatternFromConcrete(fieldsToDelete.first.name);
  debugPrint('Field name: ${fieldsToDelete.first.name}');
  debugPrint('Base path pattern: $basePathPattern');
  debugPrint('Escaped base path pattern: ${escapeRegex(basePathPattern!)}');
  if (basePathPattern == null) return;

  // Helper: does a field belong to the section being deleted?
  bool isFieldInTargetSection(String fieldName) {
    // Check if the field starts with our base path and has the target index
    final targetPattern = '$basePathPattern[$indexToRemove]';
    debugPrint('Checking: $fieldName against pattern: $targetPattern');
    return fieldName.startsWith(targetPattern);
  }

  // Helper: get all keys with the index to remove
  List<String> getFieldsWithIndex(Map<String, dynamic> obj) {
    return obj.keys.where(isFieldInTargetSection).toList();
  }

  // Delete all values/options/errors/etc. for the section being removed
  final valuesToDelete = getFieldsWithIndex(values);
  debugPrint('Values to delete: $valuesToDelete');
  for (final fieldName in valuesToDelete) {
    values.remove(fieldName);
    debugPrint('Removed from values: $fieldName');
  }
  for (final fieldName in getFieldsWithIndex(options)) {
    options.remove(fieldName);
  }
  final errorsToDelete = getFieldsWithIndex(errors);
  debugPrint('Errors to delete: $errorsToDelete');
  for (final fieldName in errorsToDelete) {
    errors.remove(fieldName);
    debugPrint('Removed from errors: $fieldName');
  }
  for (final fieldName in getFieldsWithIndex(touched)) {
    touched.remove(fieldName);
  }
  for (final fieldName in getFieldsWithIndex(dependentValues)) {
    dependentValues.remove(fieldName);
  }
  for (final fieldName in getFieldsWithIndex(fieldsDisabled)) {
    fieldsDisabled.remove(fieldName);
  }

  // Now shift all higher indices down by one
  void updateKeys(Map<String, dynamic> obj) {
    final keys = obj.keys.toList();
    for (final key in keys) {
      // Only update keys that belong to our target section
      if (isFieldInTargetSection(key)) {
        obj.remove(key);
      } else if (key.startsWith(basePathPattern)) {
        // Update indices for fields in the same section with higher indices
        // Use string manipulation instead of regex to avoid escaping issues
        final afterPattern = key.substring(basePathPattern.length);
        if (afterPattern.startsWith('[') && afterPattern.contains(']')) {
          final endBracket = afterPattern.indexOf(']');
          final indexStr = afterPattern.substring(1, endBracket);
          final fieldIndex = int.tryParse(indexStr);

          if (fieldIndex != null && fieldIndex > indexToRemove) {
            final suffix = afterPattern.substring(endBracket + 1);
            final newKey = '$basePathPattern[${fieldIndex - 1}]$suffix';
            obj[newKey] = obj[key];
            obj.remove(key);
            debugPrint("Shifted: $key -> $newKey");
          }
        }
      }
    }
  }

  updateKeys(values);
  updateKeys(options);
  updateKeys(errors);
  updateKeys(touched);
  updateKeys(dependentValues);
  updateKeys(fieldsDisabled);

  // Update allFields (remove and shift)
  debugPrint('allFields before removal: ${allFields.length}');
  allFields = removeFieldAtIndex(allFields, indexToRemove);
  debugPrint('allFields after removal: ${allFields.length}');
  debugPrint('allFields names: ${allFields.map((f) => f.name).toList()}');

  notifyListeners();
}