التحقق من الصحة باستخدام GlobalKey <FormState> في الخطوات الفردية لعنصر واجهة مستخدم Flutter Stepper يقوم بإرجاع false حتى للإدخال الصحيح

0

أنا أستخدم عنصر واجهة مستخدم السائر ، وأستخدم عنصر واجهة مستخدم نموذج في كل خطوة من خطوات السائر بمفاتيح نموذج مختلفة للتحقق من صحة كل خطوة ... المشكلة هي this._formKey.currentState.validate() دائمًا ما تُرجع خطأ حتى إذا استوفت معايير التحقق للخطوة الحالية ... فيما يلي هو الرمز الذي أستخدمه لبناء خطوات فردية في السائر:

  Widget _buildCustomerInfoWidget() {
    return Form(
        key: _formKey,
        child: Column(
          children: <Widget>[
            CustomTextField(
              focusNode: _focusNodeID,
              hintText: Translations.of(context).cnic,
              labelText: Translations.of(context).cnic,
              controller: _controllerIdentifier,
              keyboardType: TextInputType.number,
              hasError: _isIdentifierRequired,
              validator: (String t) => _validateIdentifier(t),
              maxLength: 13,
            ),
            CustomTextField(
              focusNode: _focusNodeAmount,
              hintText: Translations.of(context).amount,
              labelText: Translations.of(context).amount,
              controller: _controllerAmount,
              keyboardType: TextInputType.number,
              hasError: _isAmountRequired,
              validator: (String t) => _validateAmount(t),
              maxLength: 6,
            ),
          ],
        ));
  }

  Widget _buildCustomerVerificationWidget() {
    return Form(
        key: _formKeyOTP,
        child: Column(
          children: <Widget>[
            Center(
                child: Padding(
                    padding:
                        EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
                    child: Text(
                      Translations.of(context).helpLabelOTP,
                      style: new TextStyle(
                          color: Theme.of(context).primaryColor,
                          fontStyle: FontStyle.italic),
                    ))),
            CustomTextField(
              focusNode: _focusNodeOTP,
              hintText: Translations.of(context).otp,
              labelText: Translations.of(context).otp,
              controller: _controllerOTP,
              keyboardType: TextInputType.number,
              hasError: _isAmountRequired,
              validator: (String t) => _validateOTP(t),
              maxLength: 4,
              obscureText: true,
            ),
          ],
        ));
  }

  List<Step> _buildStepperSteps(BuildContext context) {
    List<Step> paymentSteps = [
      Step(
          title: Text(
            Translations.of(context).infoStepLabel,
          ),
          content: _buildCustomerInfoWidget(),
          state: StepState.indexed,
          isActive: _isStepActive),
      Step(
          title: Text(Translations.of(context).submitStepLabel),
          state: StepState.indexed,
          content: _buildCustomerVerificationWidget(),
          isActive: !_isStepActive),
    ];

    return paymentSteps;
  }

كود كامل كمرجع:

class PullPaymentPage extends StatefulWidget {
  PullPaymentPage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  State<StatefulWidget> createState() {
    return PullPaymentState();
  }
}

class PullPaymentState extends State<PullPaymentPage> {
  final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
  final GlobalKey<FormState> _formKeyOTP = new GlobalKey<FormState>();
  final TextEditingController _controllerIdentifier =
      new TextEditingController();
  final FocusNode _focusNodeOTP = new FocusNode();
  final FocusNode _focusNodeID = new FocusNode();
  final FocusNode _focusNodeAmount = new FocusNode();
  final TextEditingController _controllerAmount = new TextEditingController();
  final TextEditingController _controllerOTP = new TextEditingController();

