仅当单击提交按钮时,才将数据从多个复选框传递到API

我的网站上有这个手风琴,当我单击复选框时,所有复选框值都会存储在状态中,最后,当我单击提交时,只会将数据传递给API,存储的数据会显示在下面

   const getAccordionItem = ({ key, label }) => {
    const source = key === "Custom" ? "custom" : "items";

    return (
      <div className="accordion-item" key={key}>
        <div
          className="accordion-title gradiantblur"
          onClick={() => navClose(key)}
        >
          {/* // onClick={setActiveCurrentIndex(item[0].date)}> */}
          <div>{label}</div>
          <i className="fa fa-plus" aria-hidden="true"></i>
        </div>
        {state[key] ? (
          <div className="accordion-content  tableforsymtm">
            {(source !== "custom"
              ? state[source].filter(
                  (item) => item.category === label || item.category === key
                )
              : state[source]
            ).map((item, index) => {
              return (
                <span
                  key={`${key}__${item.id}__${index}`}
                  className="trforsymtm"
                >
                  <td>
                    <input
                      // className="invinsiveinput"
                      data-id={item.id}
                      type="checkbox"
                      id={item.id}
                      checked={item && item.positive}
                      onChange={(e) => handleCheckboxChange(e, source, item.id)}
                    />
                  </td>
                  <td className="tdoneline">
                    <label htmlFor={item.id}>{item.name}</label>
                  </td>
                </span>
              );
            })}
          </div>
        ) : null}
      </div>
    );
  };

  const handleCheckboxChange = (e, stateKey, itemId) => {
    const stateItems = state[stateKey];
    const index = stateItems.findIndex((item) => item.id === itemId);

    setState((prevState) => ({
      ...prevState,
      [stateKey]: [
        ...stateItems.slice(0, index),
        {
          ...stateItems[index],
          positive: e.target.checked,
        },
        ...stateItems.slice(index + 1),
      ],
    }));
  };

提交按钮点击

 const chekbox = (e) => {
    e.preventDefault();
    const headers = {

     
    };
    const data = {
      items: [...state.items]
        .filter((item) => item.positive)
        .map((item) => ({
          date: state.today,
          symptom: item.id,
          positive: item.positive,
        })),
    };

    const custum = {
      items: [...state.custom]
        .filter((item) => item.positive)
        .map((item) => ({
          date: state.today,
          symptom: item.id,
          positive: item.positive,
        })),
    };
    console.log(custum);
    axios.post("/customer/submit-multiple/", data, {
      headers: headers,
    });
    axios
      .post("/customer/submit-custom-multiple/", custum, {
        headers: headers,
      })
      .then(() => {
        alert("was submitted");
        window.location.reload();
      })
      .catch((error) => {
        alert("Cannot add submittedagain");
      });
  };


我在代码沙箱中添加的完整代码 根据Hirens Answer更新的说明 https://codesandbox.io/s/objective-jone5tlds

我现在面临的问题是,如果用户单击某个复选框,其复选值将添加到状态,如果用户在提交前取消选中该复选框,数组中将有2个条目

  • 一个被选中(True)
  • 第2个为未勾选(False)

所以复选框数据值不能提交到数组并传递到api

我希望数据能像这样传递

我收到500个错误

[
    {
        "date" : "2022-02-15",
        "id" : 6,
        "positive" : true
    },
    {
        "date" : "2022-02-15",
        "id" : 5,
        "positive" : true
    },
    {
        "date" : "2022-02-15",
        "id" :7,
        "positive" : true
    },
    {
        "date" : "2022-02-15",
        "id" : 11,
        "positive" : true
    },
    {
        "date" : "2022-02-15",
        "id" : 4,
        "positive" : true
    }
]

推荐答案

我不确定我是否正确理解了你的问题.但我已经try 让它只在单击提交按钮时提交值.此外,我还try 使用功能组件,并修改了代码以使其更简单(如果没有,我希望您能理解新的功能组件方式,这是编写Reaction组件的新方式).

你可以在这里查看完整版本:https://codesandbox.io/s/relaxed-tesla-qwmh7v?file=/src/App.js.

由于某种原因,API仍然失败,但不确定原因,但有效负载是您想要的.此外,还添加了一些 comments 来帮助您.告诉我进展如何!祝你好运?

import React from "react";
import axios from "axios";
import moment from "moment";

import "./styles.css";
// function to get data from API, taken it out since it 
// does not depend on state as such, we can pass date a param
const getData = (date) => {
  const config = {
    headers: {
      // can be taken from localStorage
      Authorization: `token 67f023b5e798b8e7217bffc4b74a23b40666c589`
    }
  };
  return axios
    .get(
      `https://shebirth.herokuapp.com/customer/Symptoms-GET/?date=${date}`,
      config
    )
    .then((res) => res.data)
    .catch((err) => {
      console.error("error ocurred while fetching data", err);
      return null;
    });
};

