Edit mode doesn't show class attributes in React - reactjs

I did both mode the creation and edit in one form but the problem when I try to edit an element I get the right id value but couldn't retrieve the attributes values.
import { yupResolver } from "#hookform/resolvers/yup";
import { useState, useEffect } from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { useParams, useHistory, Link } from "react-router-dom";
import * as yup from "yup";
import {
getChoice,
postChoice,
updateChoice,
} from "../../../../api/remote.api";
import { CustomInput } from "../../../../components/lib";
import { Choice } from "../../../../models";
type Inputs = {
displayMessage: string;
value: string;
};
const schema = yup.object().shape({
displayMessage: yup.string().min(5, "Au minimum 5 chars").required(),
value: yup.string().min(5, "Au minimum 8 chars").required(),
});
const NewChoice = () => {
const { id } = useParams<{ id?: string }>();
const isAddMode = !id;
let history = useHistory();
const [submitting, setSubmitting] = useState<boolean>(false);
const [error, setError] = useState<string>();
const {
register,
handleSubmit,
setValue,
formState: { errors },
} = useForm<Inputs>({ resolver: yupResolver(schema) });
const onSubmit: SubmitHandler<Inputs> = (data: Inputs) => {
setSubmitting(true);
const choice = new Choice({
displayMessage: data.displayMessage,
value: data.value,
id: Number(id) ? Number(id) : -1,
});
submitForm(choice, id)
.then((chc) => {
setSubmitting(false);
history.goBack();
})
.catch((e) => {
const { message } = e.response.data;
if (message) {
setError(message);
}
setSubmitting(false);
});
};
const submitForm = (choice: Choice, id?: string) => {
return id ? updateChoice(Number(id!), choice) : postChoice(choice);
};
useEffect(() => {
if (!isAddMode) {
// get set form fields
getChoice(Number(id))
.then(
(choice: Choice) => {
setValue("displayMessage", choice.displayMessage);
setValue("value", choice.value);
},
(error) => {
history.push("/choices");
}
)
.catch((e) => {
console.log("error catch");
console.log(e);
});
}
}, [id, isAddMode, setValue, history]);
return (
<div className="container m-1">
<form
className={`flex-column justify-content-center`}
onSubmit={handleSubmit(onSubmit)}
>
<h1 className="h3 mb-3 fw-normal">Création d'un choix</h1>
<CustomInput
register={register}
label="Message affiché"
type="text"
id="displayMessage"
error={errors.displayMessage?.message}
placeholder="Display Message"
/>
<CustomInput
register={register}
label="Valeur du choix"
type="text"
id="value"
error={errors.value?.message}
placeholder="Choice Value"
/>
{error && <div className="invalid-feedback d-block">{error}</div>}
<Link to={"."} className="btn btn-small btn-warning mt-3 mr-2">
Cancel
</Link>
<button
className="btn btn-small btn-primary mt-3"
type="submit"
disabled={submitting}
>
{isAddMode ? "Création" : "Mise à jour"}
</button>
</form>
</div>
);
};
export default NewChoice;
and i tried to look a little bit on stack and other websites but couldn't solve this 5 days bug , in a result i just get a blank page with the appropriate id
and the element should be in this file .
export const CustomInput = ({
register,
label,
type,
id,
error,
placeholder,
}: {
register: any;
label: string;
placeholder: string;
type: string;
id: string;
error?: string;
}) => {
return (
<>
<label htmlFor={id}>{label}</label>
<div className="form-floating">
<input
type={type}
className="form-control"
id={id}
placeholder={placeholder}
{...register(id)}
/>
{error && <p className="invalid-feedback d-block">{error}</p>}
</div>
</>
);
};

Try a new state:
const [isToUpdate, setUpdate] = useState<boolean>(false);
Add it to useEffect array:
[id,isToUpdate ....]
Add setUpdate to where you are setting values after setValue("value",choice.value);
setUpdate(true);

Related

Please how do I add maxFiles properly to this code? I have tried a billion different things, but it just does not work with the dropzone

