I am using adminlte HTML theme, I converted this theme into reactjs, everything is working fine except select2(Multi-select)
onselect I am trying to trigger the handler that is userIdHandler but it does not trigger
There is two cases:
user name with multi-select : userIdHandler not working
Status with single select: userIdHandler working
please help me to trigger userIdHandler from multi-select also
import React, { useEffect, useState } from "react";
import { getTeam } from "../services/ApiCall/attendanceApiCall";
export default function TeamattendanceComponent() {
const [team, setTeam] = useState([]);
const userIdHandler = (e) => {
console.log("hi", e.target.value);
};
useEffect(() => {
const script = document.createElement("script");
script.src = "myjs/content.js";
script.async = true;
document.body.appendChild(script);
getTeam().then((res) => {
console.log(res.data);
setTeam(res.data);
});
}, []);
return (
<div className="content-wrapper">
{/* Content Header (Page header) */}
<div className="card">
<div className="card-body row">
<div className="col-4">
<div className="form-group ">
<label>User Name</label>
<select
id
className="form-control select2"
multiple="multiple"
data-placeholder="Select a State"
style={{ width: "100%" }}
onChange={userIdHandler}
>
{team.map((user, key) => {
console.log("team data", team);
return (
<option key={key} value={user._id}>
{user.name}
</option>
);
})}
</select>
</div>
</div>
<div className="col-4">
<div className="form-group">
<label>Status</label>
<select id className="form-control" onChange={userIdHandler}>
<option>Select</option>
<option>ON</option>
<option>OFF</option>
</select>
</div>
</div>
<div className="col-4">
<div className="form-group">
<label className="hidden-xs"> </label>
<input
type="submit"
className="btn btn-primary form-control"
defaultValue="Filter"
/>
</div>
</div>
</div>
</div>
{/* /.content */}
</div>
);
}
I'm afraid that you are not using a Select2 elements that's a regular select.
First install react-select: npm i --save react-select
This is how you define a multiselect on Select2:
import Select from 'react-select';
const options = [{label: "option 1", value: 1}, {label: "option 2", value: 2}];
<Select
isMulti
options={options}
onChange={userIdHandler}
/>
And then change your userIdHandler` function to this:
const userIdHandler = (value) => {
console.log(value);
};
This way it should print you the label and value selected.
Related
I did looking for but i did not find an answer for my problem.
I need to create a dynamic form with dynamic fields, with the order that the user need.
import { useState } from "react";
const DemoLateral = () => {
const itemDataObject = {
title_item_lateral: '' ,
text_item_lateral: [],
image_lateral: [
{
title_image_lateral: '',
path_image_lateral: '',
}
],
document_lateral: [],
links: [
{
title_link:'' ,
link: ''
}
]
};
const addFields = () => {
let newItemField;
newItemField = itemDataObject;
setItems([...items, newItemField]);
};
const [items, setItems] = useState([]);
const [select, setSelect] = useState([]);
console.log(items);
console.log('select: ', select);
const handleChange = () => {
//let index =
//let name = items[i][e.target.name]=[e.target.value];
console.log();
};
const submitForm = (e) => {
e.preventDefault();
};
console.log(select);
return (
<>
<h3 className="ms-5 mb-5"> AÑADIR ITEMS </h3>
<div className="container">
<form onSubmit={submitForm} className=''>
<div>
{items.map((input, i)=> (
<>
<div className="row align-items-center row mb-4" key={i}>
<label htmlFor="exampleFormControlSelect1">Selecciona el Campo</label>
<div className="col-2" key={i}>
<select className="form-control" id="exampleFormControlSelect1"
onChange={(e) => setSelect([select[i]=e.target.value])} key={i}>
<option>Subtitulo</option>
<option>Imagen</option>
<option>Link</option>
<option>Texto</option>
</select>
</div>
<div className='col-8'>
<input
placeholder="desde From"
id={i}
className='form-control'
value={select[i]}
onChange= {handleChange(i)}
type="text"
required
/>
</div>
<button className="btn btn-danger col-1" >Borrar</button>
</div>
</>
))
}
</div>
<button className="btn btn-success me-4 mt-5" type='submit'>AddSubmit</button>
</form>
<div className="mt-5 text-center">
<button className="btn btn-primary me-4 mb-4" value='items' onClick={addFields}>Add Items</button>
</div>
</div>
</>
);
};
export default DemoLateral;
with this code i try to create a dynamic form with fields, that would be set in the form like the user need:
p.e:
'subtitle'
'image'
'text'
'text'
'link'
'image'
for this i create a select to choose the type of field, and try to put the select in the attribute name, for then when submit all works.
But i can not achieve. :-(
Where is my wrong....
maybe there are other way to do the same kind of form?
Here I built a form and I want, when I click on submit button if title part(input with id form-title) is empty border of the input gets a specific className but
It doesn't work
I uploaded an image and specify the submit button and input of title
My purpose is when I click on submit button the code must check the inside of the input tag(title) and if it's empty(I mean equal to "" ) the border of the input become red else become green
import { useState } from "react";
import "./tickets.css";
export default function Tickets() {
// States
const [toggle_new_ticket, setToggle_new_ticket] = useState(false);
const [form_title, set_form_title] = useState("");
const [form_unit, set_form_unit] = useState("");
const [form_explain, set_form_explain] = useState(false);
let [check, setCheck] = useState("");
// States functions
const form_checker = () => {
setCheck(() => {
if (form_title == "") {
check = false;
} else {
check = true;
}
console.log(check);
});
};
return (
<div className="tickets-container">
{/* New Ticket section */}
<div className="tickets-new-ticket-container">
{/* New Ticket Title */}
<div
className="tickets-new-ticket-title"
onClick={(e) => {
setToggle_new_ticket(!toggle_new_ticket);
}}
>
<div className="new-ticket-image">
<img src="https://img.icons8.com/external-tanah-basah-glyph-tanah-basah/48/000000/external-plus-user-interface-tanah-basah-glyph-tanah-basah-2.png" />
</div>
<div className="new-ticket-title">
<sapn> ثبت درخواست جدید</sapn>
</div>
</div>
{/* New Ticket Form */}
{toggle_new_ticket ? (
<div className="tickets-new-ticket-form-container">
{/* Form top container */}
<div className="tickets-new-ticket-form-top-container">
{/* Form title part */}
<div className="new-ticket-form-title">
<label htmlFor="form-title">عنوان</label>
<input
onChange={(e) => {
set_form_title(e.target.value);
}}
className={check ? "form-correct" : "form-alarm"}
type="text"
name="form-title"
id="form-title"
required
value={form_title}
title="عنوان مورد نظرتان را وارد کنید"
{...console.log(check)}
/>
<span>current state of title:{}</span>
</div>
{/* Form unit part */}
<div className="new-ticket-form-unit">
<label htmlFor="form-unit">واحد</label>
<select name="form-unit" id="form-unit" required>
<option value disabled selected className="form-unit-header">
واحد مورد نظر را انتخاب کنید
</option>
<option value="پیگیری سفارش">پیگیری سفارش</option>
<option value="احراز هویت"> احراز هویت</option>
<option value="مالی">مالی </option>
<option value="سایر">سایر </option>
</select>
</div>
</div>
{/* Form order part */}
<div className="new-ticket-form-order">
<label htmlFor="form-order">در خصوص سفارش</label>
<select name="form-order" id="form-order">
<option value="">هیچکدام</option>
</select>
</div>
{/* Form explain part */}
<div className="new-ticket-form-explain">
<label htmlFor="form-explain">توضیحات</label>
<textarea
name="form-explain"
id="form-explain"
cols="60"
rows="10"
value={form_explain}
onChange={(e) => {
set_form_explain(e.target.value);
}}
></textarea>
</div>
{/* ّForm upload file part */}
<div className="new-ticket-form-upload-file">
<label htmlFor="">فایل پیوست</label>
<label htmlFor="form-upload" className="form-upload">
<span>انتخاب فایل</span>
<img src="https://img.icons8.com/metro/20/000000/upload.png" />
</label>
<input type="file" name="form-upload" id="form-upload" />
<span className="form-upload-explain">
پسوندهای مجاز: jpg, jpeg, png, pdf, doc, docx, zip, rar حداکثر
حجم فایل 5 مگابایت
</span>
</div>
{/* Form submit btn */}
<div className="new-ticket-form-submit">
<input
type="submit"
name="form-submit"
id="form-submit"
value="ارسال درخواست"
onClick={() => {
form_checker();
}}
/>
</div>
</div>
) : (
""
)}
</div>
{/* Tickets log section */}
<div className="tickets-log-container"></div>
</div>
);}
Try like this
import React, { useState } from 'react';
import "./tickets.css";
export default function App() {
// States
const [toggle_new_ticket, setToggle_new_ticket] = useState(false);
const [form_title, set_form_title] = useState('');
const [form_unit, set_form_unit] = useState('');
const [form_explain, set_form_explain] = useState(false);
let [check, setCheck] = useState(false);
React.useEffect(() => {
if (form_title !== '') {
setCheck(true);
} else {
setCheck(false);
}
}, [form_title])
return (
<div className="tickets-container">
{/* New Ticket section */}
<div className="tickets-new-ticket-container">
{/* New Ticket Title */}
<div
className="tickets-new-ticket-title"
onClick={(e) => {
setToggle_new_ticket(!toggle_new_ticket);
}}
>
<div className="new-ticket-image">
<img src="https://img.icons8.com/external-tanah-basah-glyph-tanah-basah/48/000000/external-plus-user-interface-tanah-basah-glyph-tanah-basah-2.png" />
</div>
<div className="new-ticket-title">
<sapn> ثبت درخواست جدید</sapn>
</div>
</div>
{/* New Ticket Form */}
{toggle_new_ticket ? (
<div className="tickets-new-ticket-form-container">
{/* Form top container */}
<div className="tickets-new-ticket-form-top-container">
{/* Form title part */}
<div className="new-ticket-form-title">
<label htmlFor="form-title">عنوان</label>
<input
onChange={(e) => {
set_form_title(e.target.value);
}}
className={ check ? 'form-correct' : 'form-alarm'}
type="text"
name="form-title"
id="form-title"
required
value={form_title}
title="عنوان مورد نظرتان را وارد کنید"
{...console.log(check)}
/>
<span>current state of title:{}</span>
</div>
{/* Form unit part */}
<div className="new-ticket-form-unit">
<label htmlFor="form-unit">واحد</label>
<select
name="form-unit"
id="form-unit"
required
>
<option
value
disabled
selected
className="form-unit-header"
>
واحد مورد نظر را انتخاب کنید
</option>
<option value="پیگیری سفارش">
پیگیری سفارش
</option>
<option value="احراز هویت">
{' '}
احراز هویت
</option>
<option value="مالی">مالی </option>
<option value="سایر">سایر </option>
</select>
</div>
</div>
{/* Form order part */}
<div className="new-ticket-form-order">
<label htmlFor="form-order">در خصوص سفارش</label>
<select name="form-order" id="form-order">
<option value="">هیچکدام</option>
</select>
</div>
{/* Form explain part */}
<div className="new-ticket-form-explain">
<label htmlFor="form-explain">توضیحات</label>
<textarea
name="form-explain"
id="form-explain"
cols="60"
rows="10"
value={form_explain}
onChange={(e) => {
set_form_explain(e.target.value);
}}
/>
</div>
{/* ّForm upload file part */}
<div className="new-ticket-form-upload-file">
<label htmlFor="">فایل پیوست</label>
<label
htmlFor="form-upload"
className="form-upload"
>
<span>انتخاب فایل</span>
<img src="https://img.icons8.com/metro/20/000000/upload.png" />
</label>
<input
type="file"
name="form-upload"
id="form-upload"
/>
<span className="form-upload-explain">
پسوندهای مجاز: jpg, jpeg, png, pdf, doc, docx,
zip, rar حداکثر حجم فایل 5 مگابایت
</span>
</div>
{/* Form submit btn */}
<div className="new-ticket-form-submit">
<input
type="submit"
name="form-submit"
id="form-submit"
value="ارسال درخواست"
onClick={() => {
form_checker();
}}
/>
</div>
</div>
) : (
''
)}
</div>
{/* Tickets log section */}
<div className="tickets-log-container" />
</div>
);
}
Use UseEffect hook , when title was changed , it will be fire , and you can make a check is title empty or not , also not need use state callback for set check value.
I'm working on react and I have several drop-down and text fields where I want to clear/reset selected values from the select options and from the text field when I click the clear button. I've tried some logic, but it doesn't work. can someone help me? I created a function called "handleReset" but it does nothing and doesn't show an error.
Here is my code:
import React, { useState, useEffect } from "react";
import {
Button,
Container,
} from "react-bootstrap";
import { CarAction } from "../../Store/Actions/CarAction";
import { useDispatch, useSelector } from "react-redux";
const CarRequests = () => {
const dispatch = useDispatch();
const getCarMake = useSelector((state) => state.CarReducer.car);
const getCarMileage = useSelector((state) => state.CarReducer.mileage);
const getCarTrim = useSelector((state) => state.CarReducer.trim);
let [value, setValue] = useState()
let handleChange = (e) => {
setValue(e.target.value)
}
const handleReset = (e) => {
setValue(e.target.value = "");
}
useEffect(() => {
dispatch(CarAction.CarMake());
dispatch(CarAction.CarMileage());
dispatch(CarAction.CarTrim());
}, [dispatch]);
return (
<div className="flex-row align-items-center section">
<h3>
Filters
<i className="fa fa-cog icon float-right"></i>
</h3>
<Container className="box-shadow p-4">
<div className="form-row">
<div className="form-group col-lg-3">
<label>Make:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarMake.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
<div className="form-group col-md-3">
<label>Model:</label>
<select className="custom-select">
<option value=''>Please select...</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
<div className="form-group col-md-3">
<label>Year:</label>
<select className="custom-select">
<option value=''>Please select...</option>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
</div>
<div className="form-group col-md-3">
<label>Mileage:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarMileage.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
</div>
<div className="form-row">
<div className="form-group col-md-3">
<label>Car Trim:</label>
<select className="custom-select" onChange={handleChange}>
<option value=''>Please select...</option>
{getCarTrim.map((data, key) => <option value={data.value} key={key}>{data.name}</option>)}
</select>
</div>
<div className="form-group col-md-3">
<label>Email:</label>
<input type="email" placeholder="Email" className="custom-select" />
</div>
<div className="form-group col-md-3">
<label>Phone no:</label>
<input type="number" placeholder="Phone no" className="custom-select" />
</div>
</div>
<div className="container-buttons">
<Button className="mr-4" variant="light">
Search
</Button>
<Button variant="dark" onClick={handleReset}>Clear</Button>
</div>
</Container>
</div>
);
};
export default CarRequests;
The thing you are doing wrong is in handleReset function you are taking the event and you are setting the target value to empty which is ideally wrong.
In order to correct it we need to understand how the flow is working, you are using handleChange function in order to set the values to your state.
So in order to reset it you need to reset the value of the state only.
So the code becomes like this:
const handleReset = () => {
setValue("");
}
Now this will reset the value of your state variable and also use your state variable in your select method which will resolve the problem.
<select value={value}>
<option></option>
.
.
</select>
To make dynamic field working:
function App() {
const [value, setValue] = useState({});
const arr = ["hello", "cra"];
const arr2 = [
{
name: "hello",
id: "1",
},
{
name: "test2",
id: "2",
},
];
const handleChange = ({ target: { value: val, name } }) => {
setValue({ ...value, [name]: val });
};
const resetValue = () => {
setValue({});
};
console.log(value);
return (
<div id="wrapper">
<select
name="select1"
value={value.select1 || ""}
onChange={handleChange}
>
<option value=""></option>
{arr.map((val) => {
return <option value={val}>{val}</option>;
})}
</select>
<select
name="select2"
value={value.select2 || ""}
onChange={handleChange}
>
<option value=""></option>
{arr2.map(({ name, id }) => {
return <option value={id}>{name}</option>;
})}
</select>
<button onClick={resetValue}>Reset</button>
</div>
);
}
Or else you can initialise the value in your state as well like this
const [value, setValue] = useState({select1: "" , select2: ""});
which could further be used dynamically in your select tag for name attributes.
function App() {
const [value, setValue] = useState({ select1: "", select2: "" });
const arr = ["hello", "cra"];
const arr2 = [
{
name: "hello",
id: "1",
},
{
name: "test2",
id: "2",
},
];
const handleChange = ({ target: { value: val, name } }) => {
setValue({ ...value, [name]: val });
};
const resetValue = () => {
setValue({
select1: "",
select2: "",
});
};
console.log(value);
return (
<div id="wrapper">
<select name="select1" value={value.select1} onChange={handleChange}>
<option value=""></option>
{arr.map((val) => {
return <option value={val}>{val}</option>;
})}
</select>
<select name="select2" value={value.select2} onChange={handleChange}>
<option value=""></option>
{arr2.map(({ name, id }) => {
return <option value={id}>{name}</option>;
})}
</select>
<button onClick={resetValue}>Reset</button>
</div>
);
}
Seems you are trying to store multiple values in the value . don't use the word value there. I have tried to change it to [formValue, setFormValue]
Change 1:
let [formValue, setFormValue] = useState({
textfield1: '',
dropdownfield2: ''});
Change 2 - for dropdown changed values:
const handlDropDownChange = (event, value) => {
setFormValue({
...formValue,
['dropdownfield2']: value,
});
}
Change 3 - for mapping dropdown values from state, also use this to map to dropdown value:
formValue.dropdownfield2
Change 4 - for text field changes:
onChange={e => {
updateFieldMyForm(e);
}}
const updateFieldMyForm= e => {
setFormValue({
...formValue,
[e.target.name]: e.target.value
});
};
Note this will work for all text fields - just make sure that the name of this textfield matches the name used in the useState statement like - textfield1
Change 5 - to reset the whole thing at the end/submission
EDIT - 1
const handleReset = () => { setFormValue({ textfield1: "", dropdownfield2: "" }); };
Spread operator is the key in steps 2 & 4 [triple dots - ...] - let me know if you still have challenges.
I am using react hooks and I have a child component Addmember and a parent component MemberList. Within the member list the user clicks add member and a model pops up (the child component) and then user can input some form data then submit the form. The form then adds the new member to the MongoDB collection. .then() it called parentCallback(true) to flip the parent state of loading to true which will then trigger a component re-render. Which is successfully working.
The problem here which I cant get my head around the issue is that upon the parent re-render when it hits the database to getMembers its not returning the newly added member. If I refresh the page the same call will successfully grab all the members including the recent addition.
MemberList.js:
import React, { useState, useEffect } from "react";
import Spinner from "react-bootstrap/Spinner";
import { toast } from "react-toastify";
import { css } from "glamor";
import "react-toastify/dist/ReactToastify.css";
import "react-datepicker/dist/react-datepicker.css";
import "../Styles/ReactDatePicker.css";
import Member from "./Member";
import AddMemberModal from "../models/AddMember";
import RemoveMemberModel from "../models/RemoveMember";
const { getFamily, getMembers } = require("../Utils/Service");
const MemberList = () => {
const [family, setFamily] = useState({});
const [familyMembersList, setFamilyMembersList] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (loading) {
fetchData();
}
}, [loading]);
async function fetchData() {
getFamily.then(result => {
console.log('get family');
setFamily(result);
});
getMembers.then(result => {
try {
console.log('set family list');
console.log(result);
setFamilyMembersList(
result.map((child, index) => (
<Member
key={index}
index={child._id}
balance={child.balance}
firstName={child.firstName}
lastName={child.lastName}
birthday={child.birthday}
role={child.role[0]}
/>
))
);
} catch (e) {
toast.error("500: Error with Service Call", {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
className: css({
background: "#ed5565 !important"
})
});
} finally {
setLoading(false);
}
});
}
function handleCallback() {
setLoading(true);
}
return (
<div className="ibox">
<div className="ibox-title">
<h5>{family.name}</h5>
<div className="ibox-tools">
<span className="label label-warning-light float-right">
{familyMembersList.length} Member(s)
</span>
</div>
</div>
<div className="ibox-content">
<div className="feed-activity-list">
{loading ? (
<Spinner animation="grow" role="status" variant="dark">
<span className="sr-only">Loading...</span>
</Spinner>
) : (
familyMembersList
)}
</div>
<div className="d-flex">
<a
className="btn btn-primary text-white m-t"
data-toggle="modal"
data-target={"#newMemberModel"}
>
<i className="fa fa-plus"></i> New Member
</a>
<a
className="btn btn-danger text-white m-t m-l"
data-toggle="modal"
data-target={"#removeMemberModel"}
>
<i className="fa fa-minus"></i> Remove Member
</a>
</div>
</div>
{/* Add Member Model */}
<AddMemberModal parentCallback={handleCallback}/>
{/* Remove Member Model */}
<RemoveMemberModel />
</div>
);
};
export default MemberList;
AddMember.js
import React, { useState, useEffect } from "react";
import { toast } from "react-toastify";
import DatePicker from "react-datepicker";
import useForm from "react-hook-form";
import { css } from "glamor";
import "react-toastify/dist/ReactToastify.css";
import "react-datepicker/dist/react-datepicker.css";
import "../Styles/ReactDatePicker.css";
const { postMember } = require("../Utils/Service");
const AddMemberModal = ({parentCallback}) => {
const [date, setDate] = useState(new Date());
const { handleSubmit, register, errors } = useForm();
// const handleDateChange = date => {
// setDate(date)
// }
const onSubmit = (data) => {
try {
data.familyId = "5dddf14df965552b3da57be1";
postMember(data).then(async () => parentCallback(true));
} catch (error) {
toast.error("500: Error with Service Call", {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
className: css({
background: "#ed5565 !important"
})
});
}
};
return (
<div
className="modal inmodal"
id={"newMemberModel"}
tabIndex="-1"
role="dialog"
style={{ display: "none" }}
aria-hidden="true"
>
<div className="modal-dialog">
<div className="modal-content animated fadeIn">
<div className="modal-header">
<button type="button" className="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span className="sr-only">Close</span>
</button>
<h4 className="modal-title">New Family Member</h4>
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="modal-body">
<div className="row">
<div className="col">
<div className="form-group">
<label>First Name</label>
<input
type="text"
placeholder="First Name"
className="form-control"
name="firstName"
ref={register({
required: true,
pattern: {
value: /^[a-zA-Z]+$/i,
message: "Invalid First Name"
}
})}
/>
<div className="text-danger">
{errors.firstName && errors.firstName.message}
</div>
</div>
<div className="form-group">
<label className="font-normal">Birthday</label>
<div className="input-group date">
{/* <DatePicker
selected={date}
onChange={handleDateChange}
placeholderText="Click to select a date"
isClearable
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
ref={e =>register({
name: "Birthday",
required: false
})}
/> */}
<input
type="text"
placeholder="01/01/01"
className="form-control"
name="birthDate"
ref={register({
required: false
})}
/>
</div>
</div>
</div>
<div className="col">
<div className="form-group">
<label>Last Name</label>
<input
type="text"
placeholder="Last Name"
className="form-control"
name="lastName"
ref={register({
required: true,
pattern: {
value: /^[a-zA-Z]+$/i,
message: "Invalid Last Name"
}
})}
/>
<div className="text-danger">
{errors.lastName && errors.lastName.message}
</div>
</div>
<div className="form-group">
<label>Role</label>
<select
className="custom-select"
name="role"
ref={register({ required: true })}
>
<option defaultValue>Select Role</option>
<option value="Adult">Adult</option>
<option value="Child">Child</option>
</select>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-white"
data-dismiss="modal"
>
Close
</button>
<button type="submit" className="btn btn-primary">
Add Member
</button>
</div>
</form>
</div>
</div>
</div>
);
};
export default AddMemberModal;
The order in which I can see in the console of the console happening is:
[Log] get family
[Log] set family list
[Log] [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object] (10)
The object its return is missing the most recent member addition. I have tried adding timeouts thinking it may be a timing issue but this had no change in this issue.
you can add the submitted data to the array instead of refreshing the page
in MemberList.js file, change your handleCallback to this :
function handleCallback(data){
const arr = [...familyMembersList];
let newMember = (
<Member
key={data._id}
index={data._id}
balance={0}
firstName={data.firstName}
lastName={data.lastName}
birthday={data.birthday}
role={data.role}
/>
)
arr.push(newMember);
console.log(arr);
setFamilyMembersList(arr);
setLoading(false);
}
and in your AddMember.js change onSubmit method to this :
const onSubmit = (data) => {
try {
data.familyId = "5dddf14df965552b3da57be1";
postMember(data).then(async () => parentCallback(data));
} catch (error) {
...
}
};
I am creating a React Js website. Where I have a form with 2 select fields Min price and Max price. I want to apply validation on these two fields. So if user click minimum price of500 the maximum should only display 500 going up. My react component code is available below.
import React, { Component } from 'react';
import { Form, FormGroup, Input } from 'reactstrap';
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
};
}
handleSearch(event) {
alert("Search button clicked");
event.preventDefault();
}
render() {
return (
<div>
<header className="headerbg d-flex">
<div className="container my-auto">
<div className="row">
<div className="offset-1 col-10 offset-lg-0 col-lg-4">
<div id="search-form-div" className="container">
<div className="row">
<div className="col-12 my-4">
<h3>Search</h3>
<Form onSubmit={this.handleSearch}>
<FormGroup>
<Input type="select" name="select3" id="select3">
<option selected disabled>Min Price</option>
<option value="0">0</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</Input>
</FormGroup>
<FormGroup>
<Input type="select" name="select4" id="select4">
<option selected disabled>Max Price</option>
<option value="0">0</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</Input>
</FormGroup>
<FormGroup>
<Input type="submit" name="search" id="search" className="btn btn-primary" value="Search" />
</FormGroup>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
);
}
}
export default MyForm;
Hope you understand my code. Thanks in advance.
The recommended way (and might I add, the cleaner way, is to place to option values in an array, which you commit to state and change whenever a value is changed). So your component might look something like this...
import React, { Component } from 'react';
import { Form, FormGroup, Input } from 'reactstrap';
const defaultValues = [
{ value: 0, text: 0, key: 1 },
{ value: 500, text: 500, key: 2 },
{ value: 1000, text: 1000, key: 3 },
{ value: 1500, text: 1500, key: 4 },
{ value: 2000, text: 2000, key: 5 }
];
const MIN_TITLE = { selected: true, disabled: true, text: 'Min Price' };
const MAX_TITLE = { selected: true, disabled: true, text: 'Max Price' };
class MyForm extends Component {
constructor(props) {
super(props);
this.state = {
minData: [MIN_TITLE, ...defaultValues],
maxData: [MAX_TITLE, ...defaultValues],
minValue: null,
maxValue: null
};
// This allows us to access the state inside the renderoptions function.
// Another way (if you want to ignore this line) is to write the renderOptions
// as renderOptions = data => {}
this.renderOptions = this.renderOptions.bind(this);
}
handleSearch(event) {
alert('Search button clicked');
event.preventDefault();
}
renderOptions(data) {
return data.map(datum => {
// this allows us to indicate whether we are selecting or disabling
const selected = datum.selected || false;
const disabled = datum.disabled || false;
return (
<option key={datum.key} value={datum.value} selected={selected} disabled={disabled}>
{datum.text}
</option>
);
});
}
// Writing your function so does not require the binding in the constructor
handleMinSelect = event => {
const value = event.target.value;
const newMaxValues = [];
defaultValues.forEach(datum => {
// I'm under the impression that reactstrap will change the value to string
if (datum.value >= Number.parseInt(value, 10)) {
newMaxValues.push(datum);
}
});
this.setState({
maxData: [MAX_TITLE, ...newMaxValues],
minValue: value
});
};
handleMaxSelect = event => {
const value = event.target.value;
this.setState({ maxValue: value });
};
render() {
// I'm stri
<div>
<header className="headerbg d-flex">
<div className="container my-auto">
<div className="row">
<div className="offset-1 col-10 offset-lg-0 col-lg-4">
<div id="search-form-div" className="container">
<div className="row">
<div className="col-12 my-4">
<h3>Search</h3>
<Form onSubmit={this.handleSearch}>
<FormGroup>
<Input
type="select"
name="select3"
id="select3"
value={this.state.minValue}
onChange={this.handleMinSelect}>
{this.renderOptions(this.state.minData)}
</Input>
</FormGroup>
<FormGroup>
<Input
type="select"
name="select4"
id="select4"
value={this.state.maxValue}
onChange={this.handleMaxSelect}>
{this.renderOptions(this.state.maxData)}
</Input>
</FormGroup>
<FormGroup>
<Input
type="submit"
name="search"
id="search"
className="btn btn-primary"
value="Search"
/>
</FormGroup>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>;
}
}
export default MyForm;
Basically, the major changes are
Set the values in state and render them using the renderOptions
When a new state pops up, change the value and update the maxData property
Hope it helps you out 😉
you need to add an onChange function to your Inputs. Then update the state when the minValue input is selected. When this is the max, compare the selected value with the minValue in the state and reject it when less than the
I would do another logic if had to do this kind of form anyway. I would create the option list for maxValue dynamicaly based on the choice for minValue. I would display only the values greater than the min. I guess this is more convenient for user.