Showing Results using child when clicking a button in parent component - javascript

I am Trying to build a simple trivia quiz using React and i am stuck on as to how to show the results when the user clicks "Check Answer" Button. I need to change the colors of label reflecting correct and wrong choices.
props ={
questions: arr[str]
answers: arr[arr[str]]
correct-answer: "str"
}
export default function QuestionPage(props){let [showResults,setShowResults] = React.useState(false)let Questions = []
// create 5 questions using the data from props
function getQuestions(){
for (let i =0;i<props.questions.length;i++){
Questions.push(
<Question
key= {nanoid()}
question = {props.questions[i]}
answers = {shuffle(props.answers[i])}
correct_answer = {props.correct_answers[i]}
showResults = {showResults}
/> )
}
return Questions
}
function TotalScore(){
Questions.forEach( (value,index)=>{
console.log(value,"\t",index)
})
//get all inputs using DOM and check
}
return (
<main>
{getQuestions()}
{ showResults && <TotalScore />}
<button onClick={() => setShowResults(true)}>Check Answers</button>
</main>
)
}
I was hoping to change the background color of labels inside the input field I have created for answering the questions :
Red if user selected the wrong option
Green if correct.
I can handle the css bit of coloring, just need to understand "how to implement the passing of command from button in parent component down to child component" functionality in React.
Below is the code for Question.js Component
export default function Question ({question,answers,correct_answer,showResults}) {
const [selected,setSelected] = React.useState({
selected: ""
})
function handleChange(event){
console.log(event.target,"\t",selected.selected)
setSelected( {
selected: event.target.value}
)
}
return(
<div className='question-container'>
<h4>{question}</h4>
<div className='answers-row'>
<fieldset>
<input
type="radio"
id = {answers[0]}
name = {question}
value = {answers[0]}
onChange = {handleChange}
checked = {selected.selected === answers[0]}
/>
<label htmlFor={answers[0]}>{answers[0]}</label>
<br />
<input
type="radio"
id={answers[1]}
name = {question}
value = {answers[1]}
onChange = {handleChange}
checked= {selected.selected === answers[1]}
/>
<label htmlFor={answers[1]}>{answers[1]}</label>
<br />
<input
type="radio"
id={answers[2]}
name = {question}
value = {answers[2]}
onChange = {handleChange}
checked= {selected.selected === answers[2]}
/>
<label htmlFor={answers[2]}>{answers[2]}</label>
<br />
<input
type="radio"
id={answers[3]}
name = {question}
value = {answers[3]}
onChange = {handleChange}
checked= {selected.selected === answers[3]}
/>
<label htmlFor={answers[3]}>{answers[3]}</label>
<br />
</fieldset>
</div>
</div>
)
}

In your code, you are maintaining the state ie. the answer selected by the user, on each Question component. However, when the user clicks the button QuestionPage components re-render so do its children. The getQuestions() will be invoked and components will be created again and states will again be initialized to the default value ie "".
Read this https://reactjs.org/docs/lifting-state-up.html. The example given here is similar to what you are trying to do.

Related

How to change a value inside of displayed component?

I have written a simple React code which displays a list of Film. Name, image, and "ocena" value, which should be editable. But it is in fact not editable.
I know more or less know why. Because of the value={ocena} during creation of the element in list.
<input value ={ocena} type='number' />
But I have no idea how to make it acually editable and dynamicly change the ocena value as user edits it. Is there a way ? Here is my code:
const Film = ({kk , nazwa, ocena,opis, setOcena,filmy}) => {
console.log({kk})
return(<div className="film">
<img src={kk} width={'80px'} height={'80px'} />
<li className="film_item">{nazwa}</li>
<textarea>{opis}</textarea>
<input value ={ocena} type='number'/>
<button className="delete">DELETE</button>
</div>
)
}
And the lsit itself
const Filmlist = ({filmy, setOcena , ocena}) => {
const [kk , setkk] = useState(filmy.url1);
return(
<div className="filmlist_container">
<ul className="filmlist">
{console.log(filmy)}
{filmy.map((film)=> (
<Film setOcena={setOcena} nazwa ={film.nazwa} opis = {film.opis }
ocena= {film.ocena }kk= {film.url1 } filmy={filmy}/>
))};
</ul>
</div>
)
}
Is there a simple way, or should i rewrite my code for this thing to be possible?

REACT-HOOKS: How do I store a modifed parameter made by the user?

