How to make radio button checked/active depending on current state value - javascript

so I've got a header that cycles through 4 images every 5 seconds. The user can also cycle through these images themselves using 5 radio buttons.
The styling for the active/checked radio button is applied when the user clicks it themselves, however, if the timer switches the image the active radio button remains unchanged.
I know this is the expected behaviour based on my code below, I'm just wondering how I would go about changing the checked radio button to match it's current image!
Any help would be appreciated!
constructor(props) {
super(props);
this.state = {
time: 0,
start: 0,
currentIndex: 0
};
this.setIndex = this.setIndex.bind(this);
this.startTimer = this.startTimer.bind(this);
this.resetTimer = this.resetTimer.bind(this);
}
componentDidMount() {
this.startTimer();
}
componentDidUpdate() {
if (this.state.time === 5) {
this.setIndex(this.state.currentIndex + 1);
}
}
startTimer() {
this.timer = setInterval(
() =>
this.setState({
time: this.state.time + 1
}),
1000
);
}
resetTimer() {
this.setState({ time: 0 });
}
setIndex(index, e) {
console.log("changing");
if (index < 0) {
index = headers.length - 1;
}
if (index >= headers.length) {
index = 0;
}
this.setState({
currentIndex: index,
time: Date.now() - this.state.start
});
this.resetTimer();
}
... skipped code
<div className="carousel">
<img
alt="carousel-header"
className="background-img"
src={headers[this.state.currentIndex].image}
/>
<div className="buttons-container">
<input
type="radio"
value="1"
defaultChecked
name="index"
onClick={() => this.setIndex(0)}
></input>
<input
type="radio"
value="2"
name="index"
onClick={() => this.setIndex(1)}
></input>
<input
type="radio"
value="3"
name="index"
onClick={() => this.setIndex(2)}
></input>
<input
type="radio"
value="4"
name="index"
onClick={() => this.setIndex(3)}
></input>
</div>
</div>

You can check currentIndex for automatic change radio buttons.
In render function
const { currentIndex } = this.state
<div className="buttons-container">
<input
type="radio"
value="1"
defaultChecked
name="index"
checked={currentIndex === 0}
onClick={() => this.setIndex(0)}
></input>
<input
type="radio"
value="2"
name="index"
checked={currentIndex === 1}
onClick={() => this.setIndex(1)}
></input>
<input
type="radio"
value="3"
name="index"
checked={currentIndex === 2}
onClick={() => this.setIndex(2)}
></input>
<input
type="radio"
value="4"
name="index"
checked={currentIndex === 3}
onClick={() => this.setIndex(3)}
></input>
</div>

If I understood correctly, you are using radio buttons which are getting activated onclick (which is default HTML behavior) and are not when using your timer.
It is piece of cake, you just need to activate them via JS each time the timer switches background.
You probably assumed that your setIndex() function will run everytime your timer makes a change, but that is not a case, since that function only launches when person physically clicks on radio, or onClick event is emitted.
Because of:
onClick={() => this.setIndex(3)}
To fix it you should modify this piece of code:
startTimer() {
this.timer = setInterval(
() =>
this.setState({
time: this.state.time + 1
}),
1000
);
}
resetTimer() {
this.setState({ time: 0 });
}
There you should set the value of radio box, and update the state of index.
When resetting remember to reset the state value function and set value of radio box to #1 radio.

Related

Increment and decrement counter on checkbox

