50
votes

I am stuck in my project where I have two stateful widgets created in flutter as two different dart files. Now, I have to access the instance of an object created in first widget in the second widget, but I am not so sure how I can do this in flutter when creating widgets.

One possible solution I thought of is to declare the two widgets in just one dart file instead of two dart files for two layouts, but I am curious if we can do it by declaring in two separate dart files.

I have posted the files just to re-create the issue.

main.dart

 import 'package:flutter/material.dart';
 import 'package:untitled2/models.dart';
 import 'package:untitled2/secondwidget.dart';

void main() {
 runApp(new MaterialApp(
     home: new MyApp(),
 ),);
}

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

      class _MyAppState extends State<MyApp> {
 final TextEditingController _nameController = new TextEditingController();
 final TextEditingController _emailIdController = new 
 TextEditingController();
 final TextEditingController _passwordController = new 
 TextEditingController();
 final TextEditingController _confirmPasswordController = new 
 TextEditingController();

 MyModel myModel = new MyModel();

 @override
 Widget build(BuildContext context) {
  return new MaterialApp(
  home: new Scaffold(
    body: new ListView(

      children: <Widget>[
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
              labelText: 'Enter your Name'
            ),
            controller: _nameController,
            onSaved: (String value){myModel.name = value;} ,
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'EmailId'
            ),
              controller: _emailIdController,
              onSaved: (String value){myModel.emailId = value;}
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Password'
            ),
              controller: _passwordController,
              onSaved: (String value){myModel.password = value;}
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Confirm Password'
            ),
            controller: _confirmPasswordController,

          ),
        ),
        new Container(
          child: new FlatButton(
            onPressed: ((){

              Navigator.push(context, new MaterialPageRoute(builder: (_) => 
         new SecondScreen(),),);

            }),
            child: new Text('Save'),),
        ),



      ],


      ),
     ),
    );
   }
  }

models.dart

class MyModel {

String name;
String emailId;
String password;

  }

secondwidget.dart

 import 'package:flutter/material.dart';


 class SecondScreen extends StatefulWidget {
 @override
 _SecondScreenState createState() => new _SecondScreenState();
}

class _SecondScreenState extends State<SecondScreen> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
  home: new Scaffold(
    body: new ListView(

      children: <Widget>[
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Enter address'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Address Line 2'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Address Line 3'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'POST CODE'
            ),
          ),
        ),

        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Mobile Number'
            ),
          ),
        ),
        new Container(
          child: new FlatButton(
              onPressed: ((){


                //I want to push the data captured from main.dart and from 
                            //secondwidget.dart into database
     // I want to use the instance of MyModel from main.dart here to save 
      // the data captured from the first screen and this one into database

              }),
              child: new Text('Save'),),
        ),


      ],


    ),
  ),
);
}
}
3
I am not sure what is the problem here, you can simply import the other dart file and then create an instance of one widget inside another one, it would be better if you add the code of the two dart files in order to understand what are your trying to achieve, otherwise your question is very generic and quite vague.Shady Aziza
thank you very much aziza I have edited the question to show exactly what I was looking for. but collin Jackson suggested an answer. so i will try that one first and see if that solves my problem.Mahi
The third option Collin suggested should work just fine here, you can simply pass the data saved in the TextForms in your first page as constructor arguments of your SecondScreen and then use them to create the object of your model inside your SecondScreen.Shady Aziza

3 Answers

78
votes

There are lots of ways to do this depending on your use case. Here are a few options:

  1. You can expose the created object as public member of your State. Then use the currentState property of a GlobalKey in one State to get a reference to the other State. Now you can access the created object via the public member. (Note: This pattern limits the testability and encapsulation of your State, so use it sparingly.)
  2. Both widgets can have a ancestor widget that extends InheritedWidget that they use to look up the created object.
  3. Both widgets can be passed a model argument in their a constructor, such as a ValueNotifier. They can use this object to read and write the value.

If you go into more detail on your use case we can help you pick a pattern that makes sense.

Here is some code implementing option #1.

import 'package:flutter/material.dart';

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

final key = new GlobalKey<MyStatefulWidget1State>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            new MyStatefulWidget1(key: key),
            new MyStatefulWidget2(),
          ],
        ),
      ),
    );
  }
}

class MyStatefulWidget1 extends StatefulWidget {
  MyStatefulWidget1({ Key key }) : super(key: key);
  State createState() => new MyStatefulWidget1State();
}

class MyStatefulWidget1State extends State<MyStatefulWidget1> {
  String _createdObject = "Hello world!";
  String get createdObject => _createdObject;

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new Text(_createdObject),
    );
  }
}

class MyStatefulWidget2 extends StatefulWidget {
  State createState() => new MyStatefulWidget2State();
}

class MyStatefulWidget2State extends State<MyStatefulWidget2> {
  String _text = 'PRESS ME';

  @override
  Widget build(BuildContext context) {
    return new Center(
      child: new RaisedButton(
        child: new Text(_text),
        onPressed: () {
          setState(() {
            _text = key.currentState.createdObject;
          });
        },
      ),
    );
  }
}
13
votes

You can pass the model when you construct SecondScreen widget.

  1. Add model to SecondScreen constructor:

    class SecondScreen extends StatefulWidget {
      final MyModel myModel;
    
      SecondScreen(MyModel myModel, {Key key}):
          super(key: key);
    ...
    }
    
  2. Pass model when you construct SecondScreen in main.dart

    Navigator.push(context, new MaterialPageRoute(builder: (_) => 
      new SecondScreen(model)));
    
  3. Now you can access model in _SecondScreenState via widget.myModel

7
votes

Here is how I pass parameter to the child widget.

First Widget dart file

class FirstWidget extends StatefulWidget {
    _FirstWidgetState createState() => _FirstWidgetState() 
}

class _FirstWidgetState extends State<FirstWidget> {
    String param = "My parameter";
    @override
    Widget build(BuildContext context) {
        return Container(
                    child: 
                        SecondWidget(param), //pass parmater here
                );
    }
}

Second Widget dart file

class SecondWidget extends StatefulWidget {
    final String param; 
    SecondWidget(this.param); //passed paramter
    _SecondWidgetState createState() => _SecondWidgetState() 
}

class _SecondWidgetState extends State<SecondWidget> {
    @override
    Widget build(BuildContext context) {
        return Container(
                    child: 
                        Text(widget.param), //output paramter
                );
    }
}