ReactJS: add a new input field on an option select - reactjs

I'm using react-select with isMulti. I am trying to add a new input field when user selects an option from dropdown. I have somehow achieved it. I am facing a problem, let's say if I select 1st option from dropdown then it adds the input field for that particular option and when I try to select second option then 2 new input fields are added (1 for the previously selected option and the other for current selected option). In this way, I get 3 new input fields but I should be getting 2 input fields because I have selected only 2 options. Below is my code.
onChange = (e) => {
if(e){
e.map((item) => {
this.state.selectValue.push(item.value);
})
}
}
this.state.selectValue.map((item) => {
return(
<div className="row m-3">
<label className="col-md-4">{item}</label>
<div className="col-md-7">
<input type="text" name={item} className="form-control" />
</div>
</div>
)
})
<Select
isMulti
options={this.state.options}
onChange = {(e) => this.onChange(e)}
classNamePrefix="select"
/>
Note: I am storing the option's value as a "name" of input field to keep track of the quantity.
In the screenshot when I selected first then an input field with "first" label was displayed but when I selected "second" then 2 input fields showed up as highlighed in the image.

Updating state within a loop causes sideffects with the way the component re-renders. Try using a temporary array in your handler and then override state after your map function.
onChange = (e) => {
if(e){
let arr = []
e.map((item) => {
arr.push(item.value);
})
this.setState({selectValue: arr})
}
}

Updating state within a loop causes sideffects with the way the component re-renders. Try using a temporary array in your handler and then override state after your map function.

Related

State only getting the first letter from the input?

Hey I have an issue where I am collecting input from several inputs.. I tried to write a helper function for just updating the state object for each input, but it seems like the input is only gathering the first letter from my input and nothing else.. and it seems like it stores it once and then I can change it.. any idea what I'm missing her?
`
export const Form = ({addStudent}) => {
const [newStudent, setNewStudent] = useState({school:"university"})
const updateValue = e => {
const { name, value } = e.target;
setNewStudent({[name]: value, ...newStudent});
}
return (
<section>
<p>First Name</p>
<input type="text" name="firstName"
onChange={updateValue}
/>
<p>Last Name</p>
<input type="text" name="lastName"
onChange={updateValue}
/>
<label>Choose a school:</label>
<select name="school"
onChange={updateValue}
>
<option value="university">university</option>
<option value="highSchool">High School</option>
</select>
<button onClick={() => addStudent(newStudent)}>
Add new Student
</button>
</section>
)
}
`
I tried to make the updateValue function dynamic with the values like this and now it seems to not work anymore...
You are overwriting the current existing value with your spread.
setNewStudent({[name]: value, ...newStudent});
// ^^^^^^^^^^ overwriting existing value
After the first keystroke (onChange) the field gets created and the value of that field is just one letter (because if was empty before). And it stays in this state because the new value is consistently overwritten by the previous (first) value.
Note: You should be also using a callback while setting the new state, just to make sure it's up-to-date when updating.
setNewStudent((prev) => ({ ...prev, [name]: value }));
you are setting the values ​​in the wrong place.
first copy the state, and the add it the new field.
setNewStudent({...newStudent, [name]: value});

Populate CheckboxList Based on URL Parameters

I am trying to retrieve value from URL parameters and populate the value to a checkboxlist. Next step, select the checkbox value, update the URL parameter. My sandbox URL is https://oh2p2e.csb.app/?checkedCampusItems=A,B. Right now, it only works with one value in the URL. What is my problem? How do I synchronize the URL parameter value when clicking the checkboxlist? Many thanks.
https://oh2p2e.csb.app/?checkedCampusItems=A,B
The A and B should be selected.
That means you should grab the 'checkedCampusItems', that will return you a string 'A,B'.
For example:
// valuesToCheck is the array that contains
// the values from the url parrameter
const valuesToCheck = checkedCampusItems.split(,);
// Now you can see which one should be checked.
// The three checkboxes will be rendered but
// the ones you want to will be checked.
<input type="checkbox" checked={valuesToCheck.includes('A')} onCheck={() => history.push(`/checkedCampusItems?=${currentValue},A`)} />
<input type="checkbox" checked={valuesToCheck.includes('B')} onCheck={() => history.push(`/checkedCampusItems?=${currentValue},A`)} />
<input type="checkbox" checked={valuesToCheck.includes('C')} onCheck={() => history.push(`/checkedCampusItems?=${currentValue},A`)} />
)
This is not the exact code, but you get the main point.
You are getting TypeError this.history.push is not a function beacause you can't use this reference in functional component.
Second thing, useHistory() is now deprecated, you can use useNavigation() insted.
To summarize, first add this line:
Import {useNavigation} from "react-router-dom";
Then, change input element like this :
<input
type="checkbox"
id={`custom-checkbox-${index}`}
name={name}
value={name}
checked={checkedState[index]}
onChange={() => handleOnChange(value, index)}
/>
Change handleOnChange function like this:
const handleOnChange = (value, position) => {
const updatedCheckedState = checkedState.map((item, index) =>
index === position ? !item : item
);
setCheckedState(updatedCheckedState);
// update URL params
console.log(searchParams);
navigation(/?checkedCampusItems=${value});
};
Here is sandbox : https://codesandbox.io/s/checkboxlist-forked-c1lt1x?file=/src/App.js:1513-1824