I am working with Next.js to handle a question form that has different kinds of questions with single choice answers and multiple choice. I have a progress bar in which its percentages change according to selected answers. when I select a question's answer I increment a counter and when I unselect an answer decrement the counter.
1 - When I select a checkbox of a question at first increment the counter, but it must not increment when I select the second checkbox in the same question.
2 - When I unselect multiple-choice questions answer it must not decrement if any one of them is selected it must not decrement until the last one is unselected.
Now when selecting the first time it increments the counter but after that, if I select or unselect, it decrements.
Please help me to handle this.
Question sample:
This is my code:
<MuilteSelectQuestion
key={item.attributes.Number}
id={item.attributes.Number}
data={item}
name={`${item.attributes.Number}`}
handleMultiChecked={handleMultiChecked}
/>
The component:
<div className="relative flex items-start">
{Object.keys(attributes?.options).map(item => (
<>
<div className="flex items-center h-5">
<input
{...feild}
{...props}
id={item}
type="checkbox"
name={`${name}[]`}
value={`${item}`}
onClick={e =>
handleMultiChecked(
`question${id}`,
e.target.checked
)
}
className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div>
<div className="ml-2 mr-3 text-sm">
<label
htmlFor={item}
className="font-medium text-gray-700"
>
{item}
</label>
</div>
</>
))}
</div>
The function:
function handleMultiChecked(val, checked) {
setCompareTitle(val);
if (val !== compareTitle && checked) {
setCounter(++counter);
} else {
setCounter(--counter);
}
}
useEffect(() => {
setPercent((parseInt(counter) / parseInt(dataCount)) * 100);
}, [counter]);
The data that come from backend:
I'd suggest you have another state to track all questions' counters
const [questionCounters, setQuestionCounters] = useState({})
Apply it to handleMultiChecked
function handleMultiChecked(val, checked) {
setCompareTitle(val);
const currentQuestionCounter = questionCounters[val] || 0 // if this question is not in the state, the default counter will be 0
const updatedQuestionCounter = checked ? currentQuestionCounter + 1 : currentQuestionCounter - 1 //update the current question's counter based on checked
//no ticks on the current question, we decrease the main counter
if (currentQuestionCounter === 1 && updatedQuestionCounter === 0) {
setCounter(--counter);
}
//first tick, we increase the main counter
if(currentQuestionCounter === 0 && updatedQuestionCounter === 1) {
setCounter(++counter);
}
//apply the latest counters' changes for question list
setQuestionCounters({
...questionCounters,
[val]: updatedQuestionCounter
})
}
useEffect(() => {
setPercent((parseInt(counter) / parseInt(dataCount)) * 100);
}, [counter]);

react js update value from multiple radio and text box

I have an issue of updating state values of a particular key. Using multiple radio button and textbox.
Here is my state
this.state = {
PStudent:[{"flag_sts":1,"id":8472229,"remark":null,"status":"P","studentid":"12010013"},
{"flag_sts":1,"id":8472218,"remark":null,"status":"P","studentid":"12108051"},
{"flag_sts":1,"id":8472219,"remark":null,"status":"P","studentid":"12108052"}
],
};
On change value on radio:
const handleChange = (e,studentid) =>{
this.setState({
data: this.state.PStudent.map(item=>{
if (item.studentid !== e.target.name) {
return item;
}else{
return{
studentid: studentid,
status : e.target.value
}
}
})
})
}
And this is sending parameter form radio:
{(Object.keys(this.state.PStudent).length > 0) ? (
this.state.PStudent.map((v)=>(
<tr>
<td>{v.studentid}</td>
<td><input type="radio" name={v.studentid} value="P" onChange={(e)=>handleChange(e,v.studentid)} defaultChecked={(v.status == "P") ? true:false} /> </td>
<td><input type="radio" name={v.studentid} value="A" onChange={(e)=>handleChange(e,v.studentid)} defaultChecked={(v.status == "A") ? true:false} /> </td>
<td><input type="text" name="remarks" value="" /> </td>
</tr>
))
) : ''}
Would you like to help me how to update some value of particular key? In this case i would like to update value from key 'status' by radio button and key 'remarks' by text box. And object from PStudent will auto updated with the new value after do handleChange() by radio.
Thank you for your consider.
You may want to make use of the dynamic key and index here.
The dynamic key would allow you to reuse the same function for the value change.
The index can be used to identify the object's index in the array.
const handleChange = (e, index, field) =>{
const newPStudent = _.cloneDeep(this.state.PStudent); // or you can use this.state.PStudent.map(i => I);
newPStudent[index][field] = e.target.value
this.setState({PStudent: newPStudent})
}
{(Object.keys(this.state.PStudent).length > 0) ? (
this.state.PStudent.map((v, index)=>(
<tr>
<td>{v.studentid}</td>
<td><input type="radio" name={v.studentid} value="P" onChange={(e)=>handleChange(e, index, 'status')} defaultChecked={(v.status == "P") ? true:false} /> </td>
<td><input type="radio" name={v.studentid} value="A" onChange={(e)=>handleChange(e, index, 'status')} defaultChecked={(v.status == "A") ? true:false} /> </td>
<td><input type="text" name="remarks" value="" onChange={(e)=>handleChange(e, index, 'remark')}/> </td>
</tr>
))
) : ''}
If you are using underscore.js in your project, it's best to use _.cloneDeep() as it creates an independent copy of the object.
You can use functional version of setState as:
Live Demo
handleChange = (e, studentid) => {
const status = e.target.value;
this.setState((state) => {
return {
PStudent: state.PStudent.map((item) => {
if (item.studentid !== e.target.name) return item;
else return { ...item, status };
})
};
});
};