const SYMPTOMS_CATEGORIES = [
  { key: "Head", label: "Head" },
  { key: "Pelvis", label: "Pelvis" },
  { key: "Legs", label: "Legs" },
  { key: "Other", label: "Other" },
  { key: "Abdomen", label: "Abdomen" },
  { key: "Mental", label: "Mental Health" },
  { key: "Custom", label: "User Defined" }
];

const styles = {
  trgrid: {
    display: "grid",
    gridTemplateColumns: "1fr 1fr 1fr 1fr"
  },
  module: {
    position: "relative",
    // background: "rgb(76, 0, 61) none repeat scroll 0% 0%",
    background: "#ffffff1c 0% 0% no-repeat padding-box",
    margin: "0px 30px",
    borderRadius: "10px",
    padding: "0px 0px 20px 0px",
    height: "40rem",
    overflowY: "scroll",
    scrollbarWidth: "thin",
    marginbottom: "10px"
  },
  txt: {
    textAlign: "left"
  },
  btn: {
    border: "1px solid #974cae",
    padding: "5px 30px",
    background: "#974cae",
    fontSize: "12px"
  },
  left: {
    textAlign: "left"
  },
  boxstyle: {
    background: "#ffffff1c 0% 0% no-repeat padding-box",
    marginTop: "10px"
  },
  flex: {
    background: "#ffffff1c 0% 0% no-repeat padding-box",
    marginTop: "10px",
    display: "flex"
    // justifyContent: "space-evenly",
    //background: "#971cae",
  },
  subbtn: {
    background: "linear-gradient(90deg, #3a51a7 30%, #b53899)",
    padding: "10px 30px",
    border: "none",
    borderRadius: "10px",
    color: "#fff",
    cursor: "pointer",
    margin: "10px"
  },
  // NOTE: just for demo styling purpose for separate headings a bit!!
  // use your own styles!!!
  accordionItem: {
    marginTop: "10px",
    marginBottom: "10px"
  },
  accordionHeader: {
    fontWeight: "bold",
    cursor: "pointer",
    backgroundColor: "#7986cb",
    color: "#000",
    padding: "2px 4px"
  }
  // demo styles ends
};

