diff --git a/lib/src/form/src/controller.dart b/lib/src/form/src/controller.dart index 7eccb54..ec3a6f9 100644 --- a/lib/src/form/src/controller.dart +++ b/lib/src/form/src/controller.dart @@ -138,9 +138,44 @@ class AstromicFormController extends FormController { //S1 - State Variables final List _formGroups = []; //S1 - Methods + /// Get the structure of this groupId + FormGroupStructure? getGroupStructure(String groupID) { + // Get the full path of the group + final String? fullPath = getFullPathOfGroup(groupID, formGroups: _formGroups); - /// Recursively returns the full path of the group ID. - String? getFullPathOfGroup(String targetGroupID, {List? formGroups, String currentPath = ''}) { + // If no path is found, return null + if (fullPath == null) return null; + + // Split the path into segments (using the standard separator) + final List pathSegments = fullPath.split('->'); + + // We start with the root group (the first segment in the path) + FormGroupStructure? currentGroup = _formGroups.where((FormGroupStructure group) => group.id == pathSegments.first).firstOrNull; + + // If the root group is not found, return null + if (currentGroup == null) return null; + + // Traverse through the path segments to find the group or subgroup + for (int i = 1; i < pathSegments.length; i++) { + final String segment = pathSegments[i]; + + // Search for the subgroup within the current group + final (int, FormGroupStructure)? subGroup = currentGroup?.subGroups?.where(((int, FormGroupStructure) subGroup) => subGroup.$2.id == segment).firstOrNull; + + // If a subgroup is found, update currentGroup to the subgroup + if (subGroup != null) { + currentGroup = subGroup.$2; + } else { + // If no subgroup is found at this level, return null + return null; + } + } + + return currentGroup; + } + + /// returns the full path of this group ID. + String? getFullPathOfGroup(String targetGroupID, {List? formGroups, String currentPath = '', String separator = '->'}) { // Loop through each FormGroupStructure for (final FormGroupStructure group in (formGroups ?? _formGroups)) { // If the group ID matches, return the current path @@ -148,7 +183,7 @@ class AstromicFormController extends FormController { // Otherwise, check in its subgroups recursively for (final (int, FormGroupStructure) subGroup in group.subGroups ?? <(int, FormGroupStructure)>[]) { - final String? subGroupPath = getFullPathOfGroup(targetGroupID, formGroups: [subGroup.$2], currentPath: '$currentPath${group.id}->'); + final String? subGroupPath = getFullPathOfGroup(targetGroupID, formGroups: [subGroup.$2], currentPath: '$currentPath${group.id}$separator'); // Return the path if found if (subGroupPath != null) { return subGroupPath; @@ -160,6 +195,76 @@ class AstromicFormController extends FormController { return null; } + int getInstanceCount(String targetGroupID) { + FormGroupStructure? structure = getGroupStructure(targetGroupID); + if (structure != null) { + String firstField = structure.fields.first; + return controllers.keys.where((String c) => RegExp(standeredGroupFormat(targetGroupID, r'[\d+]', firstField)).hasMatch(c)).nonNulls.toList().length; + } + return 0; + } + + void _validateSubGroupsRecursively(FormGroupStructure groupStructure) { + groupStructure.subGroups?.forEach(((int, FormGroupStructure) subGroupTuple) { + final FormGroupStructure subGroup = subGroupTuple.$2; + assert(subGroup.fields.isNotEmpty, '${subGroup.id}: Subgroup fields should NOT be empty.'); + + // Recursively validate subgroups of subgroups + if (subGroup.subGroups != null) { + _validateSubGroupsRecursively(subGroup); + } + }); + } + + void _addGroupControllers(FormGroupStructure structure, int index, {String? parentPrefix}) { + final String baseID = parentPrefix ?? structure.id; + + for (final String fieldID in structure.fields) { + final String fullID = standeredGroupFormat(baseID, index.toString(), fieldID); + controller(fullID); + } + + for (final String valueID in structure.values ?? []) { + final String fullID = standeredGroupFormat(baseID, index.toString(), valueID); + controller(fullID); + } + } + + void _initializeGroupControllersRecursively(FormGroupStructure groupStructure, int initialCount, {String parentPrefix = ''}) { + // Add main group fields/values + for (int groupIndex = 0; groupIndex < initialCount; groupIndex++) { + _addGroupControllers(groupStructure, groupIndex, parentPrefix: parentPrefix.isEmpty ? null : parentPrefix); + + // Recursively handle subgroups + if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) { + for (final (int subgroupInitialCount, FormGroupStructure subGroup) in groupStructure.subGroups!) { + final String subgroupPrefix = parentPrefix.isEmpty + ? standeredGroupFormat(groupStructure.id, groupIndex.toString(), subGroup.id) + : standeredGroupFormat(parentPrefix, groupIndex.toString(), subGroup.id); // Add to parentPrefix only once + + // Initialize subgroup controllers recursively + for (int subIndex = 0; subIndex < subgroupInitialCount; subIndex++) { + _initializeGroupControllersRecursively(subGroup, subgroupInitialCount, parentPrefix: subgroupPrefix); + } + } + } + } + } + + /// Recursively initialize controllers for the group and its subgroups + void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) { + assert(groupStructure.fields.isNotEmpty, '${groupStructure.id}: Group fields should NOT be empty.'); + + // Validate subgroups (if any) + _validateSubGroupsRecursively(groupStructure); + + // Add structure to registry + _formGroups.add(groupStructure); + + // Initialize the group instances + _initializeGroupControllersRecursively(groupStructure, initialCount); + } + // _formController.initializeFormGroup( // FormGroupStructure( // id: 'mainGroup', @@ -197,42 +302,6 @@ class AstromicFormController extends FormController { // ); // } - /// Get the formGroupStructure of this groupId - FormGroupStructure? getGroupStructure(String groupID) { - // Get the full path of the group - final String? fullPath = getFullPathOfGroup(groupID, formGroups: _formGroups); - - // If no path is found, return null - if (fullPath == null) return null; - - // Split the path into segments - final List pathSegments = fullPath.split('->'); - - // We start with the root group (the first segment in the path) - FormGroupStructure? currentGroup = _formGroups.where((FormGroupStructure group) => group.id == pathSegments.first).firstOrNull; - - // If the root group is not found, return null - if (currentGroup == null) return null; - - // Traverse through the path segments to find the group or subgroup - for (int i = 1; i < pathSegments.length; i++) { - final String segment = pathSegments[i]; - - // Search for the subgroup within the current group - final (int, FormGroupStructure)? subGroup = currentGroup?.subGroups?.where(((int, FormGroupStructure) subGroup) => subGroup.$2.id == segment).firstOrNull; - - // If a subgroup is found, update currentGroup to the subgroup - if (subGroup != null) { - currentGroup = subGroup.$2; - } else { - // If no subgroup is found at this level, return null - return null; - } - } - - return currentGroup; - } - // FormGroupStructure? _getGroupStructure(String formGroupID, {bool isSubGroup = false}) { // FormGroupStructure? groupStructure; // if (isSubGroup) { @@ -300,68 +369,6 @@ class AstromicFormController extends FormController { // } // } - /// Validate subgroups recursively - void _validateSubGroupsRecursively(FormGroupStructure groupStructure) { - groupStructure.subGroups?.forEach(((int, FormGroupStructure) subGroupTuple) { - final FormGroupStructure subGroup = subGroupTuple.$2; - assert(subGroup.fields.isNotEmpty, '${subGroup.id}: Subgroup fields should NOT be empty.'); - - // Recursively validate subgroups of subgroups - if (subGroup.subGroups != null) { - _validateSubGroupsRecursively(subGroup); - } - }); - } - - /// Add controllers - void _addGroupControllers(FormGroupStructure structure, int index, {String? parentPrefix}) { - final String baseID = parentPrefix ?? structure.id; - - for (final String fieldID in structure.fields) { - final String fullID = standeredGroupFormat(baseID, index, fieldID); - controller(fullID); - } - - for (final String valueID in structure.values ?? []) { - final String fullID = standeredGroupFormat(baseID, index, valueID); - controller(fullID); - } - } - - /// Recursively initialize controllers for the group and its subgroups - void _initializeGroupControllersRecursively(FormGroupStructure groupStructure, int initialCount, {String parentPrefix = ''}) { - // Add main group fields/values - for (int groupIndex = 0; groupIndex < initialCount; groupIndex++) { - _addGroupControllers(groupStructure, groupIndex, parentPrefix: parentPrefix.isEmpty ? null : parentPrefix); - - // Recursively handle subgroups - if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) { - for (final (int subgroupInitialCount, FormGroupStructure subGroup) in groupStructure.subGroups!) { - final String subgroupPrefix = - parentPrefix.isEmpty ? standeredGroupFormat(groupStructure.id, groupIndex, subGroup.id) : standeredGroupFormat(parentPrefix, groupIndex, subGroup.id); // Add to parentPrefix only once - - // Initialize subgroup controllers recursively - for (int subIndex = 0; subIndex < subgroupInitialCount; subIndex++) { - _initializeGroupControllersRecursively(subGroup, subgroupInitialCount, parentPrefix: subgroupPrefix); - } - } - } - } - } - - void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) { - assert(groupStructure.fields.isNotEmpty, '${groupStructure.id}: Group fields should NOT be empty.'); - - // Validate subgroups (if any) - _validateSubGroupsRecursively(groupStructure); - - // Add structure to registry - _formGroups.add(groupStructure); - - // Initialize the group instances - _initializeGroupControllersRecursively(groupStructure, initialCount); - } - // void initializeFormGroup(FormGroupStructure groupStructure, {int initialCount = 1}) { // assert(groupStructure.fields.isNotEmpty, '$groupStructure: Group Fields should NOT be empty.'); // if (groupStructure.subGroups != null && groupStructure.subGroups!.isNotEmpty) { @@ -494,39 +501,6 @@ class AstromicFormController extends FormController { // ); // } - int getInstanceCount(String targetGroupID) { - // Helper method to check if a controller key matches the target group - bool isControllerForGroup(String controllerKey, String groupID) { - final RegExp regExp = RegExp(r'^' + RegExp.escape(groupID) + r'-#\d+-'); - return regExp.hasMatch(controllerKey); - } - - // Recursive helper function to find instances of a group and its subgroups - int countInstancesRecursively(FormGroupStructure groupStructure, List controllersKeys) { - // Start with the base count (for the current group itself) - int instanceCount = controllersKeys.where((String key) => isControllerForGroup(key, groupStructure.id)).length; - - // Recursively count instances in subgroups - if (groupStructure.subGroups != null) { - for ((int, FormGroupStructure) subGroup in groupStructure.subGroups!) { - instanceCount += countInstancesRecursively(subGroup.$2, controllersKeys); - } - } - - return instanceCount; - } - - // Flatten all controller keys into a list - final List controllerKeys = controllers.keys.toList(); - - // Find the group structure for the target group - final FormGroupStructure? groupStructure = getGroupStructure(targetGroupID); - if (groupStructure == null) return 0; - - // Use the recursive function to count instances for the target group - return countInstancesRecursively(groupStructure, controllerKeys); - } - FormGroupValue? getFormGroupValue(String formGroupID, {bool isSubGroup = false}) { // Get the group structure with the ID FormGroupStructure? groupStructure = getGroupStructure(formGroupID); @@ -639,7 +613,7 @@ class AstromicFormController extends FormController { //!SECTION //SECTION - Helper Methods - String standeredGroupFormat(String groupID, int groupIndex, String? secondaryID) => '$groupID-#$groupIndex-${secondaryID ?? ""}'; + String standeredGroupFormat(String groupID, String groupIndex, String? secondaryID) => '$groupID-#$groupIndex-${secondaryID ?? ""}'; void _addInitialControllers(Map? initialValues) { if (initialValues != null) {