Reactjs - Multiple choice questions - store state as array - reactjs

I have a reactjs form where the values are stored in state as follows
<input className="form-control" type="{inputType}" defaultValue="" name={this.props.questionInfo.module_question_id} key={this.props.questionInfo.module_question_id} onBlur={(e) => this.props.handleChange(e, inputType)} />
handleChange method is as follows
handleChange = (e, type) => {
let formValues = this.state.formValues;
let value = this.fetchValue(e, type)
formValues[e.target.name] = value;
this.setState({formValues: formValues});
console.log(this.state.formValues);
}
Now i have a question that can have multiple answers. User can select multiple checkboxes as answer.
The format should be
formValues: {
questionid_1: ans1_id,
questionid_2: ans2_id,
.
.
questionid_5: [answer1_id, answer2_id....]
}
The problem is that the handlechange method is looking only the current element. In this case multiple elements are to be chekced and corresponding array needs to be generated.
How to modifiy the current method? Any help would be appreciated.

You might consider storing all the option answers as array format, therefore for single choice answers, array will have only one element, for multiple answers, array will have multiple options. You also might have to categorize questions accordingly and put relevant checks in-place.
Updated code can look something like this.
handleChange = (e, type) => {
let formValues = this.state.formValues;
let value = this.fetchValue(e, type);
formValues[e.target.name] = formValues[e.target.name] || [];
formValues[e.target.name] = [...formValues[e.target.name], value];
this.setState({formValues: formValues});
console.log(this.state.formValues);
}
Here we are making sure formValues[e.target.name] is valid array.
Then we append the latest value to this array.
Thus all the answers now will be of type array, providing consistency across question answers. Avoiding complexity.
Hope this helps, thanks.

Related

I'm trying to update the row values in MUI datagrid, i'm using processRowUpdate property.But, I'm only getting recent updated cell value only