import { FC } from 'react';
import { useDropzone } from 'react-dropzone';
import { FileIcon } from 'assets/icons';
import Typography from '../Typography';
import { TMultipleDropzoneProps } from './types';
import styles from './MultipleDropzone.module.scss';
const MultipleDropzone: FC<TMultipleDropzoneProps> = ({ title, onDrop }) => {
const { getRootProps, getInputProps, open, isDragAccept, isFocused, isDragReject } = useDropzone({
accept: { 'image/*': ['.jpeg', '.png'], 'video/mp4': ['.mp4', '.MP4'] },
onDrop,
noClick: true,
noKeyboard: true,
maxFiles: 3,
});
const accept = isDragAccept ? 1 : 0;
const focused = isFocused ? 1 : 0;
const rejected = isDragReject ? 1 : 0;
// This is used for warning in console for camel-case attributes to the DOM element and to make it boolean
return (
<div className={styles.wrapper}>
<div
onClick={open}
className={styles.container}
{...getRootProps({ accept, focused, rejected })}
>
<input {...getInputProps({})} />
{rejected === 1 && (
<div className={styles.error}>
Some files were rejected because they did not meet the requirements.
</div>
)}
<div className={styles.container__content}>
<Typography>{title}</Typography>
</div>
<button onClick={open} className={styles.icon}>
<FileIcon />
</button>
</div>
</div>
);
};
export default MultipleDropzone;
the type file:
export type TMultipleDropzoneProps = {
title: string;
onDrop: (e: any, a: any) => void;
isFileUploaded: boolean;
maxFiles?: number;
};
the modal I am using it in:
import { useContext, useState } from 'react';
import { ModalContext } from 'context/Modal';
import { FileExtended } from 'types/global/file';
import { useAppDispatch, useAppSelector } from 'hooks';
import { NewPostTextArea, MultipleDropzone, Typography, Button } from 'components';
import { createActivityPost } from 'store/slices/activitiesSlice/activitiesThunks';
import { CloseCircleIcon } from 'assets/icons';
import { TImages } from './types';
import styles from './NewPost.module.scss';
const NewPost = () => {
const { closeModal } = useContext(ModalContext);
const [images, setImages] = useState<TImages[]>([]);
const [description, setDescription] = useState<string>('');
const dispatch = useAppDispatch();
const { userData } = useAppSelector((state) => state.auth);
const createPost = () => {
const post = {
user_id: userData?.id as number,
description: description,
content_url: 'https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg',
content_type: 'string',
};
closeModal();
if (description.trim()) {
dispatch(createActivityPost(post));
}
};
const isFileUploaded = images.length > 0;
const onDrop = (acceptedFiles: FileExtended[], maxFiles: number) => {
acceptedFiles.forEach((file) => {
const reader = new FileReader();
reader.onload = (e) => {
setImages((prev) => [
...prev,
{
id: Date.now(),
type: file.type,
src: e.target && e.target.result,
file: file,
description: file.name,
},
]);
};
reader.readAsDataURL(file);
});
let modifiedAcceptedFiles = acceptedFiles;
if (acceptedFiles.length > maxFiles) {
// If the number of files exceeds the maxFiles limit,
// slice the extra files off the array and show an error message
modifiedAcceptedFiles = acceptedFiles.slice(0, maxFiles);
}
};
const removeImage = (id: number) => {
setImages(images.filter((image) => image.id !== id));
};
const imageFiles = images.map((image) => {
return (
<div key={image.id} className={styles.container__main__case__box}>
<CloseCircleIcon
onClick={() => removeImage(image.id)}
className={styles.container__main__case__box_close}
/>
{image.type.includes('video') ? (
<video src={image.src as string} autoPlay loop />
) : (
<img src={image.src as string} alt={image.description} />
)}
</div>
);
});
return (
<div className={styles.container}>
<Typography className={styles.container__head}>New Post</Typography>
<div className={styles.container__description}>
<NewPostTextArea value={description} setValue={setDescription} />
</div>
<div className={styles.container__main}>
<Typography className={styles.container__main__head}>{images.length} items</Typography>
<div className={styles.container__main__case}>{imageFiles}</div>
</div>
<MultipleDropzone
onDrop={onDrop}
title='Please attach your files here (Max 3)'
isFileUploaded={isFileUploaded}
/>
<div className={styles.container__footer}>
<Button className={styles.container__footer_close} onClick={closeModal}>
Close
</Button>
<Button type='submit' className={styles.container__footer_submit} onClick={createPost}>
Create
</Button>
</div>
</div>
);
};
export default NewPost;
I tried adding maxFiles to every single component, I also tried adding it to the onDrop component. New to React ( 1 week) and I am slowly losing my sanity. I will never forgive Zuckerberg for this apparition he has brought upon coderkin. Even chatGPT could not help my case.

How to handle multiple select options submittion in react js?

