Aaron
Aaron

Reputation: 43

Pass data from class to class - Flutter

I have a List Builder that creates a list based off of the documents listed in Firestore. I am trying to take the value generated from a Firestore snapshot and pass it out of the class to a variable that is updated every time the user clicks on a different entry from the List Builder. Here is the class making the Firestore interaction and returning the ListBuilder:

class DeviceBuilderListState extends State<DeviceBuilderList> {
  final flutterWebviewPlugin = new FlutterWebviewPlugin();

  @override
  void initState() {
    super.initState();

    // Listen for our auth event (on reload or start)
    // Go to our device page once logged in
    _auth.onAuthStateChanged
        .where((user) {
      new MaterialPageRoute(builder: (context) => new DeviceScreen());
    });

    // Give the navigation animations, etc, some time to finish
    new Future.delayed(new Duration(seconds: 1))
        .then((_) => signInWithGoogle());
  }

  void setLoggedIn() {
    _auth.onAuthStateChanged
        .where((user) {
      Navigator.of(context).pushNamed('/');
    });
    }

  @override
  Widget build(BuildContext context) {
    return new FutureBuilder<FirebaseUser>(
        future: FirebaseAuth.instance.currentUser(),
        builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
              if (snapshot.data != null)
                return new StreamBuilder(
                  stream: Firestore.instance
                      .collection('users')
                      .document(snapshot.data.uid)
                      .collection('devices')
                      .snapshots,
                  builder: (context, snapshot) {
                    if (!snapshot.hasData)
                      return new Container();
                    return new Container(
                      margin: const EdgeInsets.symmetric(vertical: 10.0),
                        child: new ListView.builder(
                            itemCount: snapshot.data.documents.length,
                            padding: const EdgeInsets.all(10.0),
                            itemBuilder: (context, index) {
                              DocumentSnapshot ds =
                              snapshot.data.documents[index];
                              return new Card(
                                  child: new GestureDetector(
                                  onTap: () {

                                      var initialStateLink = "${ds['name']}";

                                Navigator.of(context).pushNamed("/widget");
                              },
                              child: new Text(
                                " ${ds['name']}",
                                style: new TextStyle(fontSize: 48.0),
                              ),
                              ));
                            }),

                    );
                  },
                );
              else return new Container();
          }

    );}
}  

Then I want to send the var initialStateLink to a different function in the same dart file:

Future<String> initialStateUrl() async {
  final FirebaseUser currentUser = await _auth.currentUser();

  Firestore.instance.collection('users')
      .document(currentUser.uid).collection('devices').document(initialStateLink).get()
      .then((docSnap) {
    var initialStateLink = ['initialStateLink'];
      return initialStateLink.toString();
      });
  return initialStateUrl().toString();
}  

So that it returns me the proper String. I am at a complete loss on how to do this and I was unable to find another question that answered this. Thanks for the ideas.

Upvotes: 0

Views: 8288

Answers (3)

Aaron
Aaron

Reputation: 43

I ended up finding a different solution that solved the problem (kind of by skirting the actual issue).

A MaterialPageRoute allows you to build a new widget in place while sending in arguments. So this made it so I didn't have to send any data outside of the class, here is my code:

return new Card(
    child: new GestureDetector(
    onTap: () {
        Navigator.push(context,
            new MaterialPageRoute(
            builder: (BuildContext context) => new WebviewScaffold(
        url: ds['initialStateLink'],
        appBar: new AppBar(
            title: new Text("Your Device: "+'${ds['name']}'),
        ),
        withZoom: true,
        withLocalStorage: true,)
));},

Upvotes: 0

Vinoth Kumar
Vinoth Kumar

Reputation: 13431

Just make initialStateLink variable Global and send it as an argument to the another class like below,

a) Specify route as follows

'/widget' : (Buildcontext context) => new Anotherscreen(initialStateLink)

b) Navigate to the Anotherscreen()

c) Then the Anotherscreen () will be like this,

class Anotherscreen () extends StatelessWidget {
var initialStateLink;

Anotherscreen (this.initialStateLink);

......
}

Upvotes: 0

hunghd
hunghd

Reputation: 1344

You can use Navigator.push(Route route) instead of Navigator.pushNamed(String routeName)

And I don't encourage you to place navigation code deeply inside the widget tree, it's hard to maintain your logic of application flow because you end up with many pieces of navigation code in many classes. My solution is to place navigation code in one place (one class). Let's call it AppRoute, it looks like:

class AppRoute {

  static Function(BuildContext, String) onInitialStateLinkSelected =
      (context, item) =>
      Navigator.of(context).push(
          new MaterialPageRoute(builder: (context) {
              return new NewScreen(initialStateLink: initialStateLink);
            }
          ));

}

and replace your code in onTap:

onTap: () {
  var initialStateLink = "${ds['name']}";
  AppRoute.onInitialStateLinkSelected(context, initialStateLink);
}

Now, you not only can pass data from class to another class but also can control your application flow in ease (just look at AppRoute class)

Upvotes: 1

Related Questions