Maverick 2000
Maverick 2000

Reputation: 15

Flutter: Adding text from alert dialog to list view

I'm trying to add user input from the alert dialog to list view. Every time I run it, the alert dialog accepts input and the item list gets updated but the list view wont update. The state of the app wont change after I press OK on the alert dialog button. Please help me with this issue as I'm new to flutter.

Future<String> createAlertDialog(BuildContext context) {
        //promise to return string
        TextEditingController customController =
            TextEditingController(); //new texteditingc object
        return showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                title: Text("Enter URL: "),
                content: TextField(
                  controller: customController,
                ),
                actions: [
                  MaterialButton(
                    elevation: 5.0,
                    child: Text("OK"),
                    onPressed: () {
                      Navigator.of(context).pop(customController.text.toString());
                    },
                  )
                ],
              );
            });
      }

  

    @override
      Widget build(BuildContext context) {
        List item = List();
        item=['HI'];
        String temp;
        return Scaffold(
          appBar: AppBar(
            title: Text("Shortie"),
          ),
          body: Padding(
            padding: const EdgeInsets.all(8.0),
            child: ListView(
              children: 
              
              item.map((element)=>Text(element)).toList(), 
              
              ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              createAlertDialog(context).then((onValue) {
                temp=onValue;
                print(temp);
                 
                
              });
              setState(() {
                item.add(temp);
                print(item);
              });
            },
            tooltip: 'Add URL',
            child: Icon(Icons.add),
          ),
        );

Upvotes: 0

Views: 2145

Answers (3)

mddg
mddg

Reputation: 695

You could use the provider package and communicate the AlertDialog with the ListView by using notifyListeners() and making the ListView a Consumer of the Provider data.

For more info about the package: https://pub.dev/documentation/provider/latest

Upvotes: 0

wafL
wafL

Reputation: 655

You have to call setState() in order to update a Widget if you have new information.

Try changing your showDialog() to this:

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: Text("Enter URL: "),
          content: TextField(
             controller: customController,
          ),
          actions: [
            MaterialButton(
              elevation: 5.0,
              child: Text("OK"),
              onPressed: () {
                item.add(customController.text);
                setState((){});
                Navigator.of(context).pop();

            },
          )
        ],
      );
    });

That should add the element to the item list, update the widget and then pop. The timing between refresh and popping the dialog box is near instantaneous, so that should be smooth.

Furthermore, you might want to use ListView.builder, a class that will display a list that depends on the number of elements of the list of your choice.

With that said, changing the ListView to this could help in the future:

    child: ListView.builder(
      itemCount: item.length,
      itemBuilder: (context, index) {
        return Text('${item.index}'),
        },
    ),  

Upvotes: 1

Tipu Sultan
Tipu Sultan

Reputation: 1865

You should use await instate of then. And make item as class property. Your List is not updating because every time you called setState the build function rebuild and the value of item set to ['HI'] because of item=['HI'] this line.

Again when you use then function only the code inside of then function will execute when future will complete. That's why your setState called before your dialog finished.

Here I make some change of your code:

  List item = List();
  String temp;
  Future<String> createAlertDialog(BuildContext context) {
    //promise to return string
    TextEditingController customController =
        TextEditingController(); //new texteditingc object
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text("Enter URL: "),
            content: TextField(
              controller: customController,
            ),
            actions: [
              MaterialButton(
                elevation: 5.0,
                child: Text("OK"),
                onPressed: () {
                  Navigator.of(context).pop(customController.text.toString());
                },
              )
            ],
          );
        });
  }


  @override
  void initState() {
    item = ['HI'];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Shortie"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: ListView(
          children: item.map((element) => Text(element)).toList(),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          temp = await createAlertDialog(context);
          setState(() {
            item.add(temp);
            print(item);
          });
        },
        tooltip: 'Add URL',
        child: Icon(Icons.add),
      ),
    );
  }

Upvotes: 0

Related Questions