I want to submit a form into mongoDB using nodejs API & reactJs. With the exception of the multiple select option, everything is operating as it should be.
Being new to react, I have no idea how to handle the multi select option's onChange method.
Here is what I've tried:
import React, { useState, useRef } from "react";
import { useForm } from "react-hook-form";
import { v4 as uuidv4 } from 'uuid';
import axios from "axios";
import Select from 'react-select';
export default function EventForm(props) {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm();
const form = useRef();
const [loading, setLoading] = useState(false);
const [info, setInfo] = useState("");
const [analysis, setAnalysis] = useState("Undefined");
const [relatedEvent, setRelatedEvent] = useState([]);
const handleInfoChange = (e) => {
setInfo(e.target.value)
}
const handleAnalysisChange = (e) => {
setAnalysis(e.target.value)
}
const handleRelatedEvents = (e) => {
setRelatedEvent(e.target.value)
}
const relatedEventsData = props.data.map(opt => ({ label: opt.info, value: opt._id }));
const onSubmit = async () => {
setLoading(true);
const MySwal = withReactContent(Swal);
const eventData = {
UUID: uuidv4(),
info: info,
analysis: analysis,
relatedEvent: relatedEvent,
}
axios
.post(`${process.env.REACT_APP_PROXY}/api/events`, eventData)
.then((res) => {
console.log(res);
setLoading(false);
MySwal.fire(
"Success!",
"A new event has been saved successfully",
"success"
);
})
.catch((error) => {
console.log(error);
});
};
return (
<div className="panel-body">
<Form
ref={form}
onSubmit={handleSubmit(onSubmit)}
className="form-horizontal"
>
<div className="row">
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Info</Form.Label>
<Form.Control
type="text"
placeholder="Enter info..."
{...register("info", { required: true })}
value={info}
onChange={handleInfoChange}
/>
{errors.info && (
<ul className="parsley-errors-list filled" id="parsley-id-7" aria-hidden="false">
<li className="parsley-required">This value is required.</li>
</ul>
)}
</div>
</div>
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Related events</Form.Label>
<Select
options={relatedEventsData}
value={relatedEvent}
isMulti
onChange={handleRelatedEvents}
/>
</div>
</div>
<div className="col-lg-12">
<Button variant="primary" type="submit">
{loading ? "Saving..." : "Save"}
</Button>
</div>
</div>
</Form>
</div>
);
}
Could you please guide me how to make it work!
Thank you
you can make use of Select onChange event handler which passes the selected options as an array as argument ..
from that you can map over it to get the values as required
something as below:
const handleChange = (opts) => {
const selectedValues = opts.map((opt) => opt.value);
setSelectedValues(selectedValues);
};
Please check the working sample for better clarity 😉 -

How can I trigger the function using the button?

my code consists of a select by provinces, when I click the province to filter I get the result of clinics in that province, what I want is to get that result by clicking the button, not through the select itself.///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
import React, { useState, useEffect } from 'react'
import Select, { SingleValue } from 'react-select'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
import "./Modal.css";
interface Props {
isOpen: boolean,
closeModal: () => void
}
export const SearchFilterClinics : React.FC<Props> = ({ children, isOpen, closeModal, }) => {
////filter
type OptionType = {
value: string;
label: string;
};
const provincesList: OptionType[] = [
{ value: 'Todos', label: 'Todos' },
{ value: 'Valencia', label: 'Valencia' },
{ value: 'Alicante', label: 'Alicante' },
{ value: 'Castellón', label: 'Castellón' },
]
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFilteredSelect, setClinicListFilteredSelect] = useState<Clinic[]>([]);
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
const handleChangeSelect = async (provinceList: SingleValue<OptionType>) => {
getClinic().then((response) => {
setClinicList(response);
setClinicListFilteredSelect(response)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}).catch ((error) => {
console.error(error);
throw error;
});
}
const filterSelect=(termSearch)=>{
const resultFilterSelect = clinicList.filter((element) => {
if(element.province?.toString().toLowerCase().includes(termSearch.value.toLowerCase() )
){
return element;
}
});
setClinicListFilteredSelect(resultFilterSelect);
}
const handleModalContainerClick = (e) => e.stopPropagation();
return (
<>
<div className={`modal ${isOpen && "is-open"}`} onClick={closeModal}>
<div className="modal-container" onClick={handleModalContainerClick}>
<button className="modal-close" onClick={closeModal}>x</button>
{children}
<div>
<h1>Encuentra tu clínica</h1>
</div>
<div>
<form>
<label>Provincia</label>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect}
/>
<button onClick={handleChangeSelect}>buscar</button>
</form>
{
clinicListFilteredSelect.map((clinicFilter) => (
<div>
<div>{clinicFilter.title}</div>
<div>{clinicFilter.propsPhone}</div>
<div>{clinicFilter.mobile}</div>
<div>{clinicFilter.email}</div>
<div>{clinicFilter.province} </div>
<div>{clinicFilter.registry}</div>
</div>
))
}
</div>
</div>
</div>
</>
)
}
It looks like you are calling the handleChangeSelect function with the button, and also when the select menu changes (with onChange). So remove the onChange in the select, and leave the onClick for the button.
<label>Provincia</label>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect} //THIS TRIGGERS THE FUNCTION
/>
<button onClick={handleChangeSelect}>buscar</button> //ALSO TRIGGERS FUNCTION

How to manage radio button state with React Typescript?

