Home > Enterprise >  The Passed Value isn't updating in Flutter
The Passed Value isn't updating in Flutter

Time:10-05

I pass a String named "sourceCity" and "destinationCity" to my DropDown widget but when the DropDownValue changed, the String value doesn't automatically changed The new value is only updated inside the DropDownWidget.

add_journey.dart:

class AddJourneyPage extends StatefulWidget {
  @override
  _AddJourneyPage createState() => _AddJourneyPage();
}

class _AddJourneyPage extends State {
  String sourceCity = 'Source City';
  String destenationCity = 'Destination City';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
              Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama']),
              Dropdown(destenationCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama']),
          ElevatedButton(
              onPressed: ()  {
                print(sourceCity);
                //it's printing: Source City
                print(destenationCity);
                //it's printing: Destination City
              },
              child: const Text('Add Journey'))
        ],
      ),
    );
  }
}

DropDown.dart:

class Dropdown extends StatefulWidget{
  final List<String> items;
  late String hint;
  Color backgroundColor;
  Color iconColor;
  Color textColor;
  double fontSize;
  Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items});

  @override
  State<StatefulWidget> createState() => DropdownState();
}

class DropdownState extends State<Dropdown>{
  String hint="";
  @override
  void initState() {
    hint = widget.hint;
  }
  @override
  Widget build(BuildContext context) {
    return Theme(
        data: Theme.of(context).copyWith(
         canvasColor: widget.backgroundColor,
    ),
    child: DropdownButton<String>(
      hint: Text(hint, style: TextStyle(color: widget.textColor),),
      icon: Icon(Icons.arrow_drop_down, color: widget.iconColor),
      elevation: 16,
      style: TextStyle(color: widget.textColor),
      underline: Container(
        height: 2,
        width: 50,
        color: Colors.white,
      ),
      onChanged: (String? newValue) {
        setState(() {
          hint = newValue!;

        });
        },
      items: widget.items
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value,style: TextStyle(fontSize: widget.fontSize),),
        );
      }).toList(),
    )
    );
  }
}

How Could I update the passed String when it changed?

CodePudding user response:

Because you use the widget in two different domains, to update the parent widget, you need to use the event when the values of the dropdown list change.

First, define a global function, then

Change your code to the following

typedef CallbackDropDown = void Function(
String newValue);

class AddJourneyPage extends StatefulWidget {
  @override
  _AddJourneyPage createState() => _AddJourneyPage();
}

class _AddJourneyPage extends State {
  String sourceCity = 'Source City';
  String destenationCity = 'Destination City';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
              Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'],
               callbackDropDown:(newValue){
                  sourceCity = newValue;
               }),
              Dropdown(destenationCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'],
               callbackDropDown:(newValue){
                  destenationCity = newValue;
               }),
          ElevatedButton(
              onPressed: ()  {
                print(sourceCity);
                //it's printing: Source City
                print(destenationCity);
                //it's printing: Destination City
              },
              child: const Text('Add Journey'))
        ],
      ),
    );
  }
}

class Dropdown extends StatefulWidget{
  final List<String> items;
  final CallbackDropDown callbackDropDown;
  late String hint;
  Color backgroundColor;
  Color iconColor;
  Color textColor;
  double fontSize;
  Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items, required this.callbackDropDown});

  @override
  State<StatefulWidget> createState() => DropdownState();
}

class DropdownState extends State<Dropdown>{
  String hint="";
  @override
  void initState() {
    hint = widget.hint;
  }
  @override
  Widget build(BuildContext context) {
    return Theme(
        data: Theme.of(context).copyWith(
         canvasColor: widget.backgroundColor,
    ),
    child: DropdownButton<String>(
      hint: Text(hint, style: TextStyle(color: widget.textColor),),
      icon: Icon(Icons.arrow_drop_down, color: widget.iconColor),
      elevation: 16,
      style: TextStyle(color: widget.textColor),
      underline: Container(
        height: 2,
        width: 50,
        color: Colors.white,
      ),
      onChanged: (String? newValue) {
        setState(() {
          hint = newValue!;
          widget.callbackDropDown(newValue!);
        });
        },
      items: widget.items
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value,style: TextStyle(fontSize: widget.fontSize),),
        );
      }).toList(),
    )
    );
  }
}

CodePudding user response:

Change Dropdown to accept function in constructor:

class Dropdown extends StatefulWidget{
  final List<String> items;
  late String hint;
  Color backgroundColor;
  Color iconColor;
  Color textColor;
  double fontSize;
  fined Function(String?) onChange;
  Dropdown(this.hint, this.backgroundColor, this.iconColor, this.textColor, this.fontSize, {super.key, required this.items, required this.onChange});

  @override
  State<StatefulWidget> createState() => DropdownState();
}

and in your DropdownButton's onChange do this:

onChanged: (String? newValue) {
        widge.onChange(newValue)
},

and finally last change in your AddJourneyPage class:

Dropdown(sourceCity, Colors.grey.shade200, Colors.black, Colors.grey.shade700, 18.0, items: ['Aleppo','Damascus','Homs','Hama'], onChange:(value){
  setState(() {
    sourceCity = value ?? '';           
  });

}),
  • Related