React: dynamically add input fields in dynamic input fileds - json

I want to make a form . which consist of a shop creation where 3 input fileds are plan name, descriptions, cuisuine . after that three input fileds which i want to add dynamically for duration of plan, maximum duration and price. i can add n numbers of duration and after that i also want to dynamically add all the input fields on a button clicked
plan name,
description
cuisuine
duration

I didn't quite understand the question, but in the following way you can generate a set of input fields dynamically. I hope it helps :)
import React, { useState } from "react";
export default function Example() {
const model = { name: "", desc: "", cuisuine: "" };
const [durations, setDurations] = useState([model]);
const fields = ["name", "desc", "cuisuine"];
function handleChange(field, index, value) {
let newDurations = durations;
newDurations[index][field] = value;
setDurations(newDurations);
}
return (
<div style={{ padding: "20px" }}>
{durations.map((v, i) => (
<div
style={{ border: "1px solid #ccc", padding: "20px" }}
key={`duration-${i}`}>
{fields.map(field => (
<input
key={`duration-${i}-${field}`}
type="text"
name={field}
placeholder={field}
onChange={({ target }) => handleChange(field, i, target.value)}
/>
))}
</div>
))}
<button onClick={() => setDurations([...durations, model])}>
Add field
</button>
</div>
);
}

Related

radio buttons is not functioning properly

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.

Why input value does not change when we pass null or undefined as a value?

While working with the controlled input components if we set the value of the controlled component to null or undefined the previous value is still displayed on the UI instead of changing it and the state holding that input value changes to null or undefined. I have created a sandbox for better understanding
https://codesandbox.io/s/black-architecture-0wqw1
Thank you
If the data type is null or undefined react automatically supress that value and log nothing.
If you want to see the type of that particular value, write {typeof data}, then you'll get your answer.
...
setData(null)
typeof data // object
setData("hi")
typeof data // string
setData(undefined)
typeof data // undefined
...
here is quick fix, it never changes value variable, if data then put data else empty string, that how it works
<input
type="text"
onChange={(e) => setData(e.target.value)}
value={data ? data:""}
/>
i hope this will solve your problem,
here is complete fix,
https://codesandbox.io/embed/optimistic-currying-snn8t?fontsize=14&hidenavigation=1&theme=dark
You can use ref tout change the value of your input anywhere outside your input component, see bellow :
import React, { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
const [data, setData] = useState(null);
const inputRef = React.useRef(null);
useEffect(() => {
console.log(data);
}, [data]);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<input
ref={inputRef}
type="text"
onChange={(e) => setData(e.target.value)}
value={data}
/>
<div style={{ marginTop: "10px" }}>
<button onClick={() => {
setData(null);
inputRef.current.value = ''
}}>SET DATA NULL</button>
</div>
<div style={{ marginTop: "10px" }}>
<button onClick={() => {
setData(undefined)
inputRef.current.value = ''
}}>
SET DATA UNDEFINED
</button>
</div>
<div style={{ marginTop: "10px" }}>INPUT VALUE {data}</div>
</div>
);
}

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

How Would I grab the value of my input boxes to print my own custom message?

I have a json that consists of a parent name and kids that the parent has.
I have a code that grabs the name of the parent and the kids of the json . Based on the amount of kids, input boxes are created so you can enter the name of each kid. But I am stuck. When I click the button how would I print a message that starts with the parent name and combines the values from each input box from the values of the json and the boxes that allow me to name the child
for instance when I click 'jim' from the dropdown, 2 input boxes shows up that says 'child1' and 'child2' and two boxes shows up next to them because he has two children. if i name child1 "james" and child2 "mary" and push the button how can I print a message in the final input box that says
"Jim -- child1=james -- child2=mary"
import React from 'react';
class AppEX extends React.Component {
constructor() {
super();
this.state = {
kids: null,
parentname: null,
parent: [
{ name: 'will', kids: ['child1', 'child2'] },
{ name: 'kia', kids: ['child1'] },
{ name: 'jim', kids: ['child1', 'child2'] }
]
};
}
handleParentChoice = e => {
e.persist();
this.setState({
parentname: e.target.value
});
};
render() {
const namelist = [];
this.state.parent.forEach(e => {
namelist.push({ value: e.name, label: e.name });
});
return (
<div>
<select name="select" onChange={this.handleParentChoice}>
{namelist.map(n => (
<option key={n.value} value={n.value}>
{n.label}
</option>
))}
</select>
<br />
{this.state.parentname &&
this.state.parent
.find(p => p.name === this.state.parentname)
.kids.map(k => (
<div>
<input
key={k}
type="text"
value={k}
disabled={true}
/>
<input key={k} type="text" />
</div>
))}
<br />
<button type="button" value="render" onClick={this.print} />
<input type="text" disabled={true} />
</div>
);
}
}
export default AppEX;
I created an example here, which does what you need.
Note that I had to add/modify some key attributes at places, because there were some console errors.
Also you need to synchronize input values to state at some point. In this example I do it on each keystroke, but you must be aware of the performance implications of this. You may choose different timing for the sync (on blur, with some debounce, etc.), it's up to you.
I modified inputs' name attributes so that each one has unique one, and can be recognized in the function which syncs to state (onChildNameChange).
And btw there are some nice libraries which can spare you the boilerplate of syncing, like react-hook-form (functional components, only) and formik.
As for printing the output string, I used Array.reduce to build it.

React Getting default value from an input type text and setting it as a state

I have some input text fields that I want to fill in for the user, as it will be default values for a configuration.
How can I transfer that over to a state variable in React?
I have:
<input type="number" style={header} value = "5" onChange={this.handleChange('blah')}></input> <br />
as an input field, where you can see I set the value to be 5. How can I transfer this to the state variable 'blah' located in constructor:
constructor(props) {
super(props);
this.state = {
blah: '',
}
Thank you in advance.
You can achieve like this :
state = {
blah : "hello"
}
handleChange = (e) => {
this.setState({blah:e.target.value})
}
render(){
return (
<input type="text"
value = {this.state.blah}
onChange={this.handleChange}></input>
);
}
Live example : https://codesandbox.io/s/hungry-kare-50cbn
For more understanding you can refer this doc: https://reactjs.org/docs/forms.html