How can i pass data between two widgets (files)?

I am building an flutter app and I need to pass function to other widget. Screenshot of my app for better understading

I have these 8 TextFormFields with values in it. When I press the grey button "Smazat hodnoty pasažérů" it should clear all the text fields.

I have the textfields in one file pasazeri.dart and the button in another file deleteBtn.dart. I think I can just send the function to clear the boxes to my button widget but it doesn't work.

This is my full code of pasazeri.dart

import 'package:flutter/services.dart';
import 'deleteBtn.dart';

class Pasazeri extends StatefulWidget {
  @override
  _PasazeriState createState() => _PasazeriState();
}

class _PasazeriState extends State<Pasazeri> {
  final FocusNode pasazer1 = FocusNode();
  final FocusNode pasazer2 = FocusNode();
  final FocusNode pasazer3 = FocusNode();
  final FocusNode pasazer4 = FocusNode();
  final FocusNode pasazer5 = FocusNode();
  final FocusNode pasazer6 = FocusNode();
  final FocusNode pasazer7 = FocusNode();
  final FocusNode pasazer8 = FocusNode();

  TextEditingController contPasazer1 = TextEditingController();
  TextEditingController contPasazer2 = TextEditingController();
  TextEditingController contPasazer3 = TextEditingController();
  TextEditingController contPasazer4 = TextEditingController();
  TextEditingController contPasazer5 = TextEditingController();
  TextEditingController contPasazer6 = TextEditingController();
  TextEditingController contPasazer7 = TextEditingController();
  TextEditingController contPasazer8 = TextEditingController();

  _fieldFocusChange(
      BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
    currentFocus.unfocus();
    FocusScope.of(context).requestFocus(nextFocus);
  }

  void clearBoxes() {
    setState(() {
      contPasazer1.clear();
      contPasazer2.clear();
      contPasazer3.clear();
      contPasazer4.clear();
      contPasazer5.clear();
      contPasazer6.clear();
      contPasazer7.clear();
      contPasazer8.clear();
    });
  }

