radio buttons is not functioning properly - html

a division has a checkboxs and by clicking that checkbox radio buttons options need to be shown for a particular checkbox
checkbox is mapped as according to the array
<form id="lab_test_detail">
{item.subcategory.map((item, index) =>
<>
<input type={"checkbox"} onChange={() => handleChange(item, index)} name={item.id}></input>
<label style={{ position: "inherit", zIndex: "10" }}>{item.categoryname} </label>
<div id={index}></div>
</>
)}
</form>
when the checkbox is changed radio buttons option should have to populate on
handleChange is
const handleChange = (item, index) => {
httpClient.GET(`medical-institute/categoryId/${item.id}`, false, true)
.then(resp => {
// debugger;
document.getElementById(index).innerHTML =
`
${
resp.data.data.map((item1,index1)=>{
return`<form>
<input type="radio" onChange=${handleRadioChange(item,index)}></input>
<label >${item1.medicalinstitutename}</label>
<span> Rs.${item1.price}</span>
<br/>
</form>
`
})
}
`
console.log("response is", resp.data.data)
})
}
const handleRadioChange = (item, index) => {
console.log("inside radiochange")
console.log("dasdas", item, index)
}
so when radio button is clicked i need to do a particular thing but handleRadioChange is called when i click on the checkox but not when i click on radio , why is this happening, a ny solution?

Because you are executing the handleRadioChange once the node is added into the DOM.
Change the onChange handler
handleRadioChange(item,index)
to
() => handleRadioChange(item,index)
You should try to work with the virtual DOM instead of insert html string.
In your case, I think you can use state to store the item data for display and trigger the re-render. BTW you might don't have to fetch the data every time user clicks a check box.

Related

Display div on hover for mapped buttons

So I have a group of buttons that are displayed using a map. When I hover over one of these buttons I want a black box to appear on the side of it. This black box will be developed into a preview.
However, because of the map function, the rest of the buttons get a preview when I hover over one button. This is how the buttons look before the hover. You have a subject, and the courses are listed under this. Both the courses and subjects are mapped.
When I hover over a single button all the button previews are set to true. When I move my mouse off the button, all the previews are removed. How can I single out a button to have a specific preview?
export default function Yeartwo() {
const [grade, setGrade] = useState(localStorage.getItem('grade'));
const [preview, setPreview] = useState(false);
let grades = Object.keys(courseData)
let nextGrade = grades[Object.keys(courseData).indexOf(grade)+1]
let subjects = courseData[nextGrade].subjects
let courses = courseData[nextGrade].classes
function coursePreview(e) {
e.preventDefault();
console.log('hovered')
setPreview(true)
}
return (
<div className="courseSelect">
{subjects.map((subject, index) => (
<div key={index}>
<h2 className="subject">{subject}</h2>
<div className="courses">
{courses[subject].map((course, index) => (
<div key={index}>
<button value={subject} className="course_btn" onMouseEnter={() => setPreview(true)} onMouseLeave={() => setPreview(false)}>{course}</button>
{preview && <div className="preview"> {course} </div>}
</div>
))}
</div>
</div>
))}
</div>
)
}
Reorder your preview state to contain an object instead of booleans. The object should be in the following format: { 'course1': boolean, 'course2': boolean, ..., 'courseN': boolean } - course is the key and the boolean value represents whether the preview for this item should be shown or not.
Therefore, your condition should look like this: {preview['course'] && <div className="preview"> {course} </div>}
And update your listeners to be like this: {... onMouseEnter={() => setPreview({...preview, 'course': true}) ...} and the same for the onMouseLeave method.

Auto-type in html input

I want to have two input fields. It should be possible to type in one of them, but the other one should be hidden. whatever we type in the first field should be auto-typed in the hidden one. Is this possible?
just add type='hidden' for the second input
const input = document.getElementById('input')
const hiddenInput = document.getElementById('hiddenInput')
input.addEventListener('input', ({ target: { value } }) => hiddenInput.value = value)
<input id='input'/>
<input id='hiddenInput'/>

React: Checkbox visibly toggles, but checked property does not show up in DOM

I'm learning React and have a test application where this formValues slice of state:
const initialFormValues = {
first_name: '',
last_name: '',
email: '',
password: '',
tos: false,
}
is controlled by having this listener attached to each <input> in a form:
const onChange = evt => {
const value = evt.target.type === 'checkbox' ? evt.target.checked : evt.target.value;
const name = evt.target.name;
validate(name, value);
setFormValues({ ...formValues, [name]: value});
}
One of the <input>s is this Terms of Service checkbox:
<label>
I agree to the Terms of Service
<input
name="tos"
type="checkbox"
value="tos"
checked={formValues.tos}
onChange={onChange}
/>
</label>
The form works just as expected, toggling the checkbox visually on and off, but the checkbox's checked property never shows up in the actual DOM [it just shows up as <input name="tos" type="checkbox" value="tos" /> no matter what the apparent state of the checkbox is]. I want to have code that doesn't have access to React's internal state check using only the DOM whether the checkbox is checked or not. How can I make React give the actual HTML element its proper checked property?

How do I add components dynamically in React?

In the attached picture, I want a different component to be added below the 'Choose Round Type' option based on the round type selected.
Adding to a single round is no issue. But when I add a new round and try to do the same for it, the components are essentially the same thing but repeated.
As you can see here, both of the forms are either visible or not.
I am following a wrong approach wherein I just add the form component to the mapped round and because the form is same for every round, it connects to all of the forms of the other rounds.
What I want is that I should be able to select different round types and get the corresponding input fields in every round.
As visible, once I click on a different round type in the second round, the first one also changes.
The Add a Round functionality is made using AntDesign Components.
What I tried to do:
import React, { useState } from "react";
import { useStore } from "react-redux";
import { Input, Radio, Form, Button, Space } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '#ant-
design/icons';
import "./createQuizPage.css";
const RoundTypeScheme = ({ type, count }) =>
{
console.log(type, count);
try
{
switch(type)
{
case "Pounce":
return (
<div id = {count}>
<label>Marks for correct answer (Direct)
</label>
<Input size = "small" />
<label>Marks for incorrect answer (Direct)
</label>
<Input size = "small" />
<label>Marks for correct answer (Pounce)
</label>
<Input size = "small" />
<label>Marks for incorrect answer (Pounce)
</label>
<Input size = "small" />
<hr />
</div>
);
case "Pounce + Bounce":
case "Differential":
case "Buzzer":
case "Long Visual Connect":
default:
return (<></>)
}
}
catch(err)
{
console.log(err);
}
}
const CreateQuizPage = () =>
{
const [type, setType] = useState("");
const [count, setCount] = useState(0);
const store = useStore();
let quiz_name = store.getState().quiz;
const quiz_rounds = ["Preliminary", "Main"]
const quiz_sub_rounds = ["Pounce", "Pounce + Bounce", "Buzzer", "Differential", "Long Visual Connect"]
const roundScores = (e) =>
{
setType(e.target.value);
}
const addRound = () =>
{
setCount(prev => (prev + 1));
}
return (
<div id = "createQuizPage">
<Form
name="basic"
className = "createQuizPage__form"
>
<h1>Name: {quiz_name}</h1>
<Form.Item>
<label>Choose Quiz Type </label>
<Radio.Group
options = {quiz_rounds}
optionType = "button"
buttonStyle = "solid"
className = "createQuizPage__type-button"
></Radio.Group>
</Form.Item>
<Form.List name="users">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, fieldKey, ...restField }) => (
<Space key={key} align="baseline" className = "createQuizPage__quiz-round">
<Form.Item
{...restField}
name={[name, 'round_type']}
fieldKey={[fieldKey, 'round_type']}
rules={[{ required: true, message: 'Missing Quiz Round' }]}
>
<label>Choose Round Type </label>
<Radio.Group
options = {quiz_sub_rounds}
optionType = "button"
buttonStyle = "solid"
onChange = {(e) => roundScores(e)}
></Radio.Group>
<RoundTypeScheme type = {type} count = {count}/>
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))}
<Form.Item>
<Button onClick={() => {add(); addRound();}} icon={<PlusOutlined />}>
Add a Round
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
</div>
)
}
export default CreateQuizPage;
The issue you facing is caused because you pass the type and view dependencies as props to the actual component and they're still reactive.
You need to either:
Save the initial config of the round component and then if the props will change, it won't change the UI of the round.
Hold in the container component an array of the round configs and then loop over them and pass each round config to the round component.
I think #2 would be better in terms of architecture and code readability