const SymptomTracker = () => {
  const [state, setState] = React.useState({
    medicineOpen: true,
    medicineReady: true,
    symptomReady: false,
    items: [],
    dateState: [],
    custom: [],
    Head: false,
    Pelvis: false,
    Legs: false,
    Mental: false,
    Other: false,
    Custom: false,
    today: moment().format("YYYY-MM-DD"),
    report: [],
    allValues: {
      others: "",
      bloodSugar: "",
      bloodPressure: ""
    }
  });

  // const closeMedicine = () => {
  //   setState((prevState) => ({
  //     ...prevState,
  //     medicineOpen: !state.medicineOpen
  //   }));
  // };

  // const addMedicine = () => {
  //   setState((prevState) => ({
  //     ...prevState,
  //     medicineReady: !state.medicineReady
  //   }));
  // };

  const addSymptom = () => {
    setState((prevState) => ({
      ...prevState,
      symptomReady: !state.symptomReady
    }));
  };

  const navClose = (e) => {
    setState((prevState) => ({
      ...prevState,
      [e]: !prevState[e]
    }));
  };

  const onDateChange = (e) => {
    var dateSelected = e.target.value;
    var date = moment(dateSelected).format("YYYY-MM-DD");
    console.log({ date });
    setState((prevState) => ({ ...prevState, today: date }));
  };

  const handleCheckboxChange = (e, stateKey, itemId) => {
    const stateItems = state[stateKey];
    console.table(stateItems);
    console.log({ stateKey });
    const index = stateItems.findIndex((item) => item.id === itemId);

    console.log({ item: stateItems[index] });

    setState((prevState) => ({
      ...prevState,
      [stateKey]: [
        ...stateItems.slice(0, index),
        {
          ...stateItems[index],
          positive: e.target.checked
        },
        ...stateItems.slice(index + 1)
      ]
    }));
  };

  const changeHandler = (e) => {
    setState((prevState) => ({
      ...prevState,
      allValues: {
        ...prevState.allValues,
        [e.target.name]: e.target.value
      }
    }));
  };

  const getAccordionItem = ({ key, label }) => {
    const source = key === "Custom" ? "custom" : "items";

    return (
      <div className="accordion-item" style={styles.accordionItem} key={key}>
        <div
          className="accordion-title gradiantblur"
          style={styles.accordionHeader}
          onClick={() => navClose(key)}
        >
          {/* // onClick={setActiveCurrentIndex(item[0].date)}> */}
          <span>{label}</span>
          <i className="fa fa-plus" aria-hidden="true"></i>
        </div>
        {state[key] ? (
          <div className="accordion-content  tableforsymtm">
            {(source !== "custom"
              ? state[source].filter(
                  (item) => item.category === label || item.category === key
                )
              : state[source]
            ).map((item, index) => {
              const itemId = `${key}__${item.name}__${item.id}__${index}`;
              return (
                <span key={itemId} className="trforsymtm">
                  <td>
                    <input
                      // className="invinsiveinput"
                      data-id={item.id}
                      type="checkbox"
                      id={itemId}
                      checked={item && item.positive}
                      onChange={(e) => handleCheckboxChange(e, source, item.id)}
                    />
                  </td>
                  <td className="tdoneline">
                    <label htmlFor={itemId}>{item.name}</label>
                  </td>
                </span>
              );
            })}
          </div>
        ) : null}
      </div>
    );
  };

  // handle checked items submission
  const chekbox = (e) => {
    e.preventDefault();
    const headers = {
      // Authorization: `token ` + localStorage.getItem("token")
      Authorization: `token 67f023b5e798b8e7217bffc4b74a23b40666c589`
      // Authorization: `token 67f023b5e798b8e7217bffc4b74a23b40666c589`,
    };
    const data = [...state.items]
      // keep all items
      // .filter((item) => item.positive)
      .map((item) => ({
        date: state.today,
        symptom: item.id,
        positive: item.positive
      }));

    const custom = [...state.custom]
      // keep all items
      //.filter((item) => item.positive)
      .map((item) => ({
        date: state.today,
        symptom: item.id,
        positive: item.positive
      }));

    console.log(custom);
    // submit both requests parallelly and once both gets done
    // then only reload the page.
    Promise.all([
      axios.post(
        "https://shebirth.herokuapp.com/customer/symptoms-submit-multiple/",
        data,
        {
          headers: headers
        }
      ),
      axios.post(
        "https://shebirth.herokuapp.com/customer/submit-custom-symptom-multiple/",
        custom,
        {
          headers: headers
        }
      )
    ])
      .then(() => {
        alert("symptoms are submitted");
        window.location.reload();
      })
      .catch((error) => {
        alert("Cannot add symptoms again");
        console.error(error);
      });
  };

  const onSubmit = (e) => {
    e.preventDefault();

    const headers = {
      // Authorization: `token ` + localStorage.getItem("token")
      Authorization: `token 67f023b5e798b8e7217bffc4b74a23b40666c589`
    };

    // prepare data object
    const data = {
      others: state.allValues.others,
      bloodSugar: state.allValues.bloodSugar,
      bloodPressure: state.allValues.bloodPressure,
      date: state.today,
      // combining custom and normal items together, can be separated if you want
      // in their each keys
      items: [...state.items, ...state.custom]
        // keep all items
        // .filter((item) => item.positive)
        .map((item) => ({
          date: state.today,
          symptom: item.id,
          positive: item.positive
        }))
    };

    axios
      .patch("customer/submit-symptoms-with-input/", data, {
        headers: headers
      })
      .then(() => {
        alert("symptom was submitted");
        window.location.reload();
      })
      .catch((error) => {
        alert("Cannot add symptoms again");
      });
  };

  // this effect will fire once the component is mounted, and on `state.date` changes.
  React.useEffect(() => {
    (async () => {
      const data = await getData(state.today);
      // console.log({ data });

      if (data) {
        setState((prevState) => ({
          ...prevState,
          items: data.Symptoms,
          custom: data.customSymptom,
          allValues: data.symptomsWithIputs,
          report: data.last_week_symptom_report
        }));
      }
    })();
  }, [state.today]);

  return state.medicineOpen ? (
    <div className="symptom-container" style={styles.module}>
      <h2
        className="lightgradient"
        style={{
          borderBottom: "1px solid #fff",
          padding: "10px",
          margin: "0px",
          fontSize: "24px",
          // background: "#6f1f6d",
          borderTopLeftRadius: "10px",
          borderTopRightRadius: "10px"
        }}
      >
        Symptom Tracker
      </h2>

      <div style={styles.boxstyle}>
        <span style={{ fontSize: "16px" }}> Enter Date</span>
        <input
          type="date"
          className="calanderbutton"
          value={state.today}
          onChange={onDateChange}
        />

        {/* accordion */}
        <div className="accordion">
          {SYMPTOMS_CATEGORIES.map(getAccordionItem)}
        </div>
        <button type="Button" className="pinkbutton" onClick={chekbox}>
          submit check boxes
        </button>
        {/* form */}
        <form onSubmit={onSubmit}>
          <div style={styles.flex}>
            <div
              className="marign-5"
              style={{
                transform: "rotate(90deg)",
                fontSize: "4rem",
                padding: "15px"
              }}
            >
              {/* <img src={img1} /> */}
              {/* <i className="fa fa-pencil"></i> */}
            </div>
            <div className="marign-5" style={{ padding: "10px" }}>
              <strong>Enter your weight</strong>
              <br />
              <br />

              <input
                className="inputofsymtum"
                style={{ float: "left" }}
                name="others"
                placeholder="Kg"
                onChange={changeHandler}
                defaultValue={state.allValues && state.allValues.others}
                type="text"
                // placeholder="Description"
              />
            </div>
          </div>
          <div style={styles.flex}>
            <div
              className="marign-5"
              style={{ fontSize: "4rem", padding: "15px" }}
            >
              {/* <img src={img2} /> */}
              {/* <i className="fa fa-level-up"></i> */}
            </div>
            <div className="marign-5" style={{ padding: "10px" }}>
              <strong>Enter your blood sugar level</strong>
              <br />
              <br />
              <input
                className="inputofsymtum"
                style={{ float: "left" }}
                type="text"
                name="bloodSugar"
                placeholder="(mg/dL)"
                onChange={changeHandler}
                defaultValue={state.allValues && state.allValues.bloodSugar}
              />
            </div>
          </div>
          <div style={styles.flex}>
            <div
              className="marign-5"
              style={{ fontSize: "4rem", padding: "15px" }}
            >
              {/* <img src={img3} /> */}
              {/* <i className="fa fa-area-chart"></i> */}
            </div>
            <div className="marign-5" style={{ padding: "10px" }}>
              <strong>Enter your blood pressure level</strong>
              <br />
              <br />
              <input
                className="inputofsymtum"
                style={{ float: "left" }}
                type="text"
                placeholder="(mmHg)"
                name="bloodPressure"
                onChange={changeHandler}
                defaultValue={state.allValues && state.allValues.bloodPressure}
                // onChange={changeHandler}
                // value={state.allValues.bloodPressure}
              />
            </div>
          </div>
          <div style={styles.flex}>
            <div
              className="marign-5"
              style={{
                transform: "rotate(90deg)",
                fontSize: "4rem",
                padding: "15px"
              }}
            >
              {/* <img src={img4} /> */}
              {/* <i className="fa fa-pie-chart"></i> */}
            </div>
            <div className="marign-5" style={{ padding: "10px" }}>
              <strong>Last week report</strong>
              <br />
              <br />
              <p className="fontin12">
                Last week you have experienced &nbsp;
                {state.report.map((personData, key) => {
                  return (
                    <span key={key}>
                      {personData.count}&nbsp;times&nbsp;
                      {personData.symptom}&nbsp;,&nbsp;
                    </span>
                  );
                })}
              </p>
            </div>
          </div>
          <div>
            <button type="submit" className="pinkbutton">
              Submit
            </button>
          </div>
          <br />
          {/* {state.symptomReady ? <AddSymptom /> : null} */}
          <span
            onClick={addSymptom}
            // style={styles.subbtn}
            className="pinkbutton"
            style={{ cursor: "pointer", fontSize: "16px" }}
          >
            Add User Defined Symptom
          </span>
          <hr />
        </form>
      </div>
    </div>
  ) : null;
};

