如何正确使用GetX与TextField和一些服务器端验证?

福卡

我正在使用get软件包进行项目的状态管理。但是我对表单输入和验证的实现感到困惑,因为我在文档中找不到任何示例。我对此问题有一些疑问。

  1. 我应该为每个动作创建单独的控制器吗?喜欢PageOneControllerPageOneFormController
  2. 当状态改变时,如何防止父母重建孩子?
  3. 如何触发Model().obs对象内部数据添加的重建

正如我在上面第1点提到的那样,我发现使用单独的控制器有点重复和不必要,但是在离开子页面时,在多个位置使用相同的控制器会阻止我重置状态,因为控制器仅在离开时被销毁初始化状态的页面。为了避免我的解释造成任何混淆,请看下面的插图。

视觉解释

在第2点,我们知道TextField小部件接受errorText显示错误消息,而该错误消息仅接受字符串。考虑到这个包,当我尝试通过onChanged: (value) {}事件更改错误状态时,每次我在其中键入一个值时都会重新构建整个小部件,这会导致输入指示符停留在开始位置。

在这种情况下,第2点不再发生,但是现在它根本不会更新错误状态,即使我在上面输入了新值,它也始终显示错误消息。

请帮忙,这是我的脚本:

education_info_create_page.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:prismahrfinal/app/controllers/account_info/education_info_controller.dart';
import 'package:prismahrfinal/app/ui/widgets/form_input.dart';

