Home > OS >  How to access a variable inside a ListViewBuilder from where the builder is called?
How to access a variable inside a ListViewBuilder from where the builder is called?

Time:03-01

Am working on an app that has a form that uses ListViewBuilder for the list of the items and returns a widget that shows a TextField for each item in the list. Is there a way to access the TextField Controller of any item from the form widget itself to get the new value?

Widget used in the ListView builder

class BrandNamesWidget extends StatelessWidget {
  BrandNamesWidget({Key? key, required this.brandName, required this.index})
      : super(key: key);
  final String brandName;
  final int index;

  final TextEditingController _brandNameController =
      new TextEditingController();

  @override
  Widget build(BuildContext context) {
    _brandNameController.text = brandName;
    final deviceDimensions = Provider.of<Dimension>(context);

    double height = deviceDimensions.getDeviceHeight();
    double width = deviceDimensions.getDeviceWidth();
    return TextField(
      controller: _brandNameController,
      cursorColor: Colors.black,
      style: TextStyle(
        color: AppInfo.MAIN_COLOR,
        letterSpacing: 1.5,
      ),
      keyboardType: TextInputType.text,
      decoration: InputDecoration(
        constraints: BoxConstraints(maxWidth: width * 0.45),
        labelText: 'Brand name: '   index.toString(),
        prefixIcon: Icon(Icons.medication),
        labelStyle: TextStyle(
          fontSize: height * 0.03,
          color: AppInfo.MAIN_COLOR,
        ),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(50),
        ),
      ),
    );
  }
}


Form Widget

.
.
Container(
                  child: ListView.builder(
                      itemCount: _brandnames.length,
                      itemBuilder: (BuildContext ctx, int index) {
                        return BrandNamesWidget(
                            brandName: _brandnames[index].toString(),
                            index: index);
                      }),
                ),

// Want to access the _brandNameController.text here in a function to update firestore
.
.

I have checked online for solutions and the only similar question I found was from this stackoverflow question (Is there a way to access variables in a state in Flutter/Dart?)

CodePudding user response:

One way to do it is instantiating a TextEditingController from the outside in the itemBuilder and inject it inside the BrandNamesWidget, hold their references in a collection, that way you can grab their content from the outside like this Gist I created for you. This is what your new class would look like:

class BrandNamesWidget extends StatelessWidget {
  
  final TextEditingController? controller;
  final String? brandName;
  final int? index;
  
  BrandNamesWidget({ this.brandName, required this.index, this.controller });
  
  @override
  Widget build(BuildContext context) {
    
    double height = 100;
    double width = MediaQuery.of(context).size.width;
    
    return TextField(
      controller: controller!,
      keyboardType: TextInputType.text,
      decoration: InputDecoration(
        constraints: BoxConstraints(maxWidth: width * 0.45),
        labelText: 'Brand name: '   index.toString(),
        prefixIcon: const Icon(Icons.medication),
        labelStyle: TextStyle(
          fontSize: height * 0.03,
          color: Colors.grey,
        ),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(50),
        ),
      ),
    );
  }
}

And this is the parent widget holding on to the TextEditingController references, housing your ListView.builder:


class MyWidget extends StatelessWidget {
  
  List<String> _brandnames = ['Toyota', 'Honda', 'BMW', 'Mercedes'];
  List<TextEditingController> controllers = [];
  
  @override
  Widget build(BuildContext context) {
    
    controllers = [];
    
    return Column(
      children: [
        Expanded(
          child:  Container(
            child: ListView.builder(
              itemCount: _brandnames.length,
              itemBuilder: (BuildContext ctx, int index) {
                TextEditingController ctrl = TextEditingController();
                controllers.add(ctrl);
                return BrandNamesWidget(
                  brandName: _brandnames[index].toString(),
                  controller: ctrl,
                  index: index);
              }),
          )
        ),
        TextButton(
          onPressed: () {
            
            for(var ctrl in controllers) {
              print(ctrl.text);
            }
          },
          child: Text('Click me to get their values')
        )
      ]
    );
  }
}

If you input stuff on the text fields shown, and you click on the button I provided, you'll get their content from a function, thus being able to update Firestore or anything you want. Check it out and let me know.

  • Related