Here **Skills ** will have the array of objects which includes the values Which I'm updating.
const handleProcessRowUpdate = (newRow, oldRow) => {
console.log("update called", newRow, oldRow);
let skills = assignedskillList;
let result = skills.map((item) => {
if (item.skill_id == params.skill_id) {
console.log("ids", params.skill_id, item.skill_id);
if (item.skill_level !== newRow.skill_level) {
item.skill_level = newRow.skill_level;
}
if ((item.target_level = newRow.target_level)) {
item.target_level = newRow.target_level;
}
console.log("idsss", item.skill_level, item.target_level); // here for first column edit //I'm getting current edited value only, for the second col edit getting only second column //value.the first value is resetting
}
setUpdatedVal(result); //I'm setting this in a new array to use this for post to API
return item;
});
tried onCellEdit commit , but, thats not worked. any other solutions ?
or correct me if I'm setting the value wrongly.
Thanks In advance.....
Finally, I found it.
Hope it might be helpful for someone in future
instead of updating the value inside the map. I've just defined a result array outside and assigned the map to that, Now I can get all updated values..
Thank you...

concat strings to Reference react fc prop by constructed name from inside the component

I have a series of commonly named properties, and I'd like to have the un-common part of the name used in other places. I know that wording is a little convoluted, but perhaps an example will help. What I want is something like:
const MyComponent = ({lgProp, xlProp, mdProp, smProp, defaultProp}) => {
let current = defaultProp;
let myString = 'foo';
['sm', 'md', 'lg', 'xl'].forEach(size => {
const newValue = // somehow get the value of the property ${size}Prop
if (current !== newValue) {
myString += ` ${size}: ${newValue}`;
current = newValue;
}
});
}
The canonical answer to this type of question seems to be here, but all of the answers there either refer to dynamically referencing keys in objects, or dynamically referencing variables in pure JS in the Window or this scope. I can't seem to make any of them work for referencing property names.
There are also several sections on dynamically creating property names for components, but that's the wrong direction for me.
Things I've tried:
newValue = `${size}Prop`; // string
newValue = [`${size}Prop`]; // string
newValue = [${size} + 'Prop']; // string
newValue = this[${size} + 'Prop'] // TypeError
I mean, there are only so many props, so I could just write a bunch of if statements, but that seems so inelegant. Is there an attractive/elegant way to variably reference the prop names?

How to update an array of arrays by replacing an array item with the new corresponding array item? Reactjs

Apologies for the poorly worded title, I'm not sure how to phrase the question. I have made a quiz app in React which allows the user to choose the number of questions and for each question, there are five possible answers they can toggle between.
Because of the toggle feature, if they toggle between the possible answers, I need to be able to add the new array and replace the old corresponding one, which will then be checked to see if they are correct when they check the score. I've tried for hours to figure this out but I just can't. I've come sort of close but it only works if the user doesn't toggle between the answers.
Here's my code so far and the only semi-workable solution that I've come up with but is ugly and only works if the user doesn't toggle between answers for the same question.
function getDataFromQuestionComponent(dataFromComponent){
getQuizData.push(dataFromComponent)
// stop the score data array from growing continously
if (getQuizData.length > amount) {
maintainScoreArrayLength(getQuizData)
}
}
function maintainScoreArrayLength(quizDataArray){
// to find if which answers are matching so the original can be replaced
// with the new answer (too obscure - find a better solution)
let lastItemZeroIndexText = (quizDataArray[quizDataArray.length - 1][0].body)
for (let i=0; i<quizDataArray.length; i++) {
if (lastItemZeroIndexText === getQuizData[i][0].body) {
newArray.push(getQuizData.indexOf(getQuizData[i]))
}
}
// remove the previous item from the array
getQuizData.splice(newArray[0], 1)
}
This is what the array of object arrays looks like in the console:
The .map array method and array destructuring make it possible to do this more cleanly.
I can't quite tell how you are storing the data for the quiz questions/answers, but here's an example of how you could do it if you are saving all of the quiz data in a state object and storing the index of the current question:
const [quizData, setQuizData] = useState(initialQuizData);
const [currentQuestion, setCurrentQuestion] = useState(0);
const onSelectAnswer = (selectedAnswer) => {
// create an object with updated data for the current question
const updatedQuestionData = {
...quizData[currentQuestion],
multipleChoiceAnswers: quizData[
currentQuestion
].multipleChoiceAnswers.map((answerOption) => ({
...answerOption,
selected: selectedAnswer === answerOption.body
}))
};
// iterate through the questions
// and save either the
// updatedQuestionData or the prevState data
// (store the updatedQuestionData over the prevState data for that question)
setQuizData((prevState) => [
...prevState.map((question, index) =>
currentQuestion === index ? updatedQuestionData : question
)
]);
};
To break it down, we create a copy of the answers array but we set selected to false unless it is the answer the user just clicked:
multipleChoiceAnswers.map(answerOption) => ({
...answerOption,
selected: selectedAnswer === answerOption.body
})
The updated question object is made by copying the data from the current question, then overriding the array of answers with the updated copy of the answers we just made in the code snippet above. That is what is happening in this part:
const updatedQuestionData = {
...quizData[currentQuestion],
multipleChoiceAnswers: // The updated answers array
};
Here's a full example on code sandbox:

Why is my filtering missing result for RESTCountries API?

const filterCountry = (event) => {
console.log('input', event.target.value)
const new_countries = countries.filter(country=> country.name.official.includes(event.target.value));
setCountries(new_countries)
}
Above being my filtering function to get value matching result from Rest Countries API from axios "https://restcountries.com/v3.1/all". PROBLEM is: missing results. With input 'sw', I shall have 'Botswana, Swaziland, Sweden, Swizerland', but now only 'Botswana,Eswatini', wrong result. Can you tell where is the problem ?
The issue is that the includes is case-sensitive.
Convert both the search text and values to lower case first in filter.
country.name.official.toLowerCase().includes(event.target.value.toLowerCase())

Angular 2 / Typescript - how to check an array of objects to see if a property has the same value?

This question does it in Javascript, but I would have thought in Typescript I could do some kind of map/filter operation to do the same thing.
I have an array of objects called Room. Each Room has a property called Width (which is actually a string, eg '4m', '5m', '6.5m').
I need to check the entire array to see if all the widths are the same.
Based on that question I have this, but I was wondering if TypeScript has something better:
let areWidthsTheSame = true;
this.qp.rooms.forEach(function(room, index, rooms) {
if (rooms[index] != rooms[index+1]) areWidthsTheSame = false;
});
Any ideas?
FYI the linked question has a comment that links to these performance tests, which are interesting in the context of this question:
This can be done in the following way:
const widthArr = rooms.map(r => r.width);
const isSameWidth = widthArr.length === 0 ? true :
widthArr.every(val => val === widthArr[0]);
We first convert the rooms array to an array of widths and then we check if all values in widths arrays are equal.

Resources