I am implementing a simple signup page with React Typescript.
I'm trying to set the gender with the radio button, save it in the state, and send it to the server, but the toggle doesn't work.
What should I do?
//RegisterPage.tsx
const [radioState, setradioState] = useState(null);
const [toggle, settoggle] = useState<boolean>(false);
const onRadioChange = (e: any) => {
setradioState(e);
console.log(radioState);
};
const genderOps: ops[] = [
{ view: "man", value: "man" },
{ view: "woman", value: "woman" },
];
<div>
{genderOps.map(({ title, gender }: any) => {
return (
<>
<input
type="radio"
value={gender}
name={gender}
checked={gender === radioState}
onChange={(e) => onRadioChange(gender)}
/>
{title}
</>
);
})}
</div>
You should do some changes on your code, here what you should do:
import React, { EventHandler, useState } from "react";
import "./styles.css";
export default function App() {
const [radioState, setradioState] = useState("");
const [toggle, settoggle] = useState<boolean>(false);
const onRadioChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setradioState(e.currentTarget.value);
};
const genderOps = [
{ view: "man", value: "man" },
{ view: "woman", value: "woman" }
];
return (
<div className="App">
<div>
{genderOps.map(({ view: title, value: gender }: any) => {
return (
<>
<input
type="radio"
value={gender}
name={gender}
checked={gender === radioState}
onChange={(e) => onRadioChange(e)}
/>
{title}
</>
);
})}
</div>{" "}
</div>
);
}

TypeError: editMedicine is not a function - REACT

Not sure where I am going wrong here. editMedicine should be a function but it is not. When I click the edit medicine button, I get an error onSubmit. I know in other areas of my code I had some misspellings and capitalization issues, I am hoping this is the case here . I have been looking at this for so long that I cant quite spot whats going on.
import React, { Fragment, useState, useContext, useEffect } from "react";
import { GlobalContext } from "../context/GlobalState.js";
import { useHistory, Link } from "react-router-dom";
const Editmedicine = (route) => {
let history = useHistory();
const { medicines, editMedicine } = useContext(GlobalContext);
const [selectedUser, setSeletedUser] = useState({
id: null,
name: "",
directions: "",
});
const currentUserId = route.match.params.id;
useEffect(() => {
const medicineId = currentUserId;
const selectedUser = medicines.find(
(med) => med.id === parseInt(medicineId)
);
setSeletedUser(selectedUser);
}, []);
const onSubmit = (e) => {
e.preventDefault();
editMedicine(selectedUser);
history.push("/");
};
const handleOnChange = (userKey, value) =>
setSeletedUser({ ...selectedUser, [userKey]: value });
if (!selectedUser || !selectedUser.id) {
return <div>sdf</div>;
}
return (
<Fragment>
<div id="editContainer">
<form onSubmit={onSubmit}>
<div className="w-full mb-5">
<label
htmlFor="name"
>
Name of medicine
</label>
<input
value={selectedUser.name}
onChange={(e) => handleOnChange("name", e.target.value)}
type="text"
placeholder="Enter name"
/>
</div>
<div className="w-full mb-5">
<label
htmlFor="directions"
>
Directions
</label>
<input
value={selectedUser.directions}
onChange={(e) => handleOnChange("directions", e.target.value)}
type="text"
placeholder="Enter directions"
/>
</div>
<div className="flex items-center justify-between">
<button id="editMedicine">
Edit medicine
</button>
</div>
<div className="text-center mt-4 text-gray-500">
<Link to="/">Cancel</Link>
</div>
</form>
</div>
</Fragment>
);
};
export default Editmedicine;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
// here is the globalState file
import React, { createContext, useReducer } from "react";
import AppReducer from "./AppReducer";
//start by setting the initial state
const initialState = {
medicines: [
{
id: 1,
name: "Daily Multivitamin",
directions: "Take once a day with 2 glasses of water"
},
{
id: 2,
name: "Herbal capsule",
directions: "Take once a day with food"
},
{
id: 3,
name: "Tincture",
directions: "1 drop a day, 3x a day."
}
]
};
//create context
export const GlobalContext = createContext(initialState);
//provider component
export const GlobalProvider = ({ children }) => {
const [state, dispatch] = useReducer(AppReducer, initialState);
function removeMedicine(id) {
dispatch({
type: "REMOVE_MEDICINE",
payload: id
});
}
//this might have to be ADD_MEDICINE or S instead
function addMedicine(medicines) {
dispatch({
type: "ADD_MEDICINE",
payload: medicines
});
}
function editMedicine(medicines) {
dispatch({
type: "EDIT_MEDICINE",
payload: medicines
});
}
return (
<GlobalContext.Provider
value={{
medicines: state.medicines,
removeMedicine,
addMedicine,
editMedicine
}}
>
{children}
</GlobalContext.Provider>
);
};

Resources