export default SymptomTracker;

Javascript相关问答推荐

如何在react-Router-dom 6中Forking 路由?

Angular material 表多个标题行映射

在贝塞尔曲线的直线上找不到交叉点:(使用@Pomax的bezier.js)

Redux工具包查询(RTKQ)端点无效并重新验证多次触发

zoom svg以适应圆

在vercel throws上部署带有gunjs的sveltekit应用无法找到模块./' lib/文本编码'

Spring boot JSON解析错误:意外字符错误

colored颜色 检测JS,平均图像 colored颜色 检测JS

更改JSON中使用AJAX返回的图像的路径

我的角模板订阅后不刷新'

Web Crypto API解密失败,RSA-OAEP

扩展类型的联合被解析为基类型

当我try 将值更改为True时,按钮不会锁定

try 使用PM2在AWS ubuntu服务器上运行 node 进程时出错

在JS中动态创建对象,并将其追加到HTML表中

第一项杀死下一项,直到数组长度在javascript中等于1

如何为仅有数据可用的点显示X轴标签?

postman 预请求中的hmac/sha256内标识-从js示例转换

如何在脚本编译后直接将RxJ模块导入浏览器(无需Angel、webpack、LiteServer)

Clip-Path在网页浏览器(Mozilla、Edge、Chrome)上不能正常工作,但在预览版Visual Code Studio HTML、CSS、JS上却能很好地工作