使用ViewModelProvider时如何从TextField获取文本值?

时间:2020-02-06 15:25:58

标签: flutter dart

我有一个表单(一堆TextField小部件),我从REST API获取数据,然后使用ViewModelProvider将其加载到视图中。 现在,我想按下按钮“保存”,获取TextField小部件的文本值,然后将数据传递给REST API。

我搜索了如何获取TextField的值以在其他地方使用它,发现的所有内容都与此类似:

class _MyCustomFormState extends State<MyCustomForm> {
  // Create a TextEditingController as a variable
  final myController = TextEditingController();
  @override
  void dispose() {
    myController.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Retrieve Text Input'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: TextField(
          // Set the created TextEditingController as the controller of the Text Field
          controller: myController, 
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          return showDialog(
            context: context,
            builder: (context) {
              return AlertDialog(
                // Use the text attribute of the TextEditingController variable
                content: Text(myController.text),
              );
            },
          );
        },
        tooltip: 'Show me the value!',
        child: Icon(Icons.text_fields),
      ),
    );
  }
}

(此代码段摘自Flutter website

我的问题是我使用ViewModelProvider,并且需要在内部创建TextEditingController ViewModelProvider的builder属性,用于设置从HTTP调用获取的文本。

这是我当前的代码,我只留下了一个TextField,因为它们实际上是相同的。

class SettingsView extends StatelessWidget {
  const SettingsView({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ViewModelProvider<SettingsViewModel>.withConsumer(
      viewModel: SettingsViewModel(),
      onModelReady: (model) => model.getSettings(),
      builder: (context, model, child) => Center(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              TextField(
                decoration: new InputDecoration(
                  labelText: 'Host',
                ),
                controller: TextEditingController.fromValue(
                  TextEditingValue(
                    text: model.settings == null? '' :model.settings.host,
                  ),
                ),
              ),
              GestureDetector(
                child: CallToAction("Save"),
                onTap: saveData,
              ),
            ],
          ),
        ),
      ),
    );
  }

  void saveData() {
  }
}

问题是,如何将TextField的文本值传递给saveData方法?

谢谢。

2 个答案:

答案 0 :(得分:0)

您是否要初始化TextEditingController?

如果是这样,则可以在onModelReady上初始化控件的文本,并在build外部声明控件。

class _SettingsViewState extends State<SettingsView> {
  TextEditingController myController = TextEditingController();
  @override
  Widget build(BuildContext context) {
    return ViewModelProvider<SettingsViewModel>.withConsumer(
      viewModel: SettingsViewModel(),
      onModelReady: (model) {
        myController.text =
            model.settings == null ? '' : model.settings.host;
        model.getSettings();
      },
      builder: (context, model, child) => Center(
        child: Column(
          children: <Widget>[
            Expanded(
              child: TextField(
                decoration: new InputDecoration(labelText: 'Host'),
                controller: myController,
              ),
            ),
            Expanded(
              child: GestureDetector(
                child: CallToAction("Save"),
                onTap: saveData,
              ),
            ),
          ],
        ),
      ),
    );
  }

  void saveData() {
    print('save data ${myController.text}');
  }
}

答案 1 :(得分:0)

感谢Thiago Dong Chen,我设法找到了解决我问题的方法。

Thiago建议我创建一个TextEditingController变量,并在onModelReady中设置其文本值,如下所示

onModelReady: (model) {
  myController.text = model.settings == null ? '' : model.settings.host;
  model.getSettings();
},

问题甚至出现在onModelReady中,model.settings仍然是null。但是他的解决方案使我走上了正确的道路。我是Flutter,Dart和匿名函数的新手。看到我可以将=>更改为更经典的{},使我意识到我可以在builder中做同样的事情,而不仅仅是设置窗口小部件树。

这是完整的代码:

class SettingsView extends StatefulWidget {
  const SettingsView({Key key}) : super(key: key);

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

class _SettingsViewState extends State<SettingsView> {
  TextEditingController _hostController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return ViewModelProvider<SettingsViewModel>.withConsumer(
      viewModel: SettingsViewModel(),
      onModelReady: (model) => model.getSettings(),
      builder: (context, model, child) {
        _hostController.text = model.settings == null ? null : model.settings.host;
        return Center(
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              TextField(
                decoration: new InputDecoration(
                  labelText: "Host",
                ),
                controller: _hostController,
                inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
              ),
              SizedBox(
                height: 30,
              ),
              GestureDetector(
                child: CallToAction("Save"),
                onTap: saveData,
              )
            ],
          ),
        ),
      );
        }
    );
  }

  void saveData() async{
    var _api = locator<Api>();
    bool b = await _api.setSettings(SettingItemModel(
        host: _hostController.text));
    String message = '';
    if (b) {
      message = 'Data saved to the database!';
    } else {
      message = 'Couldn\'t save the data';
    }
    final snackBar = SnackBar(content: Text(message));
    Scaffold.of(context).showSnackBar(snackBar);
  }
}