Push value of state variable in state array in react - javascript

I am facing wierd issue here.
The senario is : I have 2 variables(lets say a,b) in state of component: 1 is 2d array and other is Object. I have multiple small divs on click of which i am storing 1/0 at a's index(like if i click 1st div in 1st row: i will update value of a[0][0] to 1).
And then there are buttons below that. One button will insert the current selection in the this.state.b array and clear the selections after insertion. One is there just to clear the selection And other buttons are for each saved selection. So whenever i click on any saved selection button , the divs selected in that selection should get selected. Everything upto this works fine.
Now the issue here is, when i save a selection, then click on that saved selection button and update it, Even if i dont click on save button the selection gets updated at that index and when i save it, it creates another entry in that object.
For ex: I have saved single selection. Assume b will have value like {0:[[0,0][1, 0]]} and then I click on selection 0 button,it will show just 1st div in second row selected. Then i select div at postion [0,0] it automatically updates the varibale b as {0:[[1,0][1,0]]}. and when i click save button, it will also push another entry in b like {0:[[1,0][1,0]], 1:[[1,0][1,0]]}.
I dont want to update previous entry, I just want to add new entry on click of save button.
this is my save function:
handleSave(index) {
let routes = this.state.routes;
const selectedArray = this.state.selectedArray;
routes[index] = selectedArray;
this.setState({routes: routes});
this.setState({selectedArray: new Array(2).fill(0).map(() => new Array(2).fill(0))});
}
this is my div pattern
<div className="content">
<div>
{
length.map(key => {
return <div key={key}>{
length.map(innerKey => {
return <div key={key +''+ innerKey} className={"radio " + (this.state.selectedArray[key][innerKey] === 1 ? "selected" : "unselected")} onClick={(e) => {
let op = this.state.selectedArray;
op[key][innerKey] = op[key][innerKey] === 0 ? 1 : 0;
this.setState({selectedArray: op})
}
}></div>
})}</div>
})
}
<button className="save" onClick={() => this.handleSave(Object.keys(this.state.routes).length)}>Save</button>
<button className="save" onClick={() => this.setState({selectedArray: new Array(2).fill(0).map(() => new Array(2).fill(0))})}>Clear</button>
</div>
<div>
{Object.keys(this.state.routes).map((key, index) => {
return <div key={index}><button className="save" onClick={() => {console.log(key);this.setState({selectedArray: this.state.routes[key]})}}>Selection {index}</button>
</div>
})}
</div>
any solution to this?
################################# Updates ##########################
Tried this.Still it is not working:
handleSave(index) {
const selectedArray = [...this.state.selectedArray];
this.setState({routes: {...this.state.routes, [index]: selectedArray}});
this.setState({selectedArray: new Array(14).fill(0).map(() => new Array(14).fill(0))});
}
let op = [...this.state.selectedArray];
op[key][innerKey] = (op[key][innerKey] === 0 ? 1 : 0);
this.setState({selectedArray: op})
Thanks

Related

Antd item.list removes always removes first last element

Hi there I made simple antd list where user can add, remove edit list.
But the problem is that when i add, edit list verything works as it should.
But when i remove item from a list, antd always remove last item from a list.
Although i can remove any item.
const [employeeList, setEmployeeList] = useState([])
<List
dataSource={employeeList}
renderItem={(item, index) => (
<List.Item id='listItem' >
<Input
id='listItem-input'
defaultValue={item.name}
onChange={(i) => {
employeeList[index].name = i.target.value
setEmployeeList(answerList)
}}
/>
<span className='removeItem'
onClick={() => {
let newList = setEmployeeList
newList[index] = undefined
setEmployeeList(newList.filter(e => e))
}}
>
<CloseOutlined/>
</span>
</List.Item>
)}
/>
I checked in console items in state gets removed, although it still stays in item.list
First of all I would recomend deleting items with splice()
so rather then this 3 lines in onClick (in remove) just
employeeList.splice(index,1)
Edit:
With your approach you probably want:
let newList = employeeList
newList[index] = undefined
Turns out i had to use a keys.
List.Item wasn't registering changes without keys and was just deleting last item, on any change.
<List.Item id='listItem' key={item.answer} >

onClick doesn't work on custom created element

