Как передать функцию в качестве средства проверки в поле текстовой формы?

#flutter #validation #dart #textformfield

Вопрос:

Мне интересно, могу ли я передать функцию в качестве валидатора. Я пытался, но безрезультатно.

   Widget Field(String changedValue, String label, bool isTextObscured) {
    return TextFormField(
      decoration: InputDecoration(labelText: label),
      validator: checkFieldEmpty,
    );
  }

  checkFieldEmpty(String fieldContent) {
    if(fieldContent.isEmpty) {
      return 'Ce champ est obligatoire.';
    }
    return null;
  }
 

Комментарии:

1. Да, вы можете, но fieldContent должны быть аннулированы. Заменить String на String? . Кроме того, укажите тип возвращаемой checkFieldEmpty функции String? , как указано в ответах ниже.

Ответ №1:

Возможно, тип возврата функции должен быть String? таким, чтобы он соответствовал прототипу валидатора!

   Widget Field(String changedValue, String label, bool isTextObscured) {
    return TextFormField(
      decoration: InputDecoration(labelText: label),
      validator: checkFieldEmpty,
    );
  }

 String? checkFieldEmpty(String? fieldContent) { //<-- add String? as a return type
    if(fieldContent.isEmpty) {
      return 'Ce champ est obligatoire.';
    }
    return null;
  }
 

Более подходящий способ сделать это в Flutter

Помните, что flutter-это декларативный язык. То есть вы создаете свое приложение, составляя дерево виджетов. Здесь вы используете функцию для возврата виджета. Это нарушает это правило. Вместо этого вы должны объявить свой собственный пользовательский виджет, который реализует TextField виджет. Вот как:

1. Объявите свой пользовательский виджет

 // Declare your CustomTextField as a Stateless/Stateful Widget
class MyCustomTextField extends StatelessWidget {
  // Declare your custom vars, including your validator function
  final String? changedValue; 
  final String? label; 
  final bool? isTextObscured;
  final String? Function(String?)? validator;

  const MyCustomTextField({
    Key? key, 
    this.changedValue, 
    this.label,
    this.isTextObscured,
    this.validator,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      decoration: InputDecoration(labelText: label),
      validator: validator,
    );
  }
}
 

2. Используйте свой собственный виджет

Теперь вы можете использовать этот пользовательский виджет в качестве дочернего элемента любого другого виджета:

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

  // This is your custom validator function and can leave
  // anywhere ;)
  Stirng? customValidtaor(String? fieldContent) => fieldContent.isEmpty? 'Ce champ est obligatoire.': null

  @override
  Widget build(BuildContext context) {
    return MyCustomTextField(
      label: 'Some label'
      // declare the validator here...
      // valiator: (fieldContent) => fieldContent.isEmpty? 'Ce champ est obligatoire.': null
      // or use your custom validator function
      validator: customValidator,
    );
  }
}
 

Делая это, вы уважаете лучшие практики Flutter, используя композицию виджетов 😉

Комментарии:

1. Я боюсь, что это все еще не работает… «Тип аргумента ‘Строка? Функция(строка)’ не может быть присвоена типу параметра ‘Строка? Функция(строка?)?’.»

2. да, просто обновите функцию: String? function(String? fieldContent){/*...*/} извините, что я пропустил тип аргумента. Я соответствующим образом обновил свой ответ 😉

Ответ №2:

Добавьте строку в качестве типа возврата для метода checkFieldEmpty (), см. Ниже

вместо этого это:

 checkFieldEmpty(String fieldContent) {}
 

используйте это:

 String checkFieldEmpty(String fieldContent) {}
 

Полный Пример Кода:

 import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appTitle = 'Form Validation Demo';

    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(title: Text(appTitle)),
        body: MyCustomForm(),
      ),
    );
  }
}

// Create a Form widget.
class MyCustomForm extends StatefulWidget {
  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
  // Create a global key that uniquely identifies the Form widget
  // and allows validation of the form.
  //
  // Note: This is a GlobalKey<FormState>,
  // not a GlobalKey<MyCustomFormState>.
  final _formKey = GlobalKey<FormState>();

  Widget textField(String changedValue, String label, bool isTextObscured) {
    return TextFormField(
      decoration: InputDecoration(labelText: label),
      validator: checkFieldEmpty,
    );
  }

  String checkFieldEmpty(String fieldContent) {
    if (fieldContent.isEmpty) return 'Ce champ est obligatoire.';
    return null;
  }

  @override
  Widget build(BuildContext context) {
    // Build a Form widget using the _formKey created above.
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          textField('changedValue', 'Enter Password', false),
          ElevatedButton(
            onPressed: () {
              // Validate returns true if the form is valid, or false otherwise.
              if (_formKey.currentState.validate()) {
                // If the form is valid,
                // perform further actions here
              }
            },
            child: Text('Submit'),
          ),
        ],
      ),
    );
  }
}