如何在Stepper中验证每个表单步骤

时间:2020-04-16 10:47:26

标签: flutter dart

我正在尝试在步进器的每个步骤中验证表单。我正在从地图上为步进创建列表。问题是,如果我为每一步添加表单,都会出错

多个小部件使用了相同的GlobalKey。

如何为每个表单动态创建新密钥

  List<Step> stepList() {
    List<Step> _steps = [];
    list.forEach((k, v) => _steps.add(Step(
          title: Text(k),
          content: Column(
            children: v.map<Widget>((child) {
              return Form(key: _formKey, child: child);
            }).toList(),
          ),
        )));
    return _steps;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stepper(
        onStepContinue: next,
        currentStep: current,
        onStepCancel: cancel,
        steps: stepList(),
      ),
    );
  }

这里是完整的复制粘贴代码...也尝试动态创建新密钥

class _MaterialScreenState extends State<MaterialScreen> {
  int current = 0;
  bool complete = false;

  //final _formKey = GlobalKey<FormState>();

  List<GlobalKey<FormState>> _getFormKeys() {  //attempt to create list of Form keys for each step 
    List<GlobalKey<FormState>> l = [];
    keyList().forEach((v) => l.add(GlobalKey<FormState>()));
    return l;
  }

  goTo(int step) {
    setState(() => current = step);
  }

  bool _validate() { // this method is called on null
    final form = _getFormKeys()[current].currentState;
    if (form.validate()) {
      return true;
    }
    return false;
  }

  next() {
    bool validated = _validate();
    print(validated);
    if (complete == false) {
      if (current + 1 != list.length && validated) {
        goTo(current + 1);
      }
      if (current + 1 == list.length) {
        setState(() {
          complete = true;
        });
      }
    } else {
      print('saved');
    }
  }

  cancel() {
    if (current > 0) {
      goTo(current - 1);
    }
  }

  List<String> keyList() {
    List<String> l = [];
    list.forEach((k, v) {
      l.add(k);
    });
    return l;
  }

  Map<String, List<Widget>> list = {
    'Step1': [
      TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')
    ],
    'Step2': [
      TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')
    ],
    'Step3': [TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')]
  };

  List<Step> stepList() {
    List<Step> _steps = [];
    list.forEach((k, v) => _steps.add(Step(
          title: Text(k),
          content: Column(
            children: v.map<Widget>((child) {
              return Form(
                  key: _getFormKeys()[keyList().indexOf(k)], child: child);
            }).toList(),
          ),
        )));
    return _steps;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stepper(
        onStepContinue: next,
        currentStep: current,
        onStepCancel: cancel,
        steps: stepList(),
      ),
    );
  }
}

2 个答案:

答案 0 :(得分:1)

感谢@pskink,问题得到了答案

这是完整的代码,如何验证步进机中的每个表单步骤

class MaterialScreen extends StatefulWidget {
  @override
  _MaterialScreenState createState() => _MaterialScreenState();
}

class _MaterialScreenState extends State<MaterialScreen> {
  Map<String, List<Widget>> list = {
    'Step1': [TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')],
    'Step2': [TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')],
    'Step3': [TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')],
  };
  Map steps;

  @override
  void initState() { 
    super.initState();
    steps = list.map<GlobalKey, Step>(_makeStep);
  }

  MapEntry<GlobalKey, Step> _makeStep(k, v) {
    var key = GlobalKey();
    var step = Step(
      title: Text(k),
      content: Form(key: key, child: Column(children: v,),),
    );
    return MapEntry(key, step);
  }

  int current = 0;
  bool complete = false;

  goTo(int step) {
    setState(() => current = step);
  }

  bool _validate() {
    final form = steps.keys.elementAt(current).currentState;
    return form.validate();
  }

  next() {
    bool validated = _validate();
    print(validated);
    if (complete == false) {
      if (current + 1 != list.length && validated) {
        goTo(current + 1);
      }
      if (current + 1 == list.length) {
        setState(() {
          complete = true;
        });
      }
    } else {
      print('saved');
    }
  }

  cancel() {
    if (current > 0) {
      goTo(current - 1);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stepper(
        onStepContinue: next,
        currentStep: current,
        onStepCancel: cancel,
        steps: steps.values.toList(),
      ),
    );
  }
}

答案 1 :(得分:1)

之所以不起作用,并且您的validate方法被调用为null的原因是因为每次调用它时,都在_getFormKeys()方法中创建了brad new GlobalKey。您要做的就是在initState中初始化globalKey列表,然后在进行操作时使用它们

class _MaterialScreenState extends State<MaterialScreen> {
  int current = 0;
  bool complete = false;
  List<GlobalKey<FormState>> _formKeyList = []; //<- create variable for the list

  Map<String, List<Widget>> list = {
    'Step1': [
      TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')
    ],
    'Step2': [
      TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')
    ],
    'Step3': [TextFormField(validator: (s) => s.isNotEmpty ? null : 'Required')]
  };

  void initState() {
    list.forEach((k, v) {
      _formKeyList.add(GlobalKey<FormState>()); //<-- initialise it here
    });
    super.initState();
  }

  goTo(int step) {
    setState(() => current = step);
  }

  bool _validate() {
    // this method is called on null
    final form = _formKeyList[current].currentState;
    if (form.validate()) {
      return true;
    }
    return false;
  }

  next() {
    bool validated = _validate();
    print(validated);
    if (complete == false) {
      if (current + 1 != list.length && validated) {
        goTo(current + 1);
      }
      if (current + 1 == list.length) {
        setState(() {
          complete = true;
        });
      }
    } else {
      print('saved');
    }
  }

  cancel() {
    if (current > 0) {
      goTo(current - 1);
    }
  }

  List<String> keyList() {
    List<String> l = [];
    list.forEach((k, v) {
      l.add(k);
    });
    return l;
  }

  List<Step> stepList() {
    List<Step> _steps = [];
    list.forEach((k, v) => _steps.add(Step(
          title: Text(k),
          content: Column(
            children: v.map<Widget>((child) {
              return Form(
                  key: _formKeyList[keyList().indexOf(k)], child: child);
            }).toList(),
          ),
        )));
    return _steps;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stepper(
        onStepContinue: next,
        currentStep: current,
        onStepCancel: cancel,
        steps: stepList(),
      ),
    );
  }
}