Why does a React input element lose focus when nested within a component?

So, I have an input element connected to the React Context API - updating the value onChange works when the element is not nested within a component. Just under the input, I render a different component that returns an input field. This input field is also connected to the context API, but the input loses focus onChange.
I understand that I could add a "key" and even an "id", but none of these solutions seems to work.
Why is this happening, and what is the best way to fix is?
import React, { useContext } from "react";
import { Context } from "../../context";
import { set_employee_action } from "../../context/actions";
const DashBody = () => {
const { state, dispatch } = useContext(Context);
const DashboardBody = () => {
return (
<div key={"table"}>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT BREAKS */}
<div key={"LABEL_TWO"}>
<label htmlFor={"LABEL_TWO"}>{"LABEL_TWO"}:</label>
<input
type="text"
id={"LABEL_TWO"}
key={"LABEL_TWO"}
name={"LABEL_TWO"}
value={
state.dash.employee_form["LABEL_TWO"]
? state.dash.employee_form["LABEL_TWO"]
: ""
}
onChange={(e) => dispatch(set_employee_action(e))}
></input>
</div>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT BREAKS */}
</div>
);
};
return (
<div className="dash_body_container" key={"dash_body_container"}>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT WORKS */}
<div key={"LABEL_ONE"}>
<label htmlFor={"LABEL_ONE"}>{"LABEL_ONE"}:</label>
<input
type="text"
id={"LABEL_ONE"}
key={"LABEL_ONE"}
name={"LABEL_ONE"}
value={
state.dash.employee_form["LABEL_ONE"]
? state.dash.employee_form["LABEL_ONE"]
: ""
}
onChange={(e) => dispatch(set_employee_action(e))}
></input>
</div>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT WORKS */}
<DashboardBody></DashboardBody>
</div>
);
};
export default DashBody;
It looks like you're redefining the DashboardBody component each time DashBody is rendered. You're losing the focus inside DashboardBody's input because you're using dispatch from DashBody so that each time the dispatch is called, DashBody component is re-rendered and is rendering a different DashboardBody component. You can extract DashboardBody and define it outside DashBody but make sure you use useContext(Context) in DashboardBody:
const DashboardBody = () => {
const { state, dispatch } = useContext(Context); // make sure you have your own dispatch method
return (
<div key={"table"}>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT BREAKS */}
<div key={"LABEL_TWO"}>
<label htmlFor={"LABEL_TWO"}>{"LABEL_TWO"}:</label>
<input
type="text"
id={"LABEL_TWO"}
key={"LABEL_TWO"}
name={"LABEL_TWO"}
value={
state.dash.employee_form["LABEL_TWO"]
? state.dash.employee_form["LABEL_TWO"]
: ""
}
onChange={(e) => dispatch(set_employee_action(e))}
></input>
</div>
{/* THIS IS NOT THE ACTUAL PLACE FOR THIS INPUT - BUT THIS IS WHERE IT BREAKS */}
</div>
);
};