  Widget pasazer(cisloPasazer, controller, focusnode, next) {
    return Container(
      margin: EdgeInsets.only(left: 8),
      child: Row(
        children: <Widget>[
          Text(
            "$cisloPasazer. pasažér: ",
            style: TextStyle(fontSize: 14.5, fontWeight: FontWeight.w500),
          ),
          Container(
            padding: EdgeInsets.only(left: 3),
            width: 40,
            height: 25,
            decoration: BoxDecoration(
                color: Color(0xFFFFDD80),
                borderRadius: BorderRadius.all(Radius.circular(10))),
            child: Center(
              child: TextFormField(
                controller: controller,
                focusNode: focusnode,
                textInputAction: TextInputAction.next,
                onChanged: (String str) => DeleteBtn(delete: clearBoxes),
                onFieldSubmitted: (term) {
                  _fieldFocusChange(context, focusnode, next);
                },
                style: TextStyle(
                    color: Colors.black,
                    fontSize: 15,
                    fontWeight: FontWeight.w600),
                cursorWidth: 1,
                textAlign: TextAlign.center,
                textAlignVertical: TextAlignVertical.center,
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.symmetric(vertical: 9),
                  border: InputBorder.none,
                  hintText: "",
                  hintStyle: TextStyle(
                    color: Color(0xFF9c9a98),
                  ),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: <TextInputFormatter>[
                  WhitelistingTextInputFormatter.digitsOnly,
                  LengthLimitingTextInputFormatter(3),
                ],
              ),
            ),
          ),
          Text(" kg",
              style: TextStyle(fontSize: 14.5, fontWeight: FontWeight.w500))
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(
          top: MediaQuery.of(context).size.height * 0.015,
          bottom: MediaQuery.of(context).size.height * 0.015,
          left: 8,
          right: 8),
      padding: EdgeInsets.symmetric(
          vertical: MediaQuery.of(context).size.height * 0.012),
      decoration: BoxDecoration(
        color: Color(0xFFa38b5f),
        borderRadius: BorderRadius.all(Radius.circular(20)),
      ),
      child: Column(
        children: <Widget>[
          Container(
            margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                pasazer(1, contPasazer1, pasazer1, pasazer2),
                Container(
                  margin: EdgeInsets.only(right: 8),
                  child: Row(
                    children: <Widget>[
                      pasazer(5, contPasazer5, pasazer5, pasazer6),
                    ],
                  ),
                )
              ],
            ),
          ),
          Container(
            margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                pasazer(2, contPasazer2, pasazer2, pasazer3),
                Container(
                  margin: EdgeInsets.only(right: 8),
                  child: Row(
                    children: <Widget>[
                      pasazer(6, contPasazer6, pasazer6, pasazer7),
                    ],
                  ),
                )
              ],
            ),
          ),
          Container(
            margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                pasazer(3, contPasazer3, pasazer3, pasazer4),
                Container(
                  margin: EdgeInsets.only(right: 8),
                  child: Row(
                    children: <Widget>[
                      pasazer(7, contPasazer7, pasazer7, pasazer8),
                    ],
                  ),
                )
              ],
            ),
          ),
          Container(
            margin: EdgeInsets.symmetric(vertical: 6, horizontal: 10),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                pasazer(4, contPasazer4, pasazer4, pasazer5),
                Container(
                  margin: EdgeInsets.only(right: 8),
                  child: Row(
                    children: <Widget>[
                      Container(
                        margin: EdgeInsets.only(left: 8),
                        child: Row(
                          children: <Widget>[
                            Text(
                              "8. pasažér: ",
                              style: TextStyle(
                                  fontSize: 14.5, fontWeight: FontWeight.w500),
                            ),
                            Container(
                              padding: EdgeInsets.only(left: 3),
                              width: 40,
                              height: 25,
                              decoration: BoxDecoration(
                                  color: Color(0xFFFFDD80),
                                  borderRadius:
                                      BorderRadius.all(Radius.circular(10))),
                              child: Center(
                                child: TextFormField(
                                  controller: contPasazer8,
                                  focusNode: pasazer8,
                                  textInputAction: TextInputAction.done,
                                  onFieldSubmitted: (term) {
                                    pasazer8.unfocus();
                                  },
                                  style: TextStyle(
                                      color: Colors.black,
                                      fontSize: 15,
                                      fontWeight: FontWeight.w600),
                                  cursorWidth: 1,
                                  textAlign: TextAlign.center,
                                  textAlignVertical: TextAlignVertical.center,
                                  decoration: InputDecoration(
                                    contentPadding:
                                        EdgeInsets.symmetric(vertical: 9),
                                    border: InputBorder.none,
                                    hintText: "",
                                    hintStyle: TextStyle(
                                      color: Color(0xFF9c9a98),
                                    ),
                                  ),
                                  keyboardType: TextInputType.number,
                                  inputFormatters: <TextInputFormatter>[
                                    WhitelistingTextInputFormatter.digitsOnly,
                                    LengthLimitingTextInputFormatter(3),
                                  ],
                                  onChanged: (String str) {},
                                ),
                              ),
                            ),
                            Text(" kg",
                                style: TextStyle(
                                    fontSize: 14.5,
                                    fontWeight: FontWeight.w500))
                          ],
                        ),
                      ),
                    ],
                  ),
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

And here is my code of deleteBtn.dart


class DeleteBtn extends StatelessWidget {
  final Function delete;
  DeleteBtn({this.delete});
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
        height: 40,
        margin: EdgeInsets.only(right: 8),
        decoration: BoxDecoration(
          color: Color(0xFF616161),
          borderRadius: BorderRadius.all(Radius.circular(20)),
        ),
        child: FlatButton(
          padding: EdgeInsets.symmetric(horizontal: 0),
          child: Text(
            "Smazat hodnoty pasažérů",
            style: TextStyle(fontSize: 10),
          ),
          onPressed: () {
            print(delete);
            delete();
          },
        ),
      ),
    );
  }
}

When i press the button i need to call the function clearBoxes() which is in the pasazeri.dart I added print(delete); to onPressed: and it gives me:

The following NoSuchMethodError was thrown while handling a gesture:
The method 'call' was called on null.
Receiver: null
Tried calling: call()

So i think it's problem with passing the function.

Does anyone know how can i fix it?