  bool _isIdentifierRequired = false;
  bool _isAmountRequired = false;
  bool _isOTPRequired = false;
  bool _isStepActive = true;
  int _currentStep = 0;


  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: _buildAppBar(context),
        body: new Builder(builder: (BuildContext context) {
          return Container(child: _buildStepper(context));
        }));
  }

  Stepper _buildStepper(BuildContext context) {
    final Map functionMap = {0: _sendOTP, 1: _pullPayment};

    List<Step> paymentSteps = _buildStepperSteps(context);

    return Stepper(
      steps: paymentSteps,
      type: StepperType.vertical,
      currentStep: this._currentStep,
      onStepTapped: (step) {
        setState(() {
          if (step != 1) {
            _currentStep = step;
          }
          (_currentStep == 0) ? _isStepActive = true : _isStepActive = false;
        });
      },
      onStepContinue: () {
        functionMap[_currentStep]().then((value) {
          if (value == true) {
            setState(() {
              _currentStep++;
            });
            if (_currentStep == 1) {
              Scaffold.of(context).showSnackBar(SnackBar(
                    content: Text(Translations.of(context).otpSuccess),
                    duration: Duration(seconds: 4),
                  ));
            }
          }
        });
      },
      onStepCancel: () {
        setState(() {
          _currentStep == 0 ? Navigator.of(context).pop() : stepBack();
        });
      },
    );
  }

  void stepBack() {
    _isStepActive = true;
    _currentStep--;
  }

  Map<int, Function> createFunctionMap() {
    Map functionMap = {1: _sendOTP(), 2: _pullPayment()};
    return functionMap;
  }

  AppBar _buildAppBar(BuildContext context) {
    return AppBar(
      title: Text(
        Translations.of(context).pullPayment,
      ),
      backgroundColor: Theme.of(context).primaryColorDark,
      leading: new BackButton(),
    );
  }

  Widget _buildCustomerInfoWidget() {
    return Form(
        key: _formKey,
        child: Column(
          children: <Widget>[
            CustomTextField(
              focusNode: _focusNodeID,
              hintText: Translations.of(context).cnic,
              labelText: Translations.of(context).cnic,
              controller: _controllerIdentifier,
              keyboardType: TextInputType.number,
              hasError: _isIdentifierRequired,
              validator: (String t) => _validateIdentifier(t),
              maxLength: 13,
            ),
            CustomTextField(
              focusNode: _focusNodeAmount,
              hintText: Translations.of(context).amount,
              labelText: Translations.of(context).amount,
              controller: _controllerAmount,
              keyboardType: TextInputType.number,
              hasError: _isAmountRequired,
              validator: (String t) => _validateAmount(t),
              maxLength: 6,
            ),
          ],
        ));
  }

  Widget _buildCustomerVerificationWidget() {
    return Form(
        key: _formKeyOTP,
        child: Column(
          children: <Widget>[
            Center(
                child: Padding(
                    padding:
                        EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
                    child: Text(
                      Translations.of(context).helpLabelOTP,
                      style: new TextStyle(
                          color: Theme.of(context).primaryColor,
                          fontStyle: FontStyle.italic),
                    ))),
            CustomTextField(
              focusNode: _focusNodeOTP,
              hintText: Translations.of(context).otp,
              labelText: Translations.of(context).otp,
              controller: _controllerOTP,
              keyboardType: TextInputType.number,
              hasError: _isAmountRequired,
              validator: (String t) => _validateOTP(t),
              maxLength: 4,
              obscureText: true,
            ),
          ],
        ));
  }

  List<Step> _buildStepperSteps(BuildContext context) {
    List<Step> paymentSteps = [
      Step(
          title: Text(
            Translations.of(context).infoStepLabel,
          ),
          content: _buildCustomerInfoWidget(),
          state: StepState.indexed,
          isActive: _isStepActive),
      Step(
          title: Text(Translations.of(context).submitStepLabel),do
          state: StepState.indexed,
          content: _buildCustomerVerificationWidget(),
          isActive: !_isStepActive),
    ];

    return paymentSteps;
  }

  String _validateIdentifier(String value) {
    if (value.isEmpty || value.length < 11 || value.length > 13) {
      setState(() => _isIdentifierRequired = true);
      return Translations.of(context).invalidInput;
    }
    return "";
  }

  String _validateAmount(String value) {
    if (value.isEmpty) {
      setState(() => _isAmountRequired = true);
      return Translations.of(context).amountRequiredError;
    } else if (!RegexHelpers.amountValidatorRegex.hasMatch(value)) {
      return Translations.of(context).validAmountError;
    }
    return "";
  }

  String _validateOTP(String value) {
    if (value.isEmpty || value.length < 4) {
      setState(() => _isOTPRequired = true);
      return Translations.of(context).invalidOtp;
    }
    return "";
  }

  bool _validateInfoForm() {
    _isOTPRequired = false;
    _isAmountRequired = false;
    _isIdentifierRequired = false;

    if (!this._formKey.currentState.validate()) {
      return false;
    }
    _formKey.currentState.save();
    return true;
  }

  bool _validateOtpForm() {
    _isOTPRequired = false;
    _isAmountRequired = false;
    _isIdentifierRequired = false;

    if (!this._formKeyOTP.currentState.validate()) {
      return false;
    }
    _formKeyOTP.currentState.save();
    return true;
  }

  Future<bool> _sendOTP() async {
    bool sendOTP = false;
    setState(() {
      _isIdentifierRequired = false;
      _isAmountRequired = false;
      _isOTPRequired = false;
    });

    if (!_validateInfoForm()) {
      setState(() {
        _validateAmount(_controllerAmount.text);
        _validateIdentifier(_controllerIdentifier.text);
      });

      if (_validateAmount(_controllerAmount.text).isNotEmpty ||
          _validateIdentifier(_controllerIdentifier.text).isNotEmpty) {
        return false;
      }
    }
    try {
      showDialog(
        barrierDismissible: false,
        context: context,
        builder: (context) => AlertDialog(
              content: ListTile(
                leading: CircularProgressIndicator(),
                title: Text(Translations.of(context).processingSendOtpDialog),
              ),
            ),
      );

      TransactionApi api =
          new TransactionApi(httpDataSource, authenticator.sessionToken);
      sendOTP = await api.sendOTP(_controllerIdentifier.text);

      if (sendOTP) {
        _isStepActive = false;
        _controllerOTP.clear();
      }

      Navigator.of(context).pop();
    } catch (exception) {
      await showAlertDialog(context, Translations.of(context).pullPayment,
          '${exception.message}');
      Navigator.of(context).pop();
      return false;
    }

    return sendOTP;
  }

  Future<bool> _pullPayment() async {
    Result pullPaymentResponse = new Result();
    setState(() {
      _isIdentifierRequired = false;
      _isAmountRequired = false;
      _isOTPRequired = false;
    });

    if (!_validateOtpForm()) {
      setState(() {
        _validateOTP(_controllerAmount.text);
      });

      if (_validateAmount(_controllerAmount.text).isNotEmpty ||
          _validateIdentifier(_controllerIdentifier.text).isNotEmpty ||
          _validateOTP(_controllerOTP.text).isNotEmpty) {
        return false;
      }
    }

    try {
      setState(() {
        _isOTPRequired = false;
      });
      showDialog(
        barrierDismissible: false,
        context: context,
        builder: (context) => AlertDialog(
              content: ListTile(
                leading: CircularProgressIndicator(),
                title: Text(Translations.of(context).processingPaymentDialog),
              ),
            ),
      );

      TransactionApi api =
          new TransactionApi(httpDataSource, authenticator.sessionToken);
      pullPaymentResponse = await api.pullPayment(_controllerIdentifier.text,
          _controllerAmount.text, _controllerOTP.text);

      Navigator.of(context).pop();
    } catch (exception) {
      await showAlertDialog(context, Translations.of(context).pullPayment,
          '${exception.message}');
      Navigator.of(context).pop();
      return false;
    }

    if (successResponseCodes.contains(pullPaymentResponse.responseCode)) {
      await showAlertDialog(context, Translations.of(context).pullPayment,
          '${pullPaymentResponse.description}');
      Navigator.pop(context);
      return true;
    }
    return false;
  }
}

