Antd选择表单项键盘行为问题 [英] Antd Select form item keyboard behavior problem

查看:115
本文介绍了Antd选择表单项键盘行为问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的表格在大多数情况下都可以正常工作.但令我感到困扰的是选择项,它可以估算一个人的状态(请参见下面的屏幕截图).用鼠标可以很好地工作,但是如果您要在表单和选项卡之间切换至州"字段,然后为加利福尼亚键入"CA"之类的州,然后再切换至下一个字段(邮政编码),则州"字段将重置为空白.如果它与选择器的选项之一匹配,我希望它保持CA.

如果我键入"CA"并按Enter键进入下一个字段,它确实有效,但是对于表格的正常工作方式似乎并不直观.如果我仅使用鼠标来选择该字段,它也将起作用.我一直在查看Select上的antd文档,看不到有什么东西可以控制我.也许我缺少了某些东西,我需要执行某种onchange函数吗?

无论如何,这似乎是一个相当简单的问题,但解决方案使我难以理解.

选择表单项的代码:

 <代码>< Form.Item name = {[field.name,"state"]} fieldKey = {[[field.fieldKey,"state"]}规则= {规则}><选择showSearchplaceholder ="State"defaultActiveFirstOption = {true}>< Option value ="AL"> AL</Option>< Option value ="AK"> AK</Option>< Option value ="AZ"> AZ</Option>< Option value ="AR"> AR</Option>< Option value ="CA"> CA</Option>< Option value ="CO"> CO</Option>< Option value ="CT"> CT</Option>< Option value ="DE"> DE</Option>< Option value ="FL"> FL</Option>< Option value ="GL"> GA</Option>< Option value ="HI"> HI</Option>< Option value ="ID"> ID</Option>< Option value ="IL"> IL</Option>< Option value ="IN"> IN</Option>< Option value ="IA"> IA</Option>< Option value ="KS"> KS</Option>< Option value ="KY"> KY</Option>< Option value ="LA"> LA</Option>< Option value ="ME"> ME</Option>< Option value ="MD"> MD</Option>< Option value ="MA"> MA</Option>< Option value ="MI"> MI</Option>< Option value ="MN"> MN</Option>< Option value ="MS"> MS</Option>< Option value ="MO"> MO</Option>< Option value ="MT"> MT</Option>< Option value ="NE"> NE</Option>< Option value ="NV"> NV</Option>< Option value ="NH"> NH</Option>< Option value ="NJ"> NJ</Option>< Option value ="NM"> NM</Option>< Option value ="NY"> NY</Option>< Option value ="NC"> NC</Option>< Option value ="ND"> ND</Option>< Option value ="OH"> OH</Option>< Option value ="OK"> OK</Option>< Option value ="OR"> OR</Option>< Option value ="PA"> PA</Option>< Option value ="RI"> RI</Option>< Option value ="SC"> SC</Option>< Option value ="SD"> SD</Option>< Option value ="TN"> TN</Option>< Option value ="TX"> TX</Option>< Option value ="UT"> UT</Option>< Option value ="VT"> VT</Option>< Option value ="VA"> VA</Option>< Option value ="WA"> WA</Option>< Option value ="WV"> WV</Option>< Option value ="WI"> WI</Option>< Option value ="WY"> WY</Option>< Option value ="AS"> AS</Option>< Option value ="DC"> DC</Option>< Option value ="FM"> FM</Option>< Option value ="GU"> GU</Option>< Option value ="MH"> MH</Option>< Option value ="MP"> MP</Option>< Option value ="PW"> PW</Option>< Option value ="PR"> PR</Option>< Option value ="VI"> VI</Option></选择></Form.Item> 

更新#1

因此,请遵循注释中的建议(以及我注意到的类似方法

更新#3

试图模仿这种方法,但是由于某种原因,在对象返回值时,状态不存在,最终我遇到了未捕获的typeerror,并且状态没有填充.

 < Form.Item name = {[field.name,"state"]} fieldKey = {[field.fieldKey,"state"]} rules = {rules}><选择showSearchplaceholder ="State"defaultActiveFirstOption = {true}onBlur = {(event)=>{console.log("values",this.formRef.current.getFieldsValue());console.log("target:",event.target);console.log("id",event.target.id);const stateIndex = event.target.getAttribute("aria-activedescendant").split("_").slice(-1);const值= this.formRef.current.getFieldsValue();const namePath = event.target.id.split("_");console.log("namePath",namePath);values [namePath [0]] [namePath [1]] [namePath [2]] = event.target.value.toUpperCase()||STATES [stateIndex];this.formRef.current.setFieldsValue(values);}}>{STATES.map((state)=>(<选项值= {状态}键= {状态}>{状态}</Option>))}</选择></Form.Item> 

更新#4

可以肯定的是,删除Form标记中的name属性可以解决上述问题,并且可以按预期正常工作,并且不会出现错误.

为了结束这个问题,希望对其他人有帮助,我想介绍一下解决方案.最终,解决方案等于做到了这一点,因此当用户跳出相关字段时,该字段的值将设置为用户键入的内容.这是通过将onBlur标记添加到我的antd Select标记来完成的.用户跳出字段时会触发onBlur.然后,将字段设置为输入的字符.事实证明,由于使用了动态形式和嵌套对象数组(申请人),使事情变得更加复杂.

请注意,状态现在显示在值下方,并且名称路径与代码期望的相匹配.

到目前为止,我的最终代码如下:

  import从反应"中反应;从"antd"导入{表单,输入,行,行,选择,按钮};从"@ ant-design/icons"导入{PlusOutlined,MinusCircleTwoTone};const InputGroup = Input.Group;const Option = Select.Option;const {TextArea} =输入;const maxApplicants = 4;const rules = [{required:true}];const STATES = ["AL","AK","AZ","AR","CA","CO","CT","DE","DC",调频","FL","GA","GU",你好",ID","IL",在","IA","KS","KY","LA",我","MH","MD",嘛","MI","MN",多发性硬化症","MO",公吨","NE","NV","NH","NJ","NM","NY","NC","ND","MP",哦",好的",或者","PW","PA","PR","RI","SC","SD","TN","TX","UT","VT","VI","VA","WA","WV","WI",怀俄明州",];const validateMessages = {必填:必填!",类型:{电子邮件:电子邮件无效!",数字:无效数字!",},数字: {范围:必须在$ {min}和$ {max}之间",},};const formItemLayout = {labelCol:{xs:{span:24},sm:{span:6},},wrapperCol:{xs:{span:36},sm:{span:16},},};const formItemLayoutWithOutLabel = {wrapperCol:{xs:{span:36,offset:0},sm:{span:16,offset:6},},};导出默认类TenantForm扩展了React.Component {构造函数(道具){超级(道具);this.state = {申请人:[{firstName:props.tenant吗?props.tenant.first:",middleName:props.tenant?props.tenant.middle:",lastName:props.tenant吗?props.tenant.last:",街道:props.tenant?props.tenant.street:",城市:props.tenant?props.tenant.city:",状态:props.tenant?props.tenant.state:",邮政编码:props.tenant?props.tenant.zipcode:",},],错误: "",};}formRef = React.createRef();使成为() {const onFinish =(值)=>{console.log("onFinish:",values);this.props.onSubmit({申请人:values.applicants,});};返回 (<表格ref = {this.formRef}{... formItemLayoutWithOutLabel}onFinish = {onFinish}id ="myForm"validateMessages = {validateMessages}initialValues = {{申请人:[{firstName:"}]}}>{< Form.List name ="applicants">{(fields,{add,remove})=>{返回 (< div>{fields.map((field,index)=>(< Form.Item {... formItemLayout}标签= {`申请人#$ {index + 1}`} key = {field.key}><行键= {field.key}装订线= {[0,8]} justify ="start">< Col><行装订线= {[4,4]}><颜色范围= {7}>< Form.Item name = {[field.name,"firstName"]} fieldKey = {[field.fieldKey,"firstName"]} rules = {rules}><输入占位符=名字"/></Form.Item></Col><颜色范围= {7}>< Form.Item name = {[field.name,"middleName"]} fieldKey = {[field.fieldKey,"middleName"]} initialValue ="><输入占位符=中间名"/></Form.Item></Col><颜色范围= {9}>< Form.Item name = {[field.name,"lastName"]} fieldKey = {[field.fieldKey,"lastName"]} rules = {rules}><输入占位符=姓氏"/></Form.Item></Col>< Col flex ="none">{index>0?(< MinusCircleTwoToneclassName ="dynamic-delete-button"onClick = {()=>{remove(field.name);}}/>) : 无效的}</Col></行><行装订线= {[4,4]}><颜色范围= {23}>< Form.Item name = {[field.name,"address"]} fieldKey = {[field.fieldKey,"address"]} rules = {rules}><输入占位符=地址"/></Form.Item></Col></行><行装订线= {[4,4]}><颜色范围= {12}>< Form.Item name = {[field.name,"city"]} fieldKey = {[[field.fieldKey,"city"]}} rules = {rules}><输入占位符=城市"/></Form.Item></Col><颜色范围= {5}>< Form.Item name = {[field.name,"state"]} fieldKey = {[field.fieldKey,"state"]} rules = {rules}><选择showSearchplaceholder ="State"defaultActiveFirstOption = {true}onBlur = {(event)=>{console.log("values",this.formRef.current.getFieldsValue());console.log("target:",event.target);console.log("id",event.target.id);const stateIndex = event.target.getAttribute("aria-activedescendant").split("_").slice(-1);const值= this.formRef.current.getFieldsValue();const namePath = event.target.id.split("_");console.log("namePath",namePath);values [namePath [0]] [namePath [1]] [namePath [2]] = event.target.value.toUpperCase()||STATES [stateIndex];this.formRef.current.setFieldsValue(values);}}>{STATES.map((state)=>(<选项值= {状态}键= {状态}>{状态}</Option>))}</选择></Form.Item></Col><颜色范围= {6}>< Form.Item name = {[field.name,"zipcode"]} fieldKey = {[field.fieldKey,"zipcode"]} rules = {rules}><输入占位符=邮政编码"/></Form.Item></Col></行></Col></行></Form.Item>))}< Form.Item>{console.log("count:",fields.length)}{fields.length<maxApplicants?(<按钮类型=破折号"onClick = {()=>{添加();}}style = {{width:"100%"}}>< PlusOutlined/>添加申请人</按钮>) : 无效的}</Form.Item></div>);}}</Form.List>}</表单>);}} 

解决方案

诀窍是在Select组件上使用 onBlur form.setFieldsValue 组合.

请参见下面的代码和框: https://codesandbox.io/embed/distracted-platform-pvdiz?fontsize = 14&hidenavigation = 1& theme = dark

I have a form which for the most part works fine. But one thing bugs me about it is the Select item for imputing a person's state (see screenshot below). It works fine with the mouse, but if you're tabbing through the form and tab to the State field, then type a state like "CA" for California, then tab to the next field (zipcode), the State field resets to blank. I would like it to stay populated with CA if it matched one of the selector's options.

It does work if i type "CA" and hit enter to advance to the next field, but that doesn't seem intuitive as to how forms normally work. It also works if I just use my mouse to select the field. I've been looking over the antd documentation on a Select and don't see anything jumping out at me that might control this. Maybe i'm missing something and i need to do some kind of onchange function?

Anyways, seems like a fairly simple problem but the solution is eluding me.

The select form item's code:

                              <Form.Item name={[field.name, "state"]} fieldKey={[field.fieldKey, "state"]} rules={rules}>
                                <Select
                                  showSearch
                                  placeholder="State"
                                  defaultActiveFirstOption={true}
                                >
                                  <Option value="AL">AL</Option>
                                  <Option value="AK">AK</Option>
                                  <Option value="AZ">AZ</Option>
                                  <Option value="AR">AR</Option>
                                  <Option value="CA">CA</Option>
                                  <Option value="CO">CO</Option>
                                  <Option value="CT">CT</Option>
                                  <Option value="DE">DE</Option>
                                  <Option value="FL">FL</Option>
                                  <Option value="GL">GA</Option>
                                  <Option value="HI">HI</Option>
                                  <Option value="ID">ID</Option>
                                  <Option value="IL">IL</Option>
                                  <Option value="IN">IN</Option>
                                  <Option value="IA">IA</Option>
                                  <Option value="KS">KS</Option>
                                  <Option value="KY">KY</Option>
                                  <Option value="LA">LA</Option>
                                  <Option value="ME">ME</Option>
                                  <Option value="MD">MD</Option>
                                  <Option value="MA">MA</Option>
                                  <Option value="MI">MI</Option>
                                  <Option value="MN">MN</Option>
                                  <Option value="MS">MS</Option>
                                  <Option value="MO">MO</Option>
                                  <Option value="MT">MT</Option>
                                  <Option value="NE">NE</Option>
                                  <Option value="NV">NV</Option>
                                  <Option value="NH">NH</Option>
                                  <Option value="NJ">NJ</Option>
                                  <Option value="NM">NM</Option>
                                  <Option value="NY">NY</Option>
                                  <Option value="NC">NC</Option>
                                  <Option value="ND">ND</Option>
                                  <Option value="OH">OH</Option>
                                  <Option value="OK">OK</Option>
                                  <Option value="OR">OR</Option>
                                  <Option value="PA">PA</Option>
                                  <Option value="RI">RI</Option>
                                  <Option value="SC">SC</Option>
                                  <Option value="SD">SD</Option>
                                  <Option value="TN">TN</Option>
                                  <Option value="TX">TX</Option>
                                  <Option value="UT">UT</Option>
                                  <Option value="VT">VT</Option>
                                  <Option value="VA">VA</Option>
                                  <Option value="WA">WA</Option>
                                  <Option value="WV">WV</Option>
                                  <Option value="WI">WI</Option>
                                  <Option value="WY">WY</Option>
                                  <Option value="AS">AS</Option>
                                  <Option value="DC">DC</Option>
                                  <Option value="FM">FM</Option>
                                  <Option value="GU">GU</Option>
                                  <Option value="MH">MH</Option>
                                  <Option value="MP">MP</Option>
                                  <Option value="PW">PW</Option>
                                  <Option value="PR">PR</Option>
                                  <Option value="VI">VI</Option>
                                </Select>
                              </Form.Item>

Update #1

So following the suggestions in the comments (and my noticing a similar approach here under the form control section), to my class i've added a formRef = React.createRef();.

Then in my Form tag I added a ref={this.formRef} tag. Then modified my Select by adding an onBlur tag that triggers setFieldsValue to set the uppercase version of the input.

This compiles and runs fine. It even outputs the console.log statement. But it does not set the field value for some reason and i'm not sure why.

    return (
      <Form
**      ref={this.formRef}
        name="dynamic_form_item"
        {...formItemLayoutWithOutLabel}
        onFinish={onFinish}
        id="myForm"
        validateMessages={validateMessages}
      >
        {
          <Form.List name="applicants">
            {(fields, { add, remove }) => {
              return (
                <div>
                  {fields.map((field, index) => (
                    <Form.Item {...formItemLayout} label={`Applicant #${index + 1}`} key={field.key}>
                              <Form.Item name={[field.name, "state"]} fieldKey={[field.fieldKey, "state"]} rules={rules}>
                                <Select
                                  showSearch
                                  placeholder="State"
                                  defaultActiveFirstOption={true}
**                                onBlur={(event) => {
**                                  console.log("onblur: ", event);
**                                  this.formRef.current.setFieldsValue({ state: event.target.value.toUpperCase() });
**                                }}
                                >

Update #2

screenshot of values when onFinish is called. Note this is a dynamic form where user can add additional applicants by clicking an add applicant button. Each applicant has the fields shown including the state they live in.

    const onFinish = (values) => {
      console.log("onFinish: ", values);
      this.props.onSubmit({
        applicants: values.applicants,
      });
    };

Update #3

Tried to mimic the approach however for some reason in the object being returned by values, state is absent and ultimately i'm getting an uncaught typeerror and state doesn't populate.

                              <Form.Item name={[field.name, "state"]} fieldKey={[field.fieldKey, "state"]} rules={rules}>
                                <Select
                                  showSearch
                                  placeholder="State"
                                  defaultActiveFirstOption={true}
                                  onBlur={(event) => {
                                    console.log("values", this.formRef.current.getFieldsValue());
                                    console.log("target:", event.target);
                                    console.log("id", event.target.id);
                                    const stateIndex = event.target.getAttribute("aria-activedescendant").split("_").slice(-1);
                                    const values = this.formRef.current.getFieldsValue();
                                    const namePath = event.target.id.split("_");
                                    console.log("namePath", namePath);
                                    values[namePath[0]][namePath[1]][namePath[2]] = event.target.value.toUpperCase() || STATES[stateIndex];
                                    this.formRef.current.setFieldsValue(values);
                                  }}
                                >
                                  {STATES.map((state) => (
                                    <Option value={state} key={state}>
                                      {state}
                                    </Option>
                                  ))}
                                </Select>
                              </Form.Item>

Update #4

So sure enough, removal of the name property in the Form tag resolved the above issue and it's working as expected without error.

In the interest of wrapping up this question in hopes it may help someone else, I wanted to capture the solution. Ultimately the solution amounted to making it so when the user tabs out of the field in question, the field's value gets set to what the user typed. This was done by adding the onBlur tag to my antd Select tag. onBlur fires when the user tabs out of the field. Then making it set the field to the characters entered. Which turned out to be more complicated then I would've thought due to my use of a dyanmic form and nested object array (applicants).

Note the state now shows up under value and the namepath matches what the code expects.

My final code up until this point looks like this

import React from "react";
import { Form, Input, Col, Row, Select, Button } from "antd";
import { PlusOutlined, MinusCircleTwoTone } from "@ant-design/icons";

const InputGroup = Input.Group;
const Option = Select.Option;
const { TextArea } = Input;
const maxApplicants = 4;

const rules = [{ required: true }];

const STATES = [
  "AL",
  "AK",
  "AZ",
  "AR",
  "CA",
  "CO",
  "CT",
  "DE",
  "DC",
  "FM",
  "FL",
  "GA",
  "GU",
  "HI",
  "ID",
  "IL",
  "IN",
  "IA",
  "KS",
  "KY",
  "LA",
  "ME",
  "MH",
  "MD",
  "MA",
  "MI",
  "MN",
  "MS",
  "MO",
  "MT",
  "NE",
  "NV",
  "NH",
  "NJ",
  "NM",
  "NY",
  "NC",
  "ND",
  "MP",
  "OH",
  "OK",
  "OR",
  "PW",
  "PA",
  "PR",
  "RI",
  "SC",
  "SD",
  "TN",
  "TX",
  "UT",
  "VT",
  "VI",
  "VA",
  "WA",
  "WV",
  "WI",
  "WY",
];

const validateMessages = {
  required: "Required!",
  types: {
    email: "Invalid E-mail!",
    number: "Invalid Number!",
  },
  number: {
    range: "Must be between ${min} and ${max}",
  },
};

const formItemLayout = {
  labelCol: {
    xs: { span: 24 },
    sm: { span: 6 },
  },
  wrapperCol: {
    xs: { span: 36 },
    sm: { span: 16 },
  },
};

const formItemLayoutWithOutLabel = {
  wrapperCol: {
    xs: { span: 36, offset: 0 },
    sm: { span: 16, offset: 6 },
  },
};

export default class TenantForm extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      applicants: [
        {
          firstName: props.tenant ? props.tenant.first : "",
          middleName: props.tenant ? props.tenant.middle : "",
          lastName: props.tenant ? props.tenant.last : "",
          street: props.tenant ? props.tenant.street : "",
          city: props.tenant ? props.tenant.city : "",
          state: props.tenant ? props.tenant.state : "",
          zipcode: props.tenant ? props.tenant.zipcode : "",
        },
      ],
      error: "",
    };
  }

  formRef = React.createRef();

  render() {
    const onFinish = (values) => {
      console.log("onFinish: ", values);
      this.props.onSubmit({
        applicants: values.applicants,
      });
    };

    return (
      <Form
        ref={this.formRef}
        {...formItemLayoutWithOutLabel}
        onFinish={onFinish}
        id="myForm"
        validateMessages={validateMessages}
        initialValues={{ applicants: [{ firstName: "" }] }}
      >
        {
          <Form.List name="applicants">
            {(fields, { add, remove }) => {
              return (
                <div>
                  {fields.map((field, index) => (
                    <Form.Item {...formItemLayout} label={`Applicant #${index + 1}`} key={field.key}>
                      <Row key={field.key} gutter={[0, 8]} justify="start">
                        <Col>
                          <Row gutter={[4, 4]}>
                            <Col span={7}>
                              <Form.Item name={[field.name, "firstName"]} fieldKey={[field.fieldKey, "firstName"]} rules={rules}>
                                <Input placeholder="First Name" />
                              </Form.Item>
                            </Col>
                            <Col span={7}>
                              <Form.Item name={[field.name, "middleName"]} fieldKey={[field.fieldKey, "middleName"]} initialValue="">
                                <Input placeholder="Middle Name" />
                              </Form.Item>
                            </Col>
                            <Col span={9}>
                              <Form.Item name={[field.name, "lastName"]} fieldKey={[field.fieldKey, "lastName"]} rules={rules}>
                                <Input placeholder="Last Name" />
                              </Form.Item>
                            </Col>
                            <Col flex="none">
                              {index > 0 ? (
                                <MinusCircleTwoTone
                                  className="dynamic-delete-button"
                                  onClick={() => {
                                    remove(field.name);
                                  }}
                                />
                              ) : null}
                            </Col>
                          </Row>
                          <Row gutter={[4, 4]}>
                            <Col span={23}>
                              <Form.Item name={[field.name, "address"]} fieldKey={[field.fieldKey, "address"]} rules={rules}>
                                <Input placeholder="Address" />
                              </Form.Item>
                            </Col>
                          </Row>
                          <Row gutter={[4, 4]}>
                            <Col span={12}>
                              <Form.Item name={[field.name, "city"]} fieldKey={[field.fieldKey, "city"]} rules={rules}>
                                <Input placeholder="City" />
                              </Form.Item>
                            </Col>
                            <Col span={5}>
                              <Form.Item name={[field.name, "state"]} fieldKey={[field.fieldKey, "state"]} rules={rules}>
                                <Select
                                  showSearch
                                  placeholder="State"
                                  defaultActiveFirstOption={true}
                                  onBlur={(event) => {
                                    console.log("values", this.formRef.current.getFieldsValue());
                                    console.log("target:", event.target);
                                    console.log("id", event.target.id);
                                    const stateIndex = event.target.getAttribute("aria-activedescendant").split("_").slice(-1);
                                    const values = this.formRef.current.getFieldsValue();
                                    const namePath = event.target.id.split("_");
                                    console.log("namePath", namePath);
                                    values[namePath[0]][namePath[1]][namePath[2]] = event.target.value.toUpperCase() || STATES[stateIndex];
                                    this.formRef.current.setFieldsValue(values);
                                  }}
                                >
                                  {STATES.map((state) => (
                                    <Option value={state} key={state}>
                                      {state}
                                    </Option>
                                  ))}
                                </Select>
                              </Form.Item>
                            </Col>
                            <Col span={6}>
                              <Form.Item name={[field.name, "zipcode"]} fieldKey={[field.fieldKey, "zipcode"]} rules={rules}>
                                <Input placeholder="Zip Code" />
                              </Form.Item>
                            </Col>
                          </Row>
                        </Col>
                      </Row>
                    </Form.Item>
                  ))}
                  <Form.Item>
                    {console.log("count:", fields.length)}
                    {fields.length < maxApplicants ? (
                      <Button
                        type="dashed"
                        onClick={() => {
                          add();
                        }}
                        style={{ width: "100%" }}
                      >
                        <PlusOutlined /> Add Applicant
                      </Button>
                    ) : null}
                  </Form.Item>
                </div>
              );
            }}
          </Form.List>
        }
      </Form>
    );
  }
}

解决方案

The trick is use onBlur on the Select component in combination with form.setFieldsValue.

See codesandbox below: https://codesandbox.io/embed/distracted-platform-pvdiz?fontsize=14&hidenavigation=1&theme=dark

这篇关于Antd选择表单项键盘行为问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