16

I have previously posted about this problem I am still facing Which is to return data from a Stateful widget back to a Stateless Widget

The Widget I am using is DateTimePickerFormField widget and I am using it as a child in a stateful widget

So I have looked at https://flutter.io/docs/cookbook/navigation/returning-data#complete-example

For returning data from a widget. However, the widget that is returning the data is a stateless widget ...Which in my case isn't

So The code goes as follows

Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add a Reminder'),

      ),
      body:
      new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Form(
            child: new ListView(
              children: <Widget>[

            new TextFormField(
            keyboardType: TextInputType.text,
              // Use email input type for emails.
              decoration: new InputDecoration(
                hintText: 'Title of reminder',
              ),

            ),
            dateAndTimeWidget(context),
            RaisedButton(
            child: Text('Save'),
        onPressed: () {
          Navigator.pop(context);
        },
      )
      ],
    ),)
    ,
    )
    ,
    );

  }

That Widget is calling the method: dateAndTimeWidget, Which is supposed to return the dateTime stateful widget and save the outcoming data in a variable :

 dateAndTimeWidget(BuildContext context) async {
    final result = await Navigator.push(
      context,
      MaterialPageRoute(builder: (context)=> dateTime()),
    );

}

Then This is the dateTime Statful widget

class dateTime extends StatefulWidget{
    @override
  dateTimeState createState() => dateTimeState();

}
class dateTimeState extends State<dateTime>{

  static DateTime dateT;

  InputType inputType = InputType.both;

  final formats = {
    InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
    InputType.date: DateFormat('yyyy-MM-dd'),
    InputType.time: DateFormat("HH:mm"),
  };

  Widget build(BuildContext context) => Container(
      child: DateTimePickerFormField(
        inputType: InputType.both,
        editable: true,
        format: formats[inputType],
        decoration: InputDecoration(
            labelText: 'Date/Time', hasFloatingPlaceholder: false),
        onChanged: (dt) {
          setState(() => dateT = dt);
          Navigator.of(context).pop(dateT);
        },

      )


  );


}

I am not using the value result yet Because the error is that I never get to the add reminder page and it says that the result push navigation method is pointing at null

0

2 Answers 2

34

In this situation passing data with Navigator is not suitable. Because there isn't page transition between the page and your dateTime Widget. I recommend you to implement ValueChanged callback to pass data between widgets in same screen.

example code:

It's little bit tricky. But material.dart's widgets often use this technique. I hope this will help you!

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  DateTime dateT;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Add a Reminder'),
      ),
      body: new Container(
        padding: new EdgeInsets.all(20.0),
        child: new Form(
          child: new ListView(
            children: <Widget>[
              new TextFormField(
                keyboardType: TextInputType.text,
                // Use email input type for emails.
                decoration: new InputDecoration(
                  hintText: 'Title of reminder',
                ),
              ),
              dateTime(
                onDateTimeChanged: (newDateTime) {
                  dateT = newDateTime;
                },
              ),
              RaisedButton(
                child: Text('Save'),
                onPressed: () {
                  Navigator.pop(context);
                },
              )
            ],
          ),
        ),
      ),
    );
  }
}

class dateTime extends StatefulWidget {
  final ValueChanged<DateTime> onDateTimeChanged;

  dateTime({Key key, this.onDateTimeChanged}) : super(key: key);

  @override
  dateTimeState createState() => dateTimeState();
}

class dateTimeState extends State<dateTime> {
  DateTime dateT;

  InputType inputType = InputType.both;

  final formats = {
    InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
    InputType.date: DateFormat('yyyy-MM-dd'),
    InputType.time: DateFormat("HH:mm"),
  };

  Widget build(BuildContext context) => Container(
        child: DateTimePickerFormField(
          inputType: InputType.both,
          editable: true,
          format: formats[inputType],
          decoration: InputDecoration(
              labelText: 'Date/Time', hasFloatingPlaceholder: false),
          onChanged: (dt) {
            widget.onDateTimeChanged(dt);
          },
        ),
      );
}

(Btw your dateAndTimeWidget is a method, is not a Widget. So if you assign it to Column`s children(List), Flutter framework cannot understand.)

Sign up to request clarification or add additional context in comments.

Comments

13

For more time saving solution for returning value from another widget and using it, here's an example for Flutter Dropdown:

import 'package:flutter/material.dart';
import 'package:paxi_ride/constant.dart';

class BuildDropdown extends StatefulWidget {
  final ValueChanged<String> onChanged;
  String defaultValue, selectedValue, dropdownHint;
  List<String> itemsList;

  BuildDropdown(
      {Key key,
      this.itemsList,
      this.defaultValue,
      this.dropdownHint,
      this.onChanged})
      : super(key: key);

  @override
  _BuildDropdownState createState() => _BuildDropdownState();
}

class _BuildDropdownState extends State<BuildDropdown> {
  String _value;

  @override
  Widget build(BuildContext context) {
    return Container(
      // height: 40,
      padding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
      margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      color: Colors.white,
      child: DropdownButton<String>(
        items: widget.itemsList.map(
          (String value) {
            return new DropdownMenuItem<String>(
              value: value,
              child: new Text(value),
            );
          },
        ).toList(),
        value: _value == null ? widget.defaultValue : _value,
        isExpanded: true,
        onChanged: (String value) {
          setState(() {
            _value = value;
          });
          widget.onChanged(value);
        },
        hint: Text(widget.dropdownHint),
        style: TextStyle(
          fontSize: 14,
          color: brownColorApp,
        ),
        iconEnabledColor: brownColorApp,
        iconSize: 14,
        underline: Container(),
      ),
    );
  }
}

Call this widget from another widget where you want to get selected value like this:

String selectedValue; //class field

BuildDropdown(
          itemsList: ['Option 1','Option 2'],
          defaultValue: 'Option 1',
          dropdownHint: 'Select Required Option',
          onChanged: (value) {
            selectedValue = value;
          },
        ),

Use this value wherever needed, it will be changed as dropdown selection is changed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.