2 answers

  • answered 2020-07-29 19:09 Madhavam Shahi

    Add this line to your code:

    import 'pasazeri.dart' as paz(..in ur deletebtn.dart)
    

    Then, add this line in the onPressed():

    paz.PasazeriState().clearBoxes();
    

    OR,

    1. In your pasazeri.dart, add this line..above "override"
    
    Pasazeri(this.clearbox);
    
      final bool clearbox;
    
    
    1. Change your clearBoxes function to this-
    void clearbox(){
    
    bool k= widget.clearbox;//..put it in set state.
    
    If(k){
    //Delete boxes
    }Else{
    //Do smthng
    }
    
    }//Clearbox closes
    
    1. Now, in your deletebtn.dart, inside the onPressed (), write this
    Pasazeri(true);
    

    Lemme know if this worked, i think it should.

  • answered 2020-07-30 05:53 Alok

    There were certain problem in your code which were not letting you achieve this thing. I will point it down for you:

    • No need of doing setState() in your clearBoxes(), since, it will do it's job. setState is used, when there is a change in the value of the state of a variable, to be reflected in a widget. For example: Adding +1 on the hit of a button for Counter or more specifically, providing new text to your controller, setState(() => contPasazer1.text = "New value")
    • To pass the function to your widget, you should be doing delete: () => your_function_name, not delete: clearBoxes. Your delete is a type void, and it is a dart formatting error. hence nothing works, even you pass the correct method

    Let us look at the corrected code for the above instance:

    void clearBoxed(){
      // no need of setState
      contPasazer1.clear();
      contPasazer2.clear();
      contPasazer3.clear();
      contPasazer4.clear();
      contPasazer5.clear();
      contPasazer6.clear();
      contPasazer7.clear();
      contPasazer8.clear();
    }
    

    Passing the clearBoxes() correctly to your DeleteBtn class argument delete. Do give a read on Pass function into a function in Dart

    // you can also do this (){ clearBoxes() }, but below is more dart way or JS way
    onChanged: (String str) => DeleteBtn(delete: () => clearBoxes())
    

    Also, I wonder, why do you use DeleteBtn() in your onChanged()? If you want to use it as a button, just place there simply, and use the button

    onChanged() will be called every time you start writing in your specified TextFormField. This is not a best practise, I would suggest

    For cleaner approach, you can just call the method clearBoxes(), when you start typing something like this:

    onChanged: (String str) => clearBoxes()
    

    And wherever you wanna use your button, you can use it by placing the DeleteBtn and that is it like below:

    Row(
     children: [
        TextFormField(
           onChanged: (String str) => clearBoxes() 
        ),
        DeleteBtn(delete: () => clearBoxes())
     ]
    )
    

    Consider using the best practices, it will help you in the long run.

    I am showing my code to show how things are working. I have just used 3 TexFields and a DeleteBtn to show that how this works.

    Focus on how things are working in the code, specifically, clearBoxes() and DeleteBtn(delete: () => clearBoxes())

    class _MyHomePageState extends State<MyHomePage> {
      TextEditingController contPasazer1 = TextEditingController();
      TextEditingController contPasazer2 = TextEditingController();
      TextEditingController contPasazer3 = TextEditingController();
      
      // no need of setState()
      void clearBoxes() {
        contPasazer1.clear();
        contPasazer2.clear();
        contPasazer3.clear();
      }
      
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Container(
            height: double.infinity,
            width: double.infinity,
            padding: EdgeInsets.symmetric(horizontal: 20.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                TextFormField(controller: contPasazer1),
                SizedBox(height: 20.0),
                TextFormField(controller: contPasazer2),
                SizedBox(height: 20.0),
                TextFormField(controller: contPasazer3),
                SizedBox(height: 20.0),
                // Your delete button from another class
                DeleteBtn(delete: () => clearBoxes())
              ]
            )
          )
        );
      }
    }
    
    // Your other class
    class DeleteBtn extends StatelessWidget {
      final Function delete;
      DeleteBtn({this.delete});
      @override
      Widget build(BuildContext context) {
        return Expanded(
          child: Container(
            height: 40,
            margin: EdgeInsets.only(right: 8),
            decoration: BoxDecoration(
              color: Color(0xFF616161),
              borderRadius: BorderRadius.all(Radius.circular(20)),
            ),
            child: FlatButton(
              padding: EdgeInsets.symmetric(horizontal: 0),
              child: Text(
                "Smazat hodnoty pasažérů",
                style: TextStyle(fontSize: 10),
              ),
              onPressed: () {
                print(delete);
                delete();
              },
            ),
          ),
        );
      }
    }
    

    Result

    Disclaimer: Don't look at the UI, I would request you to look at the functionality. I have used your DeleteBtn only, but did not come fine with the layout, so apologies.

    Result