I have checkboxes and I want to save in useState hooks the modified value made by the user. By default the current state is fixed and the checkbox is filled if my_value === 1, elif 0 unfilled. But if my user decides to uncheck it, how can I store this action. (if unchecked the value is 0).
Same idea with dropdown, the default value is fixed. The user can change the Taste( Good/Medium/Bad)or the Comments ((0/4....4/4)).
For now I get only the current state.
export default function Display() {
...
//For my checkboxes
const [availability, setAvailability] = useState(item.values[0].availability)
...
const [trust, setTrust] = useState(item.values[0].trust)
//For my dropdowns
const [taste, setTaste] = useState(item.taste)
...
const [comments, setComments] = useState(rule.comments)
function Checkbox({ value }) {
const [checked, setChecked] = useState(value);
return (
<label>
<input
type="checkbox"
checked={checked}
onChange={() => setChecked(checked => !checked)}
/>
{value}
</label>
);
}
return (
<div>
<div>
Availability : <Checkbox value={!!availability} />
</div>
....
<div >
Taste : <Dropdown style={styles.select} options={TASTE} defaultValue={LIKELIHOOD.find((t) => t.label === item.taste)} />
</div>
...
</div >
);
}
This isn't so much a hooks problem as a "where do I store my state" problem. So far I don't see any place in your implementation to store the users choices. Either the MenuItemDisplay component needs to maintain that state, or it needs to receive it from a parent component. Either way, that state (containing user choices) will need to be passed down (along with update functions) into the checkbox component as the value of a 'checked' prop, and the update functions for that state should be passed as (and adapted to) the checkbox 'onToggle' (or similar) prop

Changing colours using custom CSS properties - resetting on refresh? (ReactJS)

I am trying to allow my admins to be able to change the branding and colours of my project, I am currently using CSS custom properties to do this, however, this doesn't seem to be saving. When I refresh the page it is refreshing the colours back to it's original state. Is there a way I can fix this?
CODE
JavaScript - Admin panel
import React, { Component } from 'react'
import './CompanyBranding.scss'
import firebase from 'firebase'
export default class CompanyBranding extends Component {
state = {
content: [],
textbox: "",
link: "",
primaryColour: "",
secondaryColour: ""
}
componentDidMount() {
firebase.firestore().collection('site').doc('public').collection('footer').doc('content').get().then(doc => {
const content = []
const data = doc.data()
this.setState(data)
content.push(data)
this.setState({content})
this.setState({contentLength: content.length})
})
}
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value,
})
}
handleSubmit = (e) => {
e.preventDefault();
firebase.firestore().collection('site').doc('public').collection('footer').doc('content').set({
textbox: this.state.textbox,
link: this.state.link
}).then(alert("Updated"),
document.getElementById("companydetails").reset()
)
document.documentElement.style.setProperty(
'--primary-color',
this.state.primaryColour
)
document.documentElement.style.setProperty(
'--secondary-color',
this.state.secondaryColour
)
}
render() {
return (
<div>
<div className="CompanyBranding">
<h1 className = "PageHeading"> Branding</h1>
<form className = "CompanyBrandingForm">
<label htmlFor = "Logo"> Company Logo</label> <br/>
<input type = "file" id = "Logo" name = "Logo" accept = "image/png, image/jpeg"/><br/><br/>
<label htmlFor = "PrimaryColour"> Primary Colour </label> <br/>
<input type = "color" id = "primaryColour" name = "PrimaryColour" onChange = {this.handleChange}/><br/><br/>
<label htmlFor = "SecondaryColour"> Secondary Colour </label> <br/>
<input type = "color" id = "secondaryColour" name = "SecondaryColour" onChange = {this.handleChange}/><br/><br/>
<button onClick = {this.handleSubmit} className = "SubmitButton"> Submit </button>
</form>
</div>
<div className="FooterContent">
<h1 className = "PageHeading"> Footer </h1>
<form className = "CompanyBrandingForm">
<label htmlFor = "textbox"> Text box</label> <br/>
<textarea id = "textbox" value = {this.state.textbox} onChange = {this.handleChange} />
<br/><br/>
<label htmlFor = "link"> GDPR link </label> <br/>
<input type = "text" id = "link" value = {this.state.link} onChange = {this.handleChange}/>
<button onClick = {this.handleSubmit} className = "SubmitButton"> Submit </button>
</form>
</div>
</div>
)
}
}
Variables.scss
:root {
--primary-color: #2f78e6;
--secondary-color:#2d4f81;
}
// Primary colour (can be changed by admin)
$base-colour: var(--primary-color);
$secondary-color: var(--secondary-color);
When you refresh the page your entire application is rerendered. So the color goes back to the default value as the state is lost. This means you need some kind of persistence.
Depending on what you're trying to achieve there are a few options:
If you want the admin to change the theme for everyone you should store that theme in some kind of database, for instance, Firestore as you are already using it. When you initialize the state, you run a query and fetch the value from Firestore.
If you want the admin to change the theme only for himself, you can set the preferred color in the localStorage and then fetch the value from it when you initialize the state.
Whatever style you change within React (or JS for that matter) will only be valid until the user refreshes or closes the page, because that's the scope of JavaScript.
If you want to create a theme functionality where users can choose their own theme, you should store their choice either in the localstorage or in the database (persistent storage). Only then, their choice will persist through refreshes. So, store the user's choice that you are getting from the form somewhere permanent (not in a React state).
And whenever the app loads, you have to fetch the user's choice from whichever persistent storage you used, and set the property (as you did) in CSS.

