簡體   English   中英

僅當單擊提交按鈕時才將數據從多個復選框傳遞到 api:react js

[英]Pass data from multiple checkboxes to api only when a submit button is clicked :react js

僅當單擊提交按鈕時才將數據從多個復選框傳遞到 api

我的網站上有這個手風琴。 當我點擊一個復選框時,所有復選框的值都存儲在 state 中,最后當我點擊提交時,只有數據被傳遞到 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 custom = {
      items: [...state.custom]
        .filter((item) => item.positive)
        .map((item) => ({
          date: state.today,
          symptom: item.id,
          positive: item.positive,
        })),
    };
    console.log(custom);
    axios.post("/customer/submit-multiple/", data, {
      headers: headers,
    });
    axios
      .post("/customer/submit-custom-multiple/", custom, {
        headers: headers,
      })
      .then(() => {
        alert("was submitted");
        window.location.reload();
      })
      .catch((error) => {
        alert("Cannot add submittedagain");
      });
};

我在代碼沙箱中添加的完整代碼。

根據 Hirens 的回答更新了注釋。

https://codesandbox.io/s/objective-jone5tlds

我現在面臨的問題是,如果用戶單擊一個復選框,其檢查值將添加到 state,如果用戶在提交前取消選中該復選框,數組中將有 2 個條目

  • 一個已檢查(正確)
  • 第二個未選中(假)

所以checkbox data 2的值不能提交給array傳給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
    }
]

我不確定我是否正確理解了你的問題。 但我試圖讓它僅在單擊提交按鈕時提交值。 另外,我嘗試使用功能組件並修改了您的代碼以使其更簡單(我希望您能理解新的功能組件方式,如果不了解,這是編寫 React 組件的新方式)。

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

API 由於某種原因仍然失敗,但不知道為什么,但有效載荷是你想要的。 並且還添加了一些評論來幫助您。 讓我知道事情的后續! 祝你好運!

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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM