I have implemented a form in which a Select dropdown is taking dynamic data from server.
Now when I select a option from dropdown, it is showing value in the field, but after saving the form or cancel saving it, when I reopen the form, the selected value is not cleared from field.
What needs to be done to correct it?
Here is my code:
class Task extends Component{
constructor(props){
super(props);
this.state={
SelectedName:'',
TaskList:[],
}
}
componentWillMount(){
fetch(
...
.then(responseJson => {
let taskList=responseJson.data;
let r = taskList.map(function(task){
return {value: task.id, display: task.name}
});
this.setState({TaskList:r });
}
//this is cancelForm fucntion
cancelSave=()=>{
this.setState({SelectedName:''});
}
handleNameSelection=()=>{
var row = this.state.TaskList.filter(function (item) {
return item.value == event.target.value
})
this.setState({ SelectedName: row[0].display});
}
render(){
return(
<Select
defaultValue="placeholder-item"
id="select-task-name"
labelText="Select Task Name"
value={this.state.SelectedName}
onChange={(event) => this.handleNameSelection(event)}
>
{
(this.state.TaskList.length > 0) ?
this.state.TaskList.map(function (list, idx) {
return <option key={idx}
value={list.value}>{list.display}</option>
})
:
<option />
}
</Select>
);
}
}
You should empty array list of tasks in the state after your form submit
here I can't see your submit function ( if you're using this above as subcomonent it's another logic to implement otherwise see below example )
as example :
let onSubmit = (values) => {
/* form submit stuff */
this.setState({
...state,
SelectedName:''
});
}
Related
I have a dropdownlist. Based on selected dropdown item i have to display currency. Here is the data structure : [{mruCode: "1700", country: "US", countryText: "United States", division: "WORLDWIDE_INDUSTRIAL",currency:"USD"}....]. I mapped this data to my select item. Now based on selected item (ex: division: "WorldWIDE_Industrial") i have to show currency(ex. "USD") in a label. If dropdown value change then onChange event will fire and display the corresponding currency.
I have created the action and reducer for this and filter the list based onChange action fire. I am not able to understand how to handle the change event. Please help on this.
component code:
class LocationList extends React.Component{
constructor(props){
super(props);
this.state={
isLoading:false,
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.props.loadData();
}
handleChange(mruCode){
this.props.currencyLists(mruCode);
}
render(){
const{location}=this.props;
console.log(this.props.currList);
const _labels = store.getLabels();
return(<div>
<span className="btnElement_spacing">You are viewing pricing for </span>
//here is the problem start i assume
<select id="toggleLocationName">
{location.map((item,index) =>
<option key={index} onChange={()=>this.handleChange(item.mruCode)}> value={index}>{_labels[item.division]}</option>
)}
</select>
<span className="btnElement_spacing"> in </span>
{this.props.currList.map((item,index)=><label id="toggle-currency" key ={index}>{item.currency}</label>)}
</div>
);
}
}
const mapStateToProps = state => {
return {
location: state.locationRed.location,
currList: state.locationRed.currList
}
}
const mapDispatchToProps = dispatch => {
return {
loadData:()=>{dispatch(loadData())},
currencyLists:(mruCode)=>{dispatch(currencyLists(mruCode))}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(LocationList);
action code:
export const currencyLists = mruCode =>({
type: CURRENCY_LIST,
payload: mruCode
});
reducer code:
case 'CURRENCY_LIST':
let newState = Object.assign({}, state)
let newCurrList = newState.location.filter((el) => el.mruCode === action.mruCode)
return Object.assign({}, newState, {
currList: newCurrList
});
i am trying to filter out the main list based on mruCode with action id for onChange and saved the result into a currList. mapped to display the currency. But i am failed. currList initially showing empty. onChange not triggered. How to make action fire to show the currency
Onchange should be called on select tag(not on option tag). Below code should work.
<select id="toggleLocationName" onChange={this.handleChange}>
{location.map((item, index) =>
<option key={index} value={item.mruCode}>{_labels[item.division]}</option>
)}
</select>
handleChange(e){
this.props.currencyLists(e.target.value);
}
In React I'm creating a multiple choice questionnaire. Checkboxes are generated with the possible answers. When the user ticks the answers and reloads the page, the chosen answers' checkboxes do not retained their checked state.
The questions and answers are fetched from database as an array of objects on 1st load. The user can tick multiple checkboxes for a question. A 2nd array is created that includes all the multiple answers that user has chosen and sent to database has objects. On reload, this 2nd array is added to the state of the component as well as the 1st array.
Component
const Checkbox = ({ id, name, options, onChange }) => {
return (
<div className="checkbox-group">
{options.map((option, index) => {
<div key={index}>
<label htmlFor={id}>
<input
type="checkbox"
name={name}
id={id}
value={option}
onChange={onChange}
/>
{option}
</label>
</div>
}
</div>
);
}
class Form extends Component {
constructor(props) {
super(props);
this.state = {
questionnaire: [],
answeredQuestions: [],
formData: {},
};
this.handleChange = this.handleChange.bind(this);
}
async componentDidMount() {
// it doesn't matter how I fetch the data, could have been axios, etc...
let questionnaire = await fetch(questionnaireUrl);
let answeredQuestions = await fetch(answeredQuestionsUrl);
this.setState({ questionnaire, answeredQuestions });
}
render() {
return (
<div className="questionnaire-panel">
<h1>Quiz</h1>
{this.state.questionnaire.map((question, index) => {
return (
<div key={index}>
<Checkbox
options={questions.answers}
checked={// this where I'm stuck on what to do}
name="the-quiz"
id={`the-quiz_num_${index + 1}`}
onChange={this.handleChange}
/>
</div>
)
})}
</div>
);
}
handleChange(event) {
let target = event.target;
let value = target.value;
let name = target.name;
let chosenAnwersArray = [];
let chosenAnswer = {
answer: value,
checked: true,
};
if (this.state.questionnaire.includes(chosenAnswer)) {
newChosenAnwersArray = this.state.questionnaire.filter(q => {
return q.answer !== chosenAnswer.answer;
});
} else {
newChosenAnwersArray = [...newChosenAnwersArray, chosenAnswer];
}
this.setState(prevState => ({
formData: {
[name]: value,
},
answeredQuestions: newChosenAnwersArray
}));
}
}
I want to compare these 2 arrays that are in the this.state, that if the answers in the array2 are in array1 then check the corresponding checkboxes. Is there is a better way, please teach me!
I wrote a Checkbox component, with React, that is reused to generate a list of checkboxes. I know that a react element is different from a DOM in terms of state. But how do I check if at least 1 checkbox has been selected by the user on form submit in React?
I have searched in SO and Google but all examples are either in jQuery or vanilla JS. For my case I want a React example.
component
const Checkbox = ({ title, options, id, name, onChange }) => {
return (
<div className="checkbox-group">
<h4>{title}</h4>
{options.map(option => (
<label htmlFor={`${name}-${index}`} key={`${name}-${index}`}>
<input
type="checkbox"
name={name}
value={option}
onChange={onChange}
id={`${name}-${index}`}
/>
<span> {option}</span>
</label>
))}
</div>
);
};
class Form extends Component {
...
handleChange(event) {
let newSelection = event.target.value;
let newSelectionArray;
newSelectionArray = [
...this.state.sureveyResponses.newAnswers,
newSelection,
];
this.setState(prevState => {
return {
surveyResponse: {
...this.state.surveyResponse,
newAnswers: newSelectionArray,
}
)
}
handleSubmit() {
// I'm guessing this doesn't work in React as it's using its own state!
let checkboxes = document.querySelectorAll('[name="quiz-0"]:checked');
for (let chk in checkboxes) {
if (chk.checked) {
return true;
}
}
alert('Please choose at least one answer.');
return false;
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<h4>Choose</>
{this.state.surveyQuiz.map((quiz, index) => {
return (
<div key={index}>
<Checkbox
title={quiz.question}
options={quiz.answers}
name={`quiz-${index + 1}`}
onChange={this.handleChange}
/>
</div>
);
})};
<button>Save answer(s)</span>
</form>
);
}
}
When the user submits the form, it should check if at least a checkbox is checked, if not none is checked then prevent the form to submit, i.e. return false!
You should also maintain the checked property in surveyResponse.newAnswers state. Then, you'll be able to check if any of them is true. For eg.:
const nA = this.state.surveyResponse.newAnswers
const isChecked = nA.some(c => c.checked == true)
if(isChecked) {
//...if any of them has checked state
}
Assuming example newAnswers data:
[
{answer:'foo', checked: false},
{answer:'bar', checked: true},
...
]
The following shows how to change your handleSubmit to read form data:
handleSubmit(event) {
event.preventDefault();
const form = event.target;
const data = new FormData(form);
for (let name of data.keys()) {
const input = form.elements[name];
console.log(input);
console.log('value:', input.value);
}
}
I have a <Select> component from react-select renders a couple options to a dropdown, these options are fetched from an api call, mapped over, and the names are displayed. When I select an option from the dropdown the selected name does not appear in the box. It seems that my handleChange method is not firing and this is where I update the value of the schema name:
handleChange = value => {
// this is going to call setFieldValue and manually update values.dataSchemas
this.props.onChange("schemas", value);
This is not updating the value seen in the dropdown after something is selected.
I'm not sure if I'm passing the right thing to the value prop inside the component itself
class MySelect extends React.Component {
constructor(props) {
super(props);
this.state = {
schemas: [],
fields: [],
selectorField: ""
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
axios.get("/dataschemas").then(response => {
this.setState({
schemas: response.data.data
});
console.log(this.state.schemas);
});
}
handleChange = value => {
// this is going to call setFieldValue and manually update values.dataSchemas
this.props.onChange("schemas", value);
const schema = this.state.schemas.find(
schema => schema.name === value.target.value
);
if (schema) {
axios.get("/dataschemas/2147483602").then(response => {
this.setState({
fields: response.data.fields
});
console.log(this.state.fields);
});
}
};
updateSelectorField = e => {
this.setState({ selectorField: e.target.value });
};
handleBlur = () => {
// this is going to call setFieldTouched and manually update touched.dataSchemas
this.props.onBlur("schemas", true);
};
render() {
return (
<div style={{ margin: "1rem 0" }}>
<label htmlFor="color">
DataSchemas -- triggers the handle change api call - (select 1){" "}
</label>
<Select
id="color"
options={this.state.schemas}
isMulti={false}
value={this.state.schemas.find(
({ name }) => name === this.state.name
)}
getOptionLabel={({ name }) => name}
onChange={this.handleChange}
onBlur={this.handleBlur}
/>
{!!this.props.error && this.props.touched && (
<div style={{ color: "red", marginTop: ".5rem" }}>
{this.props.error}
</div>
)}
</div>
);
}
}
I have linked an example showing this issue.
In your handleChange function you are trying to access value.target.value. If you console.log(value) at the top of the function, you will get:
{
id: "2147483603"
selfUri: "/dataschemas/2147483603"
name: "Book Data"
}
This is the value that handChange is invoked with. Use value.name instead of value.target.value.
I am trying to get a select to show/hide on check but the select just renders and does not disappear nor reappear. I am fairly new to react, so I am sure I am doing something wrong.
export default class TreeTest extends Component {
constructor() {
super();
this.state = {
checked: [
'/grantSettingsPermissions/Admin',
'/grantSettingsPermissions/ContentGroups/AddLocations',
],
expanded: [
'/grantSettingsPermissions',
'/grantSettingsPermissions/ContentGroups',
],
};
this.onCheck = this.onCheck.bind(this);
this.onExpand = this.onExpand.bind(this);
this.handleChange = this.handleChange.bind(this);
}
onCheck(checked) {
console.log(checked);
this.setState({
checked,
});
}
onExpand(expanded) {
this.setState({
expanded,
});
}
handleChange() {
this.setState({
checked: !this.state.checked,
});
}
render() {
const { checked, expanded } = this.state;
const content = this.state.checked
? <select>
<option value="test1">test1</option>
<option value="test2">test2</option>
</select>
: null;
return (
<div>
{ content }
<CheckboxTree
checked={checked}
expanded={expanded}
nodes={nodes}
onCheck={this.onCheck}
onExpand={this.onExpand}
expandDisabled={true}
onChange={ this.handleChange }
/>
</div>
);
}
}
I have a feeling I just need to add stuff to the onCheck function, but I am not entirely sure. Any help would be awesome!
Your condition should be:
const content = this.state.checked.length === 0
? <select>
<option value="test1">test1</option>
<option value="test2">test2</option>
</select>
: null;
I'm not sure what your component CheckboxTree does, but here is some info that applies to regular input controls:
Your event handler onChecked is expecting checked to be the value of your checkbox, but in fact it will be an event object. So you need to get the value from the event object and set the state with that:
onCheck(e) {
console.log(e);
let checked = {checked: e.target.value}
this.setState({
checked,
});
}
UPDATE
I see from the documentation that they are doing it the same way, so it should work, because your code is equivalent to this:
onCheck={checked => this.setState({ checked })}
onExpand={expanded => this.setState({ expanded })}