flutter - How to dynamically load choices and display them on child dropdown? - Stack Overflow

The goal is to load data and display it in a children dropdown as shown in the image:the expected resul

The goal is to load data and display it in a children dropdown as shown in the image:

the expected result is that when I click on a reference choice whose children are not present, the app should load them and display them.

This is the prompt I inserted into claude/chatgpt but I have not been able to get it to work:



When a user clicks on the arrow icon and it does not have any children, load the children
code1:



import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

import 'right_click_menu.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Right Click Menu Example'),
        ),
        body: Builder(
          builder: (context) => Listener(
            onPointerDown: (PointerDownEvent event) {
              final List<Map<String, dynamic>> buttons = [
                {'sys_id': '1', 'sys_name': 'Option 1', 'sys_type': 'bool'},
                {'sys_id': '2', 'sys_name': 'Option 2', 'sys_type': 'num'},
                {'sys_id': '3', 'sys_name': 'Submenu', 'sys_type': 'reference'},
                {'sys_id': '4', 'sys_name': 'Sub-option 1', 'sys_type': 'reference'},
                {'sys_id': '5', 'sys_name': 'Sub-option 2', 'sys_type': 'text'},
              ];

              final Map<String, List<String>> parentChildRelationships = {
                '3': ['4', '5'], 
              };

              RightClickMenu.display_right_click_menu(
                e: event,
                context: context,
                buttons: buttons,
                parentChildRelationships: parentChildRelationships,
                load_children: load_children,
              );
            },
            child: Center(
              child: Text('Right-click anywhere in this area!'),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> load_children(String id)async{
    // add dummy children to buttons and link them in parentChildRelationships
  }
}

code2:


import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class RightClickMenu {
  static Future<void> display_right_click_menu({
    required PointerDownEvent e,
    required BuildContext context,
    required List<Map<String, dynamic>> buttons,
    required Map<String, List<String>> parentChildRelationships,
    required Function(String) load_children,
  }) async {
    if (e.kind != PointerDeviceKind.mouse || e.buttons != kSecondaryMouseButton || buttons.isEmpty) {
      return; // 
    }

    final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
    final position = RelativeRect.fromLTRB(
      e.position.dx,
      e.position.dy,
      overlay.size.width - e.position.dx,
      overlay.size.height - e.position.dy,
    );

    await showMenu(
      context: context,
      position: position,
      items: _buildMenuItems(
        null, 
        buttons, 
        parentChildRelationships,
        load_children, 
        context
      ),
    );
  }

  // Helper method to find a button by its ID
  static Map<String, dynamic>? _findButtonById(String id, List<Map<String, dynamic>> allButtons) {
    return allButtons.firstWhere(
      (button) => button['sys_id'] == id,
      orElse: () => {},
    );
  }

  static List<PopupMenuEntry> _buildMenuItems(
    String? parentId, 
    List<Map<String, dynamic>> buttons,
    Map<String, List<String>> parentChildRelationships,
    Function(String) trigger_menu_script, 
    BuildContext context
  ) {
    List<PopupMenuEntry> menuItems = [];
    List<Map<String, dynamic>> filteredItems = [];

    if (parentId == null) {
      // Top-level menu: show only buttons that are NOT children of another button
      filteredItems = buttons.where((button) {
        String buttonId = button['sys_id'] ?? '';
        return !parentChildRelationships.values.any((children) => children.contains(buttonId));
      }).toList();
    } else {
      // Get child buttons of the specified parent
      List<String> childIds = parentChildRelationships[parentId] ?? [];
      filteredItems = childIds
          .map((id) => _findButtonById(id, buttons))
          .where((button) => button != null)
          .toList()
          .cast<Map<String, dynamic>>();
    }

    for (var i = 0; i < filteredItems.length; i++) {
      var item = filteredItems[i];
      String sysId = item['sys_id'] ?? '';
      String name = item['sys_name'] ?? 'Unnamed';
      
      // Check if this item has children
      bool hasChildren = parentChildRelationships.containsKey(sysId);

      // Offset calculations for submenu positioning
      double x_offset = i == 0 ? 125 : 183;

      if (hasChildren) {
        menuItems.add(
          PopupMenuItem(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(name),
                PopupMenuButton(
                  offset: Offset(x_offset, 0),
                  child: const Icon(Icons.arrow_right),
                  itemBuilder: (_) => _buildMenuItems(
                    sysId, 
                    buttons, 
                    parentChildRelationships,
                    trigger_menu_script, 
                    context
                  ),
                ),
              ],
            ),
          ),
        );
      } else {
        menuItems.add(
          PopupMenuItem(
            value: sysId,
            child: Text(name),
            onTap: () {
              trigger_menu_script(sysId);
            },
          ),
        );
      }
    }

    return menuItems;
  }
}

the image example is taken from the code below. as you can tell it appears to load the data but its never displayed.

code1:

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

