Problem with refreshing part of component - javascript

Hello I've got a problem with refreshing component, it doesn't work, in console log shows properly data. I want after click on div to change clicked element on true and add to this element changed class name
below is jsx
{tabObjects.map((item) => (
<div
key={item.key}
id={item.key}
className={item.isChecked ? checked : notChecked}
onClick={() => selectItem(item.key)}
>
<i className={item.icon}></i>
<p className="hide-sm">{item.pText}</p>
</div>
))}
after clicking selectItem I want to change class name to checked and rest of them set checked as false so:
const selectItem = (e) => {
tabObjects.map((item) => {
item.isChecked = false;
if (e === item.key) {
item.isChecked = true;
}
});
setTabObjects(tabObjects);
};
and sample data json
const [tabObjects, setTabObjects] = useState([
{
key: "sample1",
isChecked: true,
icon: "sample1i",
pText: "Test text",
},
{
key: "sample2",
isChecked: false,
icon: "sample2i",
pText: "Test text",
},
]);
let checked = "sampleClass checked";
let notChecked = "sampleClass";
What Am I doing wrong? Clicking on any div with console log working fine

Missing return statement is the reason.
const selectItem = (e) => {
const objects = tabObjects.map((item) => {
item.isChecked = false;
if (e === item.key) {
item.isChecked = true;
}
return item;
});
setTabObjects(objects);
};

Related

Displaying newest element on top in React

I am creating a React application. I want to display the last added note on top.
Notes is an array of objects. As you can see I've tried notes.reverse() but somehow it's not working. Elements are still adding at the bottom.
<div>
{notes.reverse().map((note)=> (
<NotesCard
note={note}
key={note.id}
setInputText={setInputText}
setInputTitle={setInputTitle}
setNotes={setNotes}
notes={notes}
setId={setId}
/>
))
}
</div>
I'm using submitHandler function that triggers on clicking the submit button. The function looks like this:
const submitHandler = () => {
if (inputText || inputTitle) {
setNotes([
...notes,
{title:inputTitle , text: inputText, id: Math.random()*1000}
]);
} else {
alert("Notes are Empty. Type something in textarea.");
}
setInputText("");
setInputTitle("");
setId("");
};
I'm also using an updateHandler function to update the existing note. Which triggers on clicking the Update button. Whenever I use splice() or unshift() here to set the updated note on the top chrome stops responding and everything hangs.
const updateHandler = () => {
for (var i=0; i<notes.length; i++) {
if (id===notes[i].id) {
if (inputText || inputTitle) {
notes.push(
{title:inputTitle , text: inputText, id: Math.random()*1000}
);
setNotes(notes.filter((el) => el.id !== id));
} else {
alert("Notes are Empty. Type something in textarea.");
}
}
};
setInputText("");
setInputTitle("");
setId("");
}
Remove the reverse() and add the newNote to the top of notesArray
FIRST
instead of {notes.reverse().map((note)=> ( //code ))}
use {notes.map((note)=> ( //code ))}
SECOND
instead of
setNotes([
...notes,
{title:inputTitle , text: inputText, id: Math.random()*1000}
]);
use
setNotes([
{title:inputTitle , text: inputText, id: Math.random()*1000},
...notes
]);
I think you should add your new objects at first position like below.
const submitHandler = () => {
if (inputText || inputTitle) {
setNotes([{
title: inputTitle,
text: inputText,
id: Math.random() * 1000
}, ...notes]);
} else {
alert('Notes are Empty. Type something in textarea.');
}
setInputText('');
setInputTitle('');
setId('');
};
const updateHandler = () => {
if (inputText || inputTitle) {
const newCopyNotes = notes.filter(el => el.id !== id);
setNotes([
{ title: inputTitle, text: inputText, id: Math.random() * 1000 },
...newCopyNotes
]);
} else {
alert('Notes are Empty. Type something in textarea.');
}
setInputText('');
setInputTitle('');
setId('');
};
Remove reverse and map normally
<div>
{notes.map((note)=> (
<NotesCard
note={note}
key={note.id}
setInputText={setInputText}
setInputTitle={setInputTitle}
setNotes={setNotes}
notes={notes}
setId={setId}
/>
))
}
</div>

Remove item when unchecked checkbox

I have checkbox with a couple item in it, when i click the check box the item will add to state called currentDevice, but when i unchecked the item it keep add item and not remove it.
How do i remove item from state when i unchecked the box. Im using react-native-element checkbox. Thankyou before
The code:
constructor(props) {
super(props)
this.state = {
currentDevice: [],
checked: []
}
}
handleChange = (index, item) => {
let checked = [...this.state.checked];
checked[index] = !checked[index];
this.setState({ checked });
this.setState({currentDevice: [...this.state.currentDevice, item.bcakId]})
}
renderFlatListDevices = (item, index) => {
return (
<ScrollView>
<CheckBox
title={item.label || item.bcakId}
checked={this.state.checked[index]}
onPress={() => {this.handleChange(index, item)}}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='#FFE03A'
containerStyle={styles.containerCheckBox}
textStyle={styles.textCheckBox}
/>
</ScrollView>
)
}
change the handleChange method to
const handleChange = (index, item) => {
const {currentDevice, checked} = state;
const found = currentDevice.some((data) => data === item.bcakId);
if (found) {
currentDevice.splice(
currentDevice.findIndex((data) => data === item.bcakId),
1
);
} else {
currentDevice.push(item.bcakId);
}
checked[index] = !checked[index];
this.setState({
currentDevice,
checked,
})
};
I found the solution, here is the code :
handleChange = (index, item) => {
let checked = [...this.state.checked];
checked[index] = !checked[index];
this.setState({ checked });
this.setState(previous => {
let currentDevice = previous.currentDevice;
let index = currentDevice.indexOf(item.bcakId)
if (index === -1) {
currentDevice.push(item.bcakId)
} else {
currentDevice.splice(index, 1)
}
return { currentDevice }
}, () => console.log(this.state.currentDevice));
}
Credit : Adding checked checkboxes to an array and removing the unchecked ones - react native

How to handle/select all checkboxes - ReactJS

I'm trying to handle my select all function , but at the moment i got some issues .I'm trying to fill an object with all check boxes . Can somebody give me a hand ?
This is my function to handle single checkbox :
constructor(props) {
super(props);
this.state = { docList:{} }
handleCheckboxClick = (e) => {
let parsedVal = JSON.parse(e.target.value);
let newDocList = { ...this.state.docList };
if (e.target.checked) {
newDocList[parsedVal.documentId] = parsedVal.documentNumber;
} else {
delete newDocList[parsedVal.documentId];
}
this.setState({
docList: newDocList,
}, () => {
console.log(this.state.docList)
});
};
The render :
<MaterialTable options={{
showSelectAllCheckbox:false,
selection: true,
selectionProps: rowData => ({
onClick: (event , rowData) => this.handleCheckboxClick(event,rowData),
value: JSON.stringify({ documentId: rowData.documentId, documentNumber: rowData.documentNumber })
}),
And this is handle select all :
handleAllCheckboxes = (e) => {
if(e.target.value){
this.setState(state=> ({selected: state.data.map(rowData=> rowData.documentId)
}))
console.log(this.state.selected)
return;
}
this.setState({ selected: [] });
}
And the render :
<Checkbox
onClick={this.handleAllCheckboxes}
indeterminate
/> Select All
Included an example of select all or deselect all. Alternatively, click one at a time :)
https://codesandbox.io/s/select-deselect-checkboxes-jugl2

Changing multiple states on button's click

In my react app i have a list of cars returned from an axios call, each car has an attribute inside it called refundable and it's boolean either true or false, and i have a button and a disabled input, i want when i click on this button if the refundable is true to enable the input and if it's false to hide the input and show a sentence that this car is not refundable, the code i made checks if refundable is true or not and it enables the input, but if it was false it shows the false sentence for all of the cars in the list, here is what I'm doing:
Initial state:
state={cars: [],isInputDisabled: [], isVisible: true }
Function on button's click:
changeDisableState = (id, i) => {
const car = this.state.cars.find(x => x.id === id);
let isInputDisabled = this.state.isInputDisabled;
isInputDisabled[i] = !isInputDisabled[i];
if (car.refundable == true) {
this.setState({ isInputDisabled });
} else {
this.setState({ isVisible: false });
}
};
Rendering cars:
renderCars() {
const cars = this.state.cars;
return cars.map((car, i) => (
<div key={car.id}>
<Button onClick={() => this.changeDisableState(car.id, i)}>Check</Button>
{this.state.isVisible ?
<input
disabled={!this.state.isInputDisabled[i]}/> : <p>Can't be refundable</p>}
</div>
));
}
It seems like you're missing something in your code:
changeDisableState = (id, i) => {
const car = this.state.cars.find(x => x.id === id);
let isInputDisabled = this.state.isInputDisabled;
if (car.refundable == true) {
this.setState({ isInputDisabled[i] : !isInputDisabled[i] });
} else {
this.setState({ isVisible: false });
}
};
also
this line
disabled={!this.state.isInputDisabled[i]}/>
is not clear. It reads as "make my input disabled if my state value for isInputDisable is false" - shouldn't it be inveresed?
You should have isVisible state for each car object.
{car.isVisible ? <input ... /> : <p>Can't be refundable</p>}
You need to create another state variable for recently clicked id. And then only render sentence for active id
changeDisableState = (id, i) => {
const car = this.state.cars.find(x => x.id === id);
let isInputDisabled = this.state.isInputDisabled;
isInputDisabled[i] = !isInputDisabled[i];
if (car.refundable == true) {
this.setState({ isInputDisabled,activeid:id });
} else {
this.setState({ isVisible: false, activeid:id });
}
};
renderCars() {
const cars = this.state.cars;
return cars.map((car, i) => (
<div key={car.id}>
<Button onClick={() => this.changeDisableState(car.id, i)}>Check</Button>
{this.state.isVisible ?
<input
disabled={!this.state.isInputDisabled[i]}/> : this.state.activeid === car.id && <p>Can't be refundable</p>}
</div>
));
}

Print only clicked radio button value(React)

Print selected radio button value in console.
If all radiogroup is answered then print in console only the selected= true radioValue. for example: if NO radiobutton= true its value is 2. It should print value 2. Like that all true radiovalue should print in console.
Thanks
//array of cards coming from the backend
const data = [
{
cardName: 'Do you want sugar in your coffee',
options: [
{ radioName: 'Yes',radioValue: '1', selected: false },
{ radioName: 'No',radioValue: '2', selected: false }]
},
{
cardName: 'Do you want milk in your coffee',
options: [
{ radioName: 'Yes',radioValue: '1', selected: false },
{ radioName: 'No',radioValue: '2', selected: false }]
},
{
cardName: 'Do you want low-fat-milk in your coffee',
options: [
{ radioName: 'Yes',radioValue: '1', selected: false },
{ radioName: 'No',radioValue: '2', selected: false }]
}
];
class CardsList extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: [],
};
}
componentDidMount() {
setTimeout(() => {
// mimic an async server call
this.setState({ cards: data });
}, 1000);
}
onInputChange = ({ target }) => {
const { cards } = this.state;
const nexState = cards.map(card => {
if (card.cardName !== target.name) return card;
return {
...card,
options: card.options.map(opt => {
const checked = opt.radioName === target.value;
return {
...opt,
selected: checked
}
})
}
});
this.setState({ cards: nexState })
}
onSubmit = () => {
console.log(this.state.cards.map(({ cardName, options }) => {
const option = options.filter(({ selected }) => selected)[0]
return ` ${option.radioValue}`
}))
};
onReset = () => {
this.setState({cards:[]});
}
render() {
const { cards } = this.state;
return (
<div>
{
cards.length < 1 ? "Loading..." :
<div>
{cards.map((card, idx) => (
<ul>
{card.cardName}
{card.options.radioName}
{
card.options.map((lo, idx) => {
return <input
key={idx}
type="radio"
name={card.cardName}
value={lo.radioName}
checked={!!lo.selected}
onChange={this.onInputChange}
/>
})
}
</ul>
))
}
< button onClick={this.onSubmit}>Submit</button>
< button onClick={this.onReset}>Clear</button>
</div>
}
</div>
);
}
}
ReactDOM.render(<CardsList />, document.getElementById('root'));
<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="root"></div>
Change your log in onSubmit to this
console.log(this.state.cards.map(({ cardName, options }) => {
const option = options.filter(({ selected }) => selected)[0]
return `${cardName}: ${option.radioName}`
}))
This way you filter the options to the one, where selected is truthy, and take the first one.
To address your first question, just map over your this.state.cards array before doing the log and check, if there is exactly 1 option, where selected is true. If this is not the case, tell the user in whatever way you want.
Also you can remove your constructor and change it to that:
state = {
cards: [],
}
Because you do not access your props in your constructor
You can go with the answer of #george,
for you to check if either of the radio buttons is clicked for each card, you can run a validation check
let unselectedCards = this.state.cards.filter((card) => {
return !card.options[0].selected && !card.options[1].selected
});
use the unselectedCards variable to highlight the cards.
you can use map options again inside the cards map if you would be having more options.

Categories

Resources