html5 input type range always pointing to min value and not getting onChange on text input

I am trying to use input type text along with input type range where three usecases are there.
1. defaultcase: when page is loaded the slider should point to the value as given in the text input field.
2. when user enters the text value, the slider pointer should also update.
3. when user uses the slider to change value, the text value should get updated.
In my below code
In default case: in input type range when i give defaultValue="200" the slider pointer points always to min value.
When i enter value in text area, the slider is not getting updated.
i tried some ways to fix it but failing.
if (
Type == "integer" &&
LowerBound &&
UpperBound !== 0
) {
editComponent = (
<div className="SettingsTreeValueNode__InputField">
<input
type="text"
pattern="[0-9]*"
ref="text"
value={this.state.value}
oninput={this.handleinputChanged.bind(this)}
className="inputtext"
onBlur={e => this.focusOfInputLost(e)}
/>
{LowerBound}
<input
type="range"
className="sliderinput"
defaultValue="200"
min={LowerBound}
max={UpperBound}
step="1"
oninput={this.handleSliderChange.bind(this)}
onMouseUp={this.handleWhenMouseReleased.bind(this)}
/>
{UpperBound}
</div>
);
}
handleSliderChange(event) {
var value = event.target.value;
var slidervalue = parseInt(value);
this.setState({ value: slidervalue });
}
handleInputChanged(event) {
var value = event.target.validity.valid
? event.target.value
: this.state.value;
this.setState(
{
value: value,
inputValid: this.isInputValid()
});
}
ยดยดยด[![slider along with text area][1]][1]
[1]: https://i.stack.imgur.com/w5MZ6.png
Below code will solve your problems, only use single state object to display value in both controls now it will works in both way either change value on input or slider.
class App extends Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
}
handleSliderChange = (event) => {
var value = event.target.value;
var slidervalue = parseInt(value);
this.setState({ value: slidervalue });
}
handleInputChanged = (event) => {
var value = event.target.validity.valid
? event.target.value
: this.state.value;
this.setState(
{
value: value
});
}
render() {
let LowerBound = 0;
let UpperBound = 200
return (
<div>
<button onClick={this.handleCopy}>click me</button>
<div className="SettingsTreeValueNode__InputField">
<input
type="text"
pattern="[0-9]*"
ref="text"
value={this.state.value}
onInput={this.handleInputChanged}
className="inputtext"
/>
{LowerBound}
<input
type="range"
className="sliderinput"
defaultValue="200"
min="0"
max="200"
step="1"
value={this.state.value ? this.state.value : UpperBound}
onInput={this.handleSliderChange}
/>
{UpperBound}
</div>
</div>
);
}
}
export default App;

Component didn't re-renders on state change?