class EducationInfoCreatePage extends GetWidget<EducationInfoController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            title: Text('Add Education Info'),
            floating: true,
          ),
          SliverToBoxAdapter(
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
              child: Column(
                children: <Widget>[
                  Obx(
                    () => FormInput(
                      autofocus: true,
                      label: 'Institution name',
                      focusNode: controller.institutionFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.institutionError,
                      onChanged: (value) {
                        controller.institutionError = null;
                        controller.institution = value;
                      },
                      onSubmitted: (_) {
                        controller.graduationMonthFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Graduation month',
                      focusNode: controller.graduationMonthFN,
                      keyboardType: TextInputType.number,
                      textInputAction: TextInputAction.next,
                      errorText: controller.graduationMonthError,
                      onChanged: (value) {
                        controller.graduationMonthError = null;
                        controller.graduationMonth = int.parse(value);
                      },
                      onSubmitted: (_) {
                        controller.graduationYearFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Graduation Year',
                      focusNode: controller.graduationYearFN,
                      keyboardType: TextInputType.number,
                      textInputAction: TextInputAction.next,
                      errorText: controller.graduationYearError,
                      onChanged: (value) {
                        controller.graduationYearError = null;
                        controller.graduationYear = int.parse(value);
                      },
                      onSubmitted: (_) {
                        controller.qualificationFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Qualification',
                      focusNode: controller.qualificationFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.qualificationError,
                      onChanged: (value) {
                        controller.qualificationError = null;
                        controller.qualification = value;
                      },
                      onSubmitted: (_) {
                        controller.locationFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Location',
                      focusNode: controller.locationFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.locationError,
                      onChanged: (value) {
                        controller.locationError = null;
                        controller.location = value;
                      },
                      onSubmitted: (_) {
                        controller.fieldOfStudyFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Field of study',
                      focusNode: controller.fieldOfStudyFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.fieldOfStudyError,
                      onChanged: (value) {
                        controller.fieldOfStudyError = null;
                        controller.fieldOfStudy = value;
                      },
                      onSubmitted: (_) {
                        controller.majorsFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Majors',
                      focusNode: controller.majorsFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.majorsError,
                      onChanged: (value) {
                        controller.majorsError = null;
                        controller.majors = value;
                      },
                      onSubmitted: (_) {
                        controller.finalScoreFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Final Score',
                      focusNode: controller.finalScoreFN,
                      keyboardType: TextInputType.text,
                      textInputAction: TextInputAction.next,
                      errorText: controller.finalScoreError,
                      onChanged: (value) {
                        controller.finalScoreError = null;
                        controller.finalScore = double.parse(value);
                      },
                      onSubmitted: (_) {
                        controller.additionalInfoFN.requestFocus();
                      },
                    ),
                  ),
                  Obx(
                    () => FormInput(
                      label: 'Additional Info (optional)',
                      focusNode: controller.additionalInfoFN,
                      keyboardType: TextInputType.multiline,
                      maxLines: 5,
                      textInputAction: TextInputAction.go,
                      errorText: controller.additionalInfoError,
                      onChanged: (value) {
                        controller.additionalInfoError = null;
                        controller.additionalInfo = value;
                      },
                      onSubmitted: (_) {
                        controller.add();
                      },
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.send, color: Colors.white),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
        backgroundColor: Theme.of(context).primaryColor,
        tooltip: 'Add Education Info',
        onPressed: controller.add,
      ),
    );
  }
}

education_info_controller.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:meta/meta.dart';
import 'package:pretty_json/pretty_json.dart';
import 'package:prismahrfinal/app/data/models/account_info/education_info.dart';
import 'package:prismahrfinal/app/data/models/account_info/education_info_error.dart';
import 'package:prismahrfinal/app/data/repositories/account_info/education_info_repository.dart';

class EducationInfoController extends GetxController {
  EducationInfoController({@required this.repository})
      : assert(repository != null);

  final EducationInfoRepository repository;
  final FocusNode _institutionFN = FocusNode();
  final FocusNode _graduationMonthFN = FocusNode();
  final FocusNode _graduationYearFN = FocusNode();
  final FocusNode _qualificationFN = FocusNode();
  final FocusNode _locationFN = FocusNode();
  final FocusNode _fieldOfStudyFN = FocusNode();
  final FocusNode _majorsFN = FocusNode();
  final FocusNode _finalScoreFN = FocusNode();
  final FocusNode _additionalInfoFN = FocusNode();

  final Rx<ListEducationInfo> data = ListEducationInfo().obs;
  final Rx<EducationInfo> education = EducationInfo().obs;
  final Rx<EducationInfoError> errors = EducationInfoError().obs;

  @override
  void onInit() => fetchDataFromApi();

  void fetchDataFromApi() async {
    data.value = await repository.getData();
    if (data.value == null) {
      Get.snackbar("Error", "Can't connect to server");
    }
  }

  void add() async {
    this._unfocus();
    debugPrint(prettyJson(education.value.toJson()));

    final response = await repository.add(education.value.toJson());
    if (response == null) {
      Get.snackbar("Error", "Can't connect to server");
      return;
    } else if (response is EducationInfoError) {
      errors.value = response;
      return;
    }

    data.value.educations.add(response);
  }

  void _unfocus() {
    this.institutionFN.unfocus();
    this.graduationMonthFN.unfocus();
    this.graduationYearFN.unfocus();
    this.qualificationFN.unfocus();
    this.locationFN.unfocus();
    this.fieldOfStudyFN.unfocus();
    this.majorsFN.unfocus();
    this.finalScoreFN.unfocus();
    this.additionalInfoFN.unfocus();
  }

  // Getters -- Focus Nodes
  get institutionFN => this._institutionFN;
  get graduationMonthFN => this._graduationMonthFN;
  get graduationYearFN => this._graduationYearFN;
  get qualificationFN => this._qualificationFN;
  get locationFN => this._locationFN;
  get fieldOfStudyFN => this._fieldOfStudyFN;
  get majorsFN => this._majorsFN;
  get finalScoreFN => this._finalScoreFN;
  get additionalInfoFN => this._additionalInfoFN;

  // Getters -- Values
  get institution => this.education.value.institution;
  get graduationMonth => this.education.value.graduationMonth;
  get graduationYear => this.education.value.graduationYear;
  get qualification => this.education.value.qualification;
  get location => this.education.value.location;
  get fieldOfStudy => this.education.value.fieldOfStudy;
  get majors => this.education.value.majors;
  get finalScore => this.education.value.finalScore;
  get additionalInfo => this.education.value.additionalInfo;

  // Getters -- Errors
  get institutionError => this.errors.value.institution?.first;
  get graduationMonthError => this.errors.value.graduationMonth?.first;
  get graduationYearError => this.errors.value.graduationYear?.first;
  get qualificationError => this.errors.value.qualification?.first;
  get locationError => this.errors.value.location?.first;
  get fieldOfStudyError => this.errors.value.fieldOfStudy?.first;
  get majorsError => this.errors.value.majors?.first;
  get finalScoreError => this.errors.value.finalScore?.first;
  get additionalInfoError => this.errors.value.additionalInfo?.first;

  // Setters -- Values
  set institution(value) => this.education.value.institution = value;
  set graduationMonth(value) => this.education.value.graduationMonth = value;
  set graduationYear(value) => this.education.value.graduationYear = value;
  set qualification(value) => this.education.value.qualification = value;
  set location(value) => this.education.value.location = value;
  set fieldOfStudy(value) => this.education.value.fieldOfStudy = value;
  set majors(value) => this.education.value.majors = value;
  set finalScore(value) => this.education.value.finalScore = value;
  set additionalInfo(value) => this.education.value.additionalInfo = value;

  // Setters -- Errors
  set institutionError(value) => this.errors.value.institution = value;
  set graduationMonthError(value) => this.errors.value.graduationMonth = value;
  set graduationYearError(value) => this.errors.value.graduationYear = value;
  set qualificationError(value) => this.errors.value.qualification = value;
  set locationError(value) => this.errors.value.location = value;
  set fieldOfStudyError(value) => this.errors.value.fieldOfStudy = value;
  set majorsError(value) => this.errors.value.majors = value;
  set finalScoreError(value) => this.errors.value.finalScore = value;
  set additionalInfoError(value) => this.errors.value.additionalInfo = value;
}

app_pages.dart

import 'package:get/get.dart';
import 'package:prismahrfinal/app/bindings/education_info_binding.dart';
import 'package:prismahrfinal/app/bindings/employment_info_binding.dart';
import 'package:prismahrfinal/app/bindings/personal_info_binding.dart';
import 'package:prismahrfinal/app/ui/android/account_info/education_info/education_info.dart';
import 'package:prismahrfinal/app/ui/android/account_info/education_info/education_info_create.dart';
import 'package:prismahrfinal/app/ui/android/account_info/employment_info/employment_info.dart';
import 'package:prismahrfinal/app/ui/android/account_info/personal_info/personal_info.dart';
import 'package:prismahrfinal/app/ui/android/account_info/personal_info/personal_info_edit.dart';
import 'package:prismahrfinal/app/ui/android/home.dart';
import 'package:prismahrfinal/app/ui/android/login.dart';
import 'package:prismahrfinal/app/ui/android/account_info.dart';
part './app_routes.dart';

abstract class AppPages {
  static final pages = [
    GetPage(
      name: Routes.EDUCATION_INFO,
      page: () => EducationInfoPage(),
      binding: EducationInfoBinding(),
    ),
    GetPage(
      name: Routes.EDUCATION_INFO_CREATE,
      page: () => EducationInfoCreatePage(),
    ),
  ];
}
嘉泰科

问题1-在我看来,每个屏幕都需要一个控制器。因此,您要创建的每个屏幕都需要创建一个控制器。如果需要在屏幕之间传递数据,则需要使用Get.arguments来捕获路线之间的参数。要通过,您只需通过大声笑。

Get.toNamed(yourRoute, arguments: yourArgument);

问题2-每次更新列表错误时,所有观察者都会观察更新。

  // Getters -- Errors
  get institutionError => this.errors.value.institution?.first;
  get graduationMonthError => this.errors.value.graduationMonth?.first;
  get graduationYearError => this.errors.value.graduationYear?.first;
  get qualificationError => this.errors.value.qualification?.first;
  get locationError => this.errors.value.location?.first;
  get fieldOfStudyError => this.errors.value.fieldOfStudy?.first;
  get majorsError => this.errors.value.majors?.first;
  get finalScoreError => this.errors.value.finalScore?.first;
  get additionalInfoError => this.errors.value.additionalInfo?.first;

这就是所有小部件都在重建的原因。

问题3-您可以使用update方法在模型上触发反应。

use model.update((model){
   model.email = 'foo@bar'
});

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章