Validating a value when button is pressed before passing it

Hi I am new to React and I am a little bit confused on how to validate a value before passing it to the partialRefund function I have.
I am trying to set a simple validation to make sure the value is not empty and numeric before passing it to the partialRefund function.
The first line is the code I currently have. The second line is the code I am trying to write for the validation but it is not working.
Any help would be really appreciated! Thanks!
//Current code
{partialRefundSelected ? <div> <input id={`partial_refund_${order_id}`} type='text'/> <button onClick={() => partialRefund(order_deets_obj,"partialRefund",document.getElementById('partial_refund_'+order_id).value)}> Refund Order </button> </div> : ""}
//Code I am trying to use
{partialRefundSelected ? <div> <input id={`partial_refund_${order_id}`} type='text'/> <button onClick={(validateValue(document.getElementById('partial_refund_'+order_id).value)) => partialRefund(order_deets_obj,"partialRefund",document.getElementById('partial_refund_'+order_id).value)}> Refund Order </button> </div> : ""}
On the second line i am trying to pass a function that will validate the value and the pass it to the partialRefund function. But it doesnt seem to be working :(
Use this:
{
partialRefundSelected ?
<div>
<input id={`partial_refund_${order_id}`} type='text'/>
<button onClick={() => {
const validatedValue=validateValue(document.getElementById('partial_refund_'+order_id).value));
partialRefund(order_deets_obj,"partialRefund",validatedValue);
}}> Refund Order
</button>
</div> :
""}
You can do the validation in the onClick callback if you add curly brackets around the parttialRefund call.
export default function App() {
const partialRefundSelected = true;
const order_id = 1;
const order_deets_obj = { deets: "good deets" };
const partialRefund = (deets, someString, someValue) => {
console.log(deets, someString, someValue);
};
return partialRefundSelected ? (
<div>
<input id={`partial_refund_${order_id}`} type="text" />
<button
onClick={() => {
const value = document.getElementById("partial_refund_" + order_id)
.value;
// Do validation here
if (value === "I LOVE CATS") {
partialRefund(order_deets_obj, "partialRefund", value);
}
}}
>
Refund Order
</button>
</div>
) : (
""
);
}
While this is an option in react, I would suggest making your input a Controlled Component. This would allow you to keep the input's text in state instead of needing to pull the text off of the element after a click. Here is an example.

How to use checkbox as Radio Button in ReactJS with hooks?

I'm Building a filter in ReactJS with hooks and now I need apply some style to the checkboxes.. The CSS is not the problem, I already did it in vanilla:
function checkOne(checkbox) {
var checkboxes = document.getElementsByName('plan')
checkboxes.forEach((item) => {
item !== checkbox ? item.checked = false : item.checked = true;
})
}
=======================================================================
X 3
<label for="premium">
<input
type="checkbox"
name="plan"
onclick="checkOne(this)"
class="input-check"
value="Premium"
>
<span
class="checkmark"
id="premium"
>
Premium
</span>
</label>
Now I need to do the same think in react with hooks and I get stuck, I'm mapping a source of products and making a list of checkboxes form the product categories...
...
const [checked, setChecked] = useState(false) //hook
...
handleChange(e, checkbox){
setProduct(e.target.value);
setSearch(e.target.value);
let checkboxes = document.getElementsByName('products')
checkboxes.forEach((item) => {
item !== checkbox ? setChecked(false) : setChecked(true);
})
}
... in render method
<div className="filters" id="top">
{uniqueProduct.map(product => (
<label key={product.id}>
<input
className='filters-available-size'
type="checkbox"
value={product.category}
onChange={handleChangeProduct} // <-- ?¿?¿ what should go here?
name='product'
/>
<span className="checkmark">
{product.category}
</span>
</label>
))}
</div>
Why do you need to use checkboxes as radio buttons? I'm going to assume because of the styling--a design decision, perhaps. In which case, I would use radio buttons for the functionality and then use CSS to hide radio buttons and show checkboxes that reflect the state of the chosen option.

Categories

Resources