I am creating a random quote generator. There is a quote box that displays quote and author names. I created a method to invoke on a button click that may randomize the quote list and display a new quote and a next button to get next quote from my quote list. I can see the first quote but the component didn't re-renders on clicking buttons or something gets wrong that I can't get next quote or can't randomize. Here is the code:
class UI_qoutebox extends React.Component {
constructor(props) {
super(props);
this.state = { qoutes: props.qoutes, authors: props.authors, num: 0 };
this.UI_rq = this.UI_rq.bind(this);
this.UI_next = this.UI_next.bind(this);
}
UI_rq() {
let rnd = Math.floor(Math.random() * this.state.qoutes.length);
this.setState({ num: rnd });
}
UI_next() {
let p = this.state.num + 1;
if (p > this.state.qoutes.length) { p = 0 }
this.setState({ num: p })
}
render() {
const { qoutes, authors, num } = this.state;
return (
<div className="qoute-box">
<span className="qoute">{qoutes[num]}</span>
<span>{authors[num]}</span>
<input type="button" value="Randomize" onClick={() => this.UI_rq} />
<input type="button" value="Next" onClick={() => this.UI_next} />
</div>
)
}
}
I am working on Freecodecamp's project and I need quick help. Thanks in advance.
Change this
<input type="button" value="Randomize" onClick={this.UI_rq}/>
<input type="button" value="Next" onClick={this.UI_next}/>

uncheck checkbox programmatically in reactjs

I am messing with checkboxes and I want to know that is there a way in which I can uncheck a checkbox on click of a button by calling a function?? If so? How can I do that?
<input type="checkbox" className="checkbox"/>
<button onClick={()=>this.unCheck()}
How can I uncheck the checkbox programmatically and what if I have multiple checkboxes generated dynamically using map function.
How can I uncheck them If I want to?
There is property of checkbox checked you can use that to toggle the status of check box.
Possible Ways:
1- You can use ref with check boxes, and onClick of button, by using ref you can unCheck the box.
2- You can use controlled element, means store the status of check box inside a state variable and update that when button clicked.
Check this example by using ref, assign a unique ref to each check box then pass the index of that item inside onClick function, use that index to toggle specific checkBox:
class App extends React.Component{
constructor(){
super();
this.state = {value: ''}
}
unCheck(i){
let ref = 'ref_' + i;
this.refs[ref].checked = !this.refs[ref].checked;
}
render(){
return (
<div>
{[1,2,3,4,5].map((item,i) => {
return (
<div>
<input type="checkbox" checked={true} ref={'ref_' + i}/>
<button onClick={()=>this.unCheck(i)}>Toggle</button>
</div>
)
})}
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
Check this example of controlled element, means storing the state of checkbox inside state variable, and on click of button change the value of that:
class App extends React.Component{
constructor(){
super();
this.state = {value: []}
}
onChange(e, i){
let value = this.state.value.slice();
value[i] = e.target.checked;
this.setState({value})
}
unCheck(i){
let value = this.state.value.slice();
value[i] = !value[i];
this.setState({value})
}
render(){
return (
<div>
{[1,2,3,4,5].map((item,i) => {
return (
<div>
<input checked={this.state.value[i]} type="checkbox" onChange={(e) => this.onChange(e, i)}/>
<button onClick={()=>this.unCheck(i)}>Toggle</button>
</div>
)
})}
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
React
Checked
Using State
<input type="radio" name="count" value="minus" onChange={this.handleRadioChange} checked={this.state.operation == "minus"} /> Decrement
2.Using Refs
<input type="radio" name="count" ref="minus" /> Decrement
onSubmit(e){ this.refs.minus.checked = false }
Using plain javascript you can acheive like below.
function unCheck() {
var x = document.getElementsByClassName("checkbox");
for(i=0; i<=x.length; i++) {
x[i].checked = false;
}
}
Small DEMO
I was thinking of a thing like that:
<input onChange={(input) => this.onFilterChange(input)} className="form-check-input" type="checkbox" />
onFilterChange = (input) => { let { value, checked } = input.target;}
unCkeckAll = () => {
[...document.querySelectorAll('.form-check-input')].map((input) => {
if (input.checked) {
let fakeInput = {
target: {
value: input.value,
checked: false
}
}
input.checked = !input.checked;
this.onFilterChange(fakeInput);
}
return null;
})
}
Checkboxes have a checked property, you can hook it to the state and change it dynamically. Check these links:
https://facebook.github.io/react/docs/forms.html#handling-multiple-inputs
http://react.tips/checkboxes-in-react/
Sometime its good to use plain javascript. If you have of checkbox value in any of your state then try this
let checkboxValue = xyz
document.querySelectorAll("input[value="+checkboxValue+"]")[0].checked = false;

Categories

Resources