handleRemoveMore method
void
handleRemoveMore(
- String componentName,
- 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();
}