How to reset/clear a Formik FieldArray that is conditionally rendered?

Using Formik, I am conditionally rendering via a select list value, a FieldArray that has two fields, i.e. name and age.
My question is, assuming that I have rendered this FieldArray relating to name and age and have created 5 rows of info but I then decide to change the select list value to another value that now hides this FieldArray. In doing so, how can I clear/reset this FieldArray back to null?
There can be multiple ways to do this based on the structure of your form component.
Here is one way which uses setFieldValue function exported by Formik to explicitly set a value to a field.
const FormComp = () => {
return (
<div>
<Formik>
{({ values, setFieldValue }) => (
<Form>
<select
onChange={(e) => {
const {value} = e.target;
let shouldResetFieldArray = value !== 'showFieldArray'; // replace with actual condition
if (shouldResetFieldArray) {
setFieldValue("fieldArrayKey", []); // reset fieldArrayKey to empty array [];
}
}}
></select>
</Form>
)}
</Formik>
</div>
);
};

How to deal with multiple <select> dropdown menus in the same class component that use the same state to pass a value to redux?

This code works fine if the user selects something from each dropdown menu, but if they forget to make a selection, it will just use the value selected from the previous dropdown menu. Also if they don't make any selection at all and submit, it will obviously submit the default value stored in the state which is "0".
Anyone happen to have a workaround for this? Thanks.
export class Content extends Component {
constructor(props){
super(props)
this.state = {
selectedOption: 0
}
}
handleOptionChange = e => {
this.setState({
selectedOption: e.target.value
})
}
handleSubmit = e => {
e.preventDefault()
}
render() {
let snowboardItems = this.props.snowboards.map((board,index) => {
return <div><form onSubmit={this.handleSubmit}>
<li key={index} className="list_item">
<div className="content_div1">
<h3>{board.name}</h3>
<h3>$ {board.price}</h3>
<h4>{board.terrain}</h4>
<h4>Shape: {board.shape}</h4>
<p>Board Length:</p>
<select value={this.state.selectedOption} onChange={this.handleOptionChange}>
{board.length.map((item, index) =>
<option value={item} key={index}>{item}</option>
)}
</select> cm
</div>
<div className="content_div2">
<button className="content_button" type="submit" onClick={() => this.props.addToCart({board}, this.state.selectedOption)}>Add to Cart</button>
<img className="image" src={board.imageurl} />
</div>
</li>
</form>
</div>
})
This is really a case where you should separate this into two components: one to render the list of items (you could do this in the parent passing the props too), and another to render the item and possibly handle its state.
If for some reason you can't though, you'll probably want to separate each board option into its own property on state. Here's an example where state is updated dynamically:
https://codesandbox.io/embed/snowboards-pl9r5
You should always code defensively, so in the example there's a "short circuit" check to make sure that a length was selected before adding it to the cart. Also the select field is marked as required so that you can use HTML5 as another fallback validator.
You can check it by trying to add an item without a length and also selecting different options and adding them to the cart (logging them in the console).
On another note: I changed it to more specific keys because mapping multiple lists and using the index as a key will result in duplicate keys. Keys are how react knows which item is which, and you don't want to confuse react!
P.S. Way to bum me out giving a snowboard example in the summer! lol Happy hackin'

How to filter data based on selected value from dropdown menu and search query in input field using reactjs?

i want to filter data based on the search query entered in input field from the values selected in dropdown menu.
What i am trying to do?
Consider the image below
From the select dropdown option user can select both messages and info or either of the options. Based on the option selected from dropdown menu and search query entered in the search input field it should filter data.
Suppose if user selected messages and entered search query "hello" it should retrieve messages containing text "hello" and similarly with info and messages option as well.
I am not sure how to do this. Could someone help me solve this?
Below is the code,
<div className='wrapper'>
<div>
{!state.expanded && <Svgsearch/>}
{state.expanded && props.active && <div onClick=
{this.collapse_input}><Svgsearch/></div>}
{state.expanded &&
<div className="search_input">
<input type="text" placeholder="search query" />
</div>}
<div className="search_dropdown">
<FieldDropdown on_dropdown_toggle=
{this.handle_dropdown_toggle} />
</div>
</div>
</div>);
export default class FieldDropdown extends react.component {
render = () => {
return (
<Dropdown className="category_dropdown" on_dropdown_open=
{this.handle_dropdown_open} on_dropdown_close=
{this.handle_dropdown_close}>
<div>
<button>{dropdown_text}</button>
</div>
{state.options.map((option, i) => {
return (
<DropdownItem key={i} on_select=
{this.handle_option_selection} value={i}>
<input type="checkbox" value={option.value}
checked="true" readOnly />
<span>
{option.text}</span>
</DropdownItem>)
})}
</Dropdown>);
};
Consider i have messages and info in an array of objects.
How can i write a method to filter data based on option selected from dropdown.
Thanks.
Html for query field
<input
id="searchId"
type="text"
value={this.state.queryValue}
onChange={this.handleTextChange}
/>
State
state = { data: [], filteredData:[],queryValue: '' ,value:'' };
Event Handling Method
handleTextChange = event => {
//read the value of the textbox with event.target.value
const filteredData = this.state.data.filter(d =>
// object where condition based on value(options value) & queryValue
);
this.setState({ queryValue: event.target.value, filteredData});
};
and bind UI to the filteredData.

Resources