1 إجابة

-2
افضل جواب

يعلن أولا أ bool متغير.

 bool _autoValidate = false;

ثم استخدم هذا المنطقي في خاصية التحقق التلقائي من النموذج الخاص بك. كما هو مذكور ادناه

Form(
    key: _formKey,
    autovalidate: _autoValidate,
    child: Column(
      children: <Widget>[
        CustomTextField(
          focusNode: _focusNodeID,
          hintText: Translations.of(context).cnic,
          labelText: Translations.of(context).cnic,
          controller: _controllerIdentifier,
          keyboardType: TextInputType.number,
          hasError: _isIdentifierRequired,
          validator:  _validateIdentifier,
          maxLength: 13,
        ),
        CustomTextField(
          focusNode: _focusNodeAmount,
          hintText: Translations.of(context).amount,
          labelText: Translations.of(context).amount,
          controller: _controllerAmount,
          keyboardType: TextInputType.number,
          hasError: _isAmountRequired,
          validator: (String t) => _validateAmount(t),
          maxLength: 6,
        ),
      ],
    ));

الآن كلما أردت التحقق من صحة الحقول استدعاء هذه الوظيفة.

setState(() {
      _autoValidate = true;
    });

سيؤدي هذا إلى التحقق تلقائيًا من جميع الحقول في النموذج التي تحتوي على وظيفة مدقق.

ووظائف المدقق الخاصة بك تذهب هكذا.

String _validateIdentifier(String value) {
if (value.isEmpty || value.length < 11 || value.length > 13) {
  setState(() => _isIdentifierRequired = true);
  return Translations.of(context).invalidInput;
}
return null;

}}

:مؤلف

أسئلة ذات صلة

فوق
قائمة طعام