leodriesch
leodriesch

Reputation: 5780

Flutter TextField with controller resetting after TextInputType change

I'm using a fullscreen dialog in my app to make the user input values into text fields. Some of these values are Strings and some are ints. So I want to change the keyboard accordingly to make the unnecessary keys disappear. Here's my implementation:

import 'package:flutter/material.dart';
import 'package:meal_tracker/model/food_model.dart';

class AddFoodDialog extends StatelessWidget {
  TextEditingController nameController = TextEditingController(),
      carbsController = TextEditingController(),
      fatController = TextEditingController(),
      proteinController = TextEditingController(),
      amountController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Add Food"),
        actions: <Widget>[
          FlatButton(
            child: Text(
              "SAVE",
              style: TextStyle(color: Colors.white),
            ),
            onPressed: () {
              _handleSave(context);
            },
          )
        ],
      ),
      body: Form(
          child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: <Widget>[
            TextFormField(
              decoration: InputDecoration(labelText: "Name"),
              controller: nameController,
            ),
            TextFormField(
              decoration: InputDecoration(labelText: "Carbs per 100g"),
              controller: carbsController,
              keyboardType: TextInputType.number,
            ),
            TextFormField(
              decoration: InputDecoration(labelText: "Fat per 100g"),
              controller: fatController,
              keyboardType: TextInputType.number,
            ),
            TextFormField(
              decoration: InputDecoration(labelText: "Protein per 100g"),
              controller: proteinController,
              keyboardType: TextInputType.number,
            ),
            TextFormField(
              decoration: InputDecoration(labelText: "Amount in g"),
              controller: amountController,
              keyboardType: TextInputType.number,
            ),
          ],
        ),
      )),
    );
  }

  void _handleSave(BuildContext context) {
    print("Dialog text: " + nameController.text);
    Navigator.of(context).pop(Food(
        name: nameController.text,
        carbsPer100g: double.parse(carbsController.text),
        fatPer100g: double.parse(fatController.text),
        proteinPer100g: double.parse(proteinController.text),
        amount: double.parse(amountController.text)));
  }
}

The problem is that when I input something in the "Name" TextField, which has TextInputType.text and then tap into another one of the TextFields, which has TextInputType.number, the "Name" field clears out for no apparent reason. That also happens the other way around.

Upvotes: 15

Views: 19112

Answers (3)

PradeepKN
PradeepKN

Reputation: 657

TextFields value resets can happen due to 2 main reasons

  • Stateless Widget
  • Declaring property of TextEditingController as final.

If you want to handle states of any widget especially inside Dialogue (SimpleDialog) always create a separate StatefulWidget class and TextEditingController property as variable var.

Below is the complete example of Stateful widget which will not reset TextFields values on switching

class ReportDialog extends StatefulWidget {
  @override
  _ReportDialogState createState() => new _ReportDialogState();
}

class _ReportDialogState extends State<ReportDialog> {
  var selectedConfiguration = SharedConfiguration().selectedConfiguration;
  var titleTextField = TextEditingController();
  var descriptionTextField = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final reportButton = ReusableWidgets.getButton('REPORT',
        Colors.redAccent, Colors.white, reportButtonAction, context, 46);

    return SimpleDialog(
      contentPadding: EdgeInsets.fromLTRB(20, 10, 20, 10),
      children: <Widget>[
        new TextField(
          controller: titleTextField,
          decoration: new InputDecoration(
            border: new OutlineInputBorder(),
            hintText: 'Title',
          ),
          maxLines: 1,
        ),
        SizedBox(height: 8.0),
        new TextField(
          controller: descriptionTextField,
          decoration: new InputDecoration(
            border: new OutlineInputBorder(),
            hintText: 'Add your message here...',
            helperText: 'Keep it short, this is just a demo.',
          ),
          maxLines: 6,
        ),
        SizedBox(height: 20.0),
        reportButton
      ],
    );
  }

  void reportButtonAction() {
    Navigator.of(context).pop();
  }
}

Hope it is useful :)

Upvotes: 6

Andrew Chamamme
Andrew Chamamme

Reputation: 165

In your case you had to declare a StatefulWidget. A similar issue can be caused if the controllers are defined inside the build function

Upvotes: 7

leodriesch
leodriesch

Reputation: 5780

I had to put the TextEditingControllers inside a Stateful Widget, that did end up working. Thanks to Jonah Williams for the fast reply!

Upvotes: 19

Related Questions