import 'right_click_menu.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // Store menu data in state
  late List<Map<String, dynamic>> buttons;
  late Map<String, List<String>> parentChildRelationships;

  @override
  void initState() {
    super.initState();
    
    // Initialize menu data
    buttons = [
      {'sys_id': '1', 'sys_name': 'Option 1', 'sys_type': 'bool'},
      {'sys_id': '2', 'sys_name': 'Option 2', 'sys_type': 'num'},
      {'sys_id': '3', 'sys_name': 'Submenu', 'sys_type': 'reference'},
      {'sys_id': '4', 'sys_name': 'Sub-option 1', 'sys_type': 'reference'},
      {'sys_id': '5', 'sys_name': 'Sub-option 2', 'sys_type': 'text'},
    ];

    parentChildRelationships = {
      '3': ['4', '5'], 
    };
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Right Click Menu Example'),
        ),
        body: Builder(
          builder: (context) => Listener(
            onPointerDown: (PointerDownEvent event) {
              RightClickMenu.display_right_click_menu(
                e: event,
                context: context,
                buttons: buttons,
                parentChildRelationships: parentChildRelationships,
                load_children: load_children,
              );
            },
            child: Center(
              child: Text('Right-click anywhere in this area!'),
            ),
          ),
        ),
      ),
    );
  }

  Future<void> load_children(String id) async {
    // Simulate loading delay
    await Future.delayed(Duration(seconds: 1));
    
    // Update state with new children
    setState(() {
      // Check if the item already has children
      if (!parentChildRelationships.containsKey(id)) {
        // Generate new children
        String childId1 = 'child_${id}_1';
        String childId2 = 'child_${id}_2';
        
        // Add new children to buttons list
        buttons.add({
          'sys_id': childId1,
          'sys_name': 'Dynamic Child 1 of $id',
          'sys_type': 'text'
        });
        
        buttons.add({
          'sys_id': childId2,
          'sys_name': 'Dynamic Child 2 of $id',
          'sys_type': 'reference'  // This could potentially have children too
        });
        
        // Update parent-child relationships
        parentChildRelationships[id] = [childId1, childId2];
      }
    });
  }
}

code2:

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class RightClickMenu {
  static Future<void> display_right_click_menu({
    required PointerDownEvent e,
    required BuildContext context,
    required List<Map<String, dynamic>> buttons,
    required Map<String, List<String>> parentChildRelationships,
    required Function(String) load_children,
  }) async {
    if (e.kind != PointerDeviceKind.mouse || e.buttons != kSecondaryMouseButton || buttons.isEmpty) {
      return; //
    }

    final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
    final position = RelativeRect.fromLTRB(
      e.position.dx,
      e.position.dy,
      overlay.size.width - e.position.dx,
      overlay.size.height - e.position.dy,
    );

    await showMenu(
      context: context,
      position: position,
      items: _buildMenuItems(null, buttons, parentChildRelationships, load_children, context),
    );
  }

  // Helper method to find a button by its ID
  static Map<String, dynamic>? _findButtonById(String id, List<Map<String, dynamic>> allButtons) {
    return allButtons.firstWhere(
      (button) => button['sys_id'] == id,
      orElse: () => {},
    );
  }

  static List<PopupMenuEntry> _buildMenuItems(String? parentId, List<Map<String, dynamic>> buttons, Map<String, List<String>> parentChildRelationships, Function(String) load_children, BuildContext context) {
    List<PopupMenuEntry> menuItems = [];
    List<Map<String, dynamic>> filteredItems = [];

    if (parentId == null) {
      // Top-level menu: show only buttons that are NOT children of another button
      filteredItems = buttons.where((button) {
        String buttonId = button['sys_id'] ?? '';
        return !parentChildRelationships.values.any((children) => children.contains(buttonId));
      }).toList();
    } else {
      // Get child buttons of the specified parent
      List<String> childIds = parentChildRelationships[parentId] ?? [];
      filteredItems = childIds.map((id) => _findButtonById(id, buttons)).where((button) => button != null).toList().cast<Map<String, dynamic>>();
    }

    for (var i = 0; i < filteredItems.length; i++) {
      var item = filteredItems[i];
      String sysId = item['sys_id'] ?? '';
      String name = item['sys_name'] ?? 'Unnamed';

      // Check if this item has children or is a "reference" type that might have children
      bool hasChildren = parentChildRelationships.containsKey(sysId);
      bool isReferenceType = item['sys_type'] == 'reference';

      // Offset calculations for submenu positioning
      double x_offset = i == 0 ? 125 : 183;

      if (hasChildren || isReferenceType) {
        menuItems.add(
          PopupMenuItem(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(name),
                PopupMenuButton(
                  offset: Offset(x_offset, 0),
                  child: const Icon(Icons.arrow_right),
                  itemBuilder: (BuildContext context) {
                    // If this item doesn't have children but is a reference type,
                    // trigger the load_children function first
                    if (!hasChildren && isReferenceType) {
                      // Using Future.delayed to ensure the menu is built after the children are loaded
                      Future.delayed(Duration.zero, () => load_children(sysId));

                      // Return a loading indicator while children are being loaded
                      return [
                        PopupMenuItem(
                          enabled: false,
                          child: Center(
                            child: SizedBox(
                              height: 20,
                              width: 20,
                              child: CircularProgressIndicator(
                                strokeWidth: 2,
                              ),
                            ),
                          ),
                        ),
                      ];
                    }

                    // Otherwise, build the submenu as normal
                    return _buildMenuItems(sysId, buttons, parentChildRelationships, load_children, context);
                  },
                ),
              ],
            ),
          ),
        );
      } else {
        menuItems.add(
          PopupMenuItem(
            value: sysId,
            child: Text(name),
            onTap: () {
              load_children(sysId);
            },
          ),
        );
      }
    }

    return menuItems;
  }
}

at this point im not sure what to do. the stack overflows I found dont dynamically load data in a manner that I am looking for like these ones:

How can I make a multi level dependable dropdown List in Flutter?

How to build dependent dropdown menus in Flutter?

as you can see they mention 1/3 of the solution I want. they have dependent dropdown logic, but its not even close to what I am looking for.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744905272a4600217.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信