Greetings
I have built a search and every time user types word it renders new checkboxes but new checkboxes don't work like they used to be none of the event listeners work on new checkboxes, when I'm clicking on checkboxes they just don't react, but in old ones, until search will render this they are working normally
//search in checkbox data
const checkOptions = (container, value, containerId) => {
for (let i = 0; i < props.unique[containerId].length; i++) {
let item = props.unique[containerId][i];
if (
props.unique[containerId][i] !== null &&
props.unique[containerId][i].includes(value)
) {
element = (
<label
onClick={(e) => {e.stopPropagation(); ifAnyChecked(e);}} key={i}>
<input onClick={(e) => {tableSearch(e);}} type="checkbox" value={item ? item : "empty"}/>
{item && item.length > 28 ? (
handleCheckbox(item)
) : (
<p>{item}</p>
)}
</label>
);
tempData += ReactDOMServer.renderToString(element);
}
}
container.innerHTML = tempData;
};
any idea what's happening?
Have you tried to use onChange event instead of onClick? As far as I know, input type checkbox doesn't have such an event like onClick.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
I used to get this problem when I was working with Vanilla JS whenever i render a new element then that element was not triggering my events. That was because they were generated on runtime so the event wasn't bound to that element. Now I think that thing is happening here as well. So I changed your code and put it inside a state now it is working. I hope I helped. Do let me know if this is not the solution that you were looking for but it solves your problem though
I put the html inside a state array then i mapped it out inside the newCheckBox div. I changed the input to controlled input with fieldValue state. Lastly i changed the new checkbox alert from onClick={alert("doesn't goes in")} to onClick={() => alert("I think its working now right?")}
Here is the complete code sandbox
https://codesandbox.io/s/polished-sea-vedvh?file=/src/App.js

Is there a way to give the name attribute of a button to an object in React?

I have a few buttons that increment by one a few separate object properties. Can I use the button name to indicate which object property to increment? Instead of writing the same function for each button?
after a button is clicked, send the button name and add this on to the object name like object.[event.target.name]= object.[event.target.name] +1
Example code
increaseClick = (id, e) => {
console.log(e.target.name);
const updatedData = this.state.students.map((student) => {
if (id === student.id) {
student.noHW = student.noHW + 1;
}
return student;
});
this.setState({
students: updatedData,
});
};
// button code
<button name="noHW" onClick={(e) => lowerClick(id, e)}>
-
</button>{' '}
{noHW}{' '}
can I change student.noHW to something like student.[e.target.name] to get which button was clicked which will correspond to the property I want to add 1 to.

How to remove value from state array on click

Currently I'm working on Alarm clock app and I want to do it in way so you can add multiple Alarms. Every Alarm is stored in alarms:[] state in App.js file. If alarm is added,I want to display that alarm as a li element under the clock and I want to be able to remove it by clicking on X icon. Also ,when current time === time set for alarm ,Ring.js component renders and alarm starts ringing. When alarm is ringing there is 'turn off' button. How is it possible to delete this specific alarm which is ringing ,from state array after click on turn off button?
I've tried to send removeAlarm function and alarm(which may help in determining which alarm from array delete)as a prop to this component when condition if fulfilled.
function checkTime(){
if(time.alarms[0]){
const alarms = time.alarms.map(function(alarm,i){
if(time.currentHour === alarm.hour && time.currentMinute === alarm.minute && time.currentSecond
>= 0){
return <Ring message={alarm.message} key={i} alarm={alarm} removeAlarm={removeAlarm} />
}
})
return alarms;
}
}
removeAlarm function:
function removeAlarm(alarm){
setTime(prevState => ({
...prevState,
alarms:[...prevState.alarms.filter(el => el !== alarm)]
}))
}
Ring.js file
let message = props.message;
function removeAlarm(alarm){
props.removeAlarm(alarm);
}
function turnOff(e,alarm){
e.preventDefault();
setShowRing(false);
removeAlarm(alarm);
}
<form>
<h3>{message}</h3>
<button onClick={turnOff}>TURN OFF</button>
</form>
I can't figure it out how to do that. I don't know how to use that passed function or how to determine in that onClick function that THIS is that button which has to be send to removeAlarm function ,map thru state and remove that specific one.
Also second problem which I've noticed is with React Spring Transitions. I'm using it in Ring.js,Alarm.js and want to use it also for listing active alarms in ListAlarms.js. I'm using it the exact same way as in first two components but for ListAlarms.js it's not working and I don't undestand why. My goal is to display those active alarms with transitions not just 'blink' there.
Thank you.
CodeSandBox link here
OK some corrections but you have to alter the transitions
First of all you need to filter your list by id, in order to remove correctly the alarm.
function removeAlarm(alarm){
setTime(prevState => ({
...prevState,
alarms:[...prevState.alarms.filter(el => el.id !== alarm.id)]
}))
}
Secondly, I have removed the from property from your transition, since every new object was positioned on top of others. Also, instead of null for the key I used mapping to each item's id.
(item) => item.id
Finally I corrected the order in map function
{listAlarmTransitions.map(({ item, props, key }) => (
So it became
const listAlarmTransitions = useTransition(props.alarms, (item) => item.id, {
enter: { opacity: 1 },
leave: { opacity: 0 }
});
return (
<ul>
{listAlarmTransitions.map(({ item, props, key }) => (
<animated.div key={key} style={props}>
<li
key={item.id}
id={item.id}
onClick={() => {
removeAlarm(item);
}}
>
<FontAwesomeIcon icon={faTimesCircle} className="listIcon" />
<h3>{item.message}</h3>
<span>
{item.hour}:{item.minute}
</span>
</li>
</animated.div>
))}
</ul>
);
Check this sandbox
https://codesandbox.io/s/broken-morning-upqwp
You are filtering out objects/references you should filter out by id.
Your passed alarm argument is an object and your alarms filter array contains objects, find a unique property which you can filter against, by looking at your code, it should be id.
Something like this:
function removeAlarm(alarm){
setTime(prevState => ({
...prevState,
alarms:[...prevState.alarms.filter(el => el.id !== alarm.id)]
}))
}

Dynamically adding input fields and keeping track of what was entered

I am wanting to dynamically create input field values for each category a user creates, the issue is how can I keep track of what the user enters into the input field. As I cannot create X amount of states as it is dynamic. Any tips would be much appreciated, my code is shown below:
var categories = newData.map((category,index) => {
console.log(category)
return (
<div className="content row marginCenter" key={category._id}>
<p>{category.category}</p>
<input type="text" /> //How do I keep track of what was entered for this input field??
<button onClick={() => this.addCategoryLink(category._id)}>Add
link</button>
</div>
)
})
I am wondering how to bind that to the button element
The React docs have a section related to the core of this question:
https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers
Assuming your state holds an array of "categories" objects- essentially, I think what you're looking for boils down to something like this in your map function:
{this.state.categories.map(category => (
<input
type="text"
onChange={event => this.handleCategoryChange(category, event)}
value={category.value}
/>
)}
And then a change handler that looks something like this:
handleCategoryChange = (category, event) => {
const value = event.currentTarget.value;
this.setState(state => {
// Create a copy of the categories array:
const categories = [...state.categories];
// Create a copy of the category, with an updated value:
categories[category.index] = {
...category,
value
};
// Update state with the new values:
return { categories };
});
};
Here's a simple demo:
https://codesandbox.io/s/woqpwvl777
i have other Way for doing this , Of course this way just working well in some situation , forExample when you have just 1 or 3 value
i think you wanna create Input , and there Input are dynamic , and you want define that , if user click in first Button , you get and use first TextInput (value)
in my way ( again i say this : this way just well in some situation ) , we Create data Json like this
[
{ id: n ,
category: 'some',
value: ''
}
in this structure Value key , in the mounting contain nothing or null value if the Value not defined before
for now i create one handler method and this method, called after onChange Event fired on
<input onChange={(e) => this.getValue(category.id,e)} />
that element , this means when user start fill input onChange event handle function and update your state
getValue(id,e) {
let thisId = id-1;
let vs = this.state.c;
vs[thisId].value = e.target.value;
this.setState({
c:vs
});
let v = this.state.c[thisId];
console.log(v);
}
i create Pen in this address -> https://codepen.io/hamidrezanikoonia/pen/vRyJRx?editors=1111
you can check console , for more details ( open console tab in codepen )
and for more details , i create two method , the first fired when input (text) filled ( onChange event ) , and the other fired when clicked on button ( click event )

Categories

Resources