How to get object data when one value is changed in React? - javascript

In a React project, I've certain records of data which are populated in a grid. It also has two input fields one for text and other is date. User can make any changes on text or date field. My concern is that when date value is changed, text data is shown in console along with new date value, but, when text value or date value from other record is changed, the previous record's text value is reset to old value. Please refer to the code below
Below is the code where I'm extracting both text and date values on handlechange
const handleChange = (data) => {
const { id: newId, textVal: franchise, dateVal: dateData } = data;
setDataNew((prevInfo) => {
const newList = [...prevInfo];
const index = newList.findIndex((datum) => datum.newId === newId);
if (index !== -1) {
if (newId !== undefined) {
newList[index].newId = newId;
}
if (franchise !== undefined) {
newList[index].franchise = franchise;
}
if (dateData !== undefined) {
newList[index].dateData = dateData;
}
} else {
newList.push({ newId, franchise, dateData });
}
return [...newList];
});
};
These are the changes
<input type="text" onChange={(e) => textCallback({textVal: e.target.value,id: rowData[0].id,
dateVal: rowData[4] <-- This date value is added in text field
})}/>
<DatePickerNew setRequesterDate={(e) => dateCallback({dateVal: e, id: rowData[0].id,
textVal: rowData[3] <-- This text value is added in date field
})} startDate={colData}
/>
As you can see from above code, new keys have been added to get the values of respective fields. It works for date field but, not for text field. What could be the best optimal solution?
Please refer to codesandbox link --> https://codesandbox.io/s/keen-dubinsky-7z53vc?file=/src/Grid.js
Do observe the console output to see the changes

Related

Getting undefined when changed data in input field

In a table of records, there are certain input text fields and date field which can be changed. When input text is changed date field gets undefined and for date field its vice-versa. My intention is to pass values of input text as well as date values, but, gets undefined in the console. Please refer to code below
const handleChange = (data) => {
// here text and date values are extracted
const { id, textVal, dateVal } = data;
setDataNew((prevInfo) => {
const newList = [...prevInfo];
const index = newList.findIndex((datum) => datum.id === id);
if (index !== -1) {
// getting undefined here
newList[index] = { id, textVal, dateVal };
} else {
newList.push({ id, textVal, dateVal });
}
return [...newList];
});
};
I'm able to process data only when input text is changed, but, on date field change input data is undefined... similarly it happens for date field as well.
Please refer to codesandbox link for better clarity --> https://codesandbox.io/s/elated-varahamihira-xpjtdb?file=/src/Table.js:968-1155
You will have to pass other value from the Grid component in the callback of date change and name change.

Filtering with a multi-select menu

So I have a select menu that lets the user select multiple options. the selected options correspond to actorModel.
Then I have an object array and I wish to filter it according to the selected options.
If the user selected option A and B , then it will return two objects from actorDocs.
The one that has a label value 'A' and the one that has the label value 'B'.
If no option is selected (actorModel is null) then it will return all objects from actorDocs.
The problem I am encountering in this code is that it only works if the user selects one option.
If the user selects more than one, then I tink it is trying to locate an object that has several labels instead of several objects with each label.
Any help is more than welcome
const actorModel = ref({ 0:'label1', 1:'label2', 3:'label3'})
const actorDocs = ref([{'label':'label1'},{'label':'label2'},{'label':'label3'},{'label':'label4'}])
const actorListTest2 = computed(() => {
if (actorModel.value == null){var ttt = actorDocs.value}
else {
var ttt = actorDocs.value.filter(obj => {
return (
(!actorModel.value.length || obj.label.includes(actorModel.value) )
) })}
lenActordata.value = ttt.length
return ttt
});
Try like following snippet:
const actorModel = {0:'label1', 1:'label3'}
const actorDocs = [{'label':'label1'}, {'label':'label2'}, {'label':'label3'}, {'label':'label4'}]
const actorListTest2 = () => {
if (actorModel == null){
return actorDocs
} else {
return actorDocs.filter(obj => [...Object.values(actorModel)].includes(obj.label))
}
};
console.log(actorListTest2())

Handle multiple inputs

This task is tough one for me. Please don't get mad. I'm making dynamic inputs to able for user add more informartion.Expected output if both field was filled, push it to the array. I have one datalist and one input. For both of them I want to use one onChange function to make validation and push to the array. Right now, in onChange function I'm checking datalist, does value was typed or selected from options. The problem is that when I'm storing in state, it only saves one sigle value or doesn't push to array. I commented where is the problem in the code. I have tried to reproduced my code : https://jsfiddle.net/armakarma/qwg3j2fa/9/
{this.state.arrayOfInput.map((item, idx) => {
return (
<>
<input
type="text"
name="address"
list="data-list"
onChange={e => this.onChooseAddress(e)}
/>
<datalist id="data-list">
{this.state.adresses.map((item, idx) => {
const { id, address } = item
return <option key={idx} data-value={id} value={address} />
})}
</datalist>
<input
name="contact"
className="event_time-inputs event_table_textarea"
placeholder="Contact"
onChange={e => this.onChooseAddress(e)}
/>
</>
)
})}
onChange function:
onChooseAddress(e) {
const { adresses } = this.state
let address_id = ""
let new_address = ""
let whoIsMetting = ""
// checking if value from "contact" input
if (e.target.name === "contact") {
whoIsMetting = e.target.value
}
// checking if value is selected from options in datalist
for (let i = 0; i < adresses.length; i++) {
if (
e.target.value === adresses[i].address &&
e.target.name === "address"
) {
address_id = adresses[i].id
}
}
//if user typed value
if (!address_id && e.target.name === "address") {
new_address = e.target.value
}
// PROBLEM IS HERE!!!! if both fields was filled pushing to array
if ((address_id || new_address) && whoIsMetting) {
let interviewDetails = {
address_id: address_id,
new_address: new_address,
whoIsMetting: whoIsMetting,
}
this.setState(prevState => ({
arrayOfAddresses: [...prevState.arrayOfAddresses, interviewDetails],
}))
}
}
Your problem is, that only one of the three variables address_id, new_address and whoIsMetting can have a value at a call of onChooseAddress.
You can never have a value in whoisMetting and one of the others together, because whoIsMetting only gets a value if onChooseAddress is called from the contact input and the others if it is called from the address input.
I suggest you either stash partly correct values in a different variable (outside of the method ofc) and check for completion before pushing them to the arrayOfAddresses OR simply push partly correct entries directly to arrayOfAddresses and check for completion before using an entry of this array.

Change all cell values in table column, already using 2D array for row and cell

https://codesandbox.io/s/1p770371j
The above demo shows a table where you can change data in each sell and the 2d array records which row and column cell the data change occurred. I have just added a column button to the colum header titles.
The idea is that the button will change all the column values to the same value. It opens up a dialog that has the 3 options. Once clicked all the options within that column changes accordingly.
This is the handle that returns each individual cell/row data upon change, which is fine.
handleValue = (event, val, rowIdx, cellIdx) => {
const newValue = [...this.state.value];
newValue[rowIdx][cellIdx] = val;
this.setState({
value: newValue
});
};
I have a new handle for the update all column:
handleChange = name => event => {
this.setState({ [name]: event.target.value });
};
which just changes the select value at the minute, but this value will need to update all in that column, guessing it will need to look like the above handle something like this...
handleChange = event => {
const newAllValues = [...this.state.value];
newAllValues = [event.target.value]
this.setState({
value: newAllValues
});
};
Any assistance in this would be great, will I need to introduce a 3rd array property for the column?
You can send handleChange which column you intend to update as argument and update each row against that column name.
I also think (I could be wrong) you intend to keep the state of all "column wise" select values in state too. But currently you are keeping it against state.status. This way, selecting "Yes" in one column would change other columns select menu to "Yes", right?
So I changed the status to be an object:
state = {
value: selected,
status: {}
};
Now logic of updating status should be added to your handleChange function too. The idea is similar, update whichever column's select menu has been changed.
So the handler becomes:
// take `column` as parameter
// update each row's `column` value. i.e. row[column]
handleChange = column => event => {
const newValue = this.state.value.map(row => ({
...row,
[column]: event.target.value
}));
this.setState({
// status is now object, save whichever column just been selected
status: {
...this.state.status,
[column]: event.target.value
},
// set value to newly calculated rows
value: newValue
});
};
I also made minor modifications in your render method to adapt to new shape of your state and new signature of handleChange.
For exmaple:
<Select
native
value={this.state.status[mItem.value]} // i.e. status['Seniors']
onChange={this.handleChange(mItem.value)} // sends 'Seniors' as argument
input={<Input id="status-native-simple" />}
>
//...
</Select>
Here is the forked sandbox:

How to get newly typed text in react-native text input?

When user types text in TextInput, onChangeText and onChange are called.
I am getting event from onChange callback and can get newly updated text from event.nativeEvent.text.
I am getting text from onChangeText callback and can get newly updated text from it.
But I only want newly entered text/letters. How to get this?
For example:-
lets assume we have som as text in TextInput, now as soon as user type e, I want only this e instead of whole text some.
Any work around?
We can get newly typed letters via
Use onSelectionChange props in your Input. We can get an event from onSelectionChange from which we can get cursor position. Through cursor position and full text we can easily get newly entered letters.
Example:-
<Input
...
onChangeText={this.handleMessageChange}
onSelectionChange={this.handleMessageSelectionChange}
...
/>
And methods
handleMessageChange = (message: string) => {
this.setState({ message });
};
handleMessageSelectionChange = (event: Object) => {
const { selection } = event.nativeEvent;
this.setState({ selection });
};
Now whenever you want newly entered letters, get it
getNewlyEnteredLetters = (): string => {
const { selection, message } = state;
const { start, end } = selection;
return start === end ? message[start -1 ] : message[message.length - 1]
}; // start === end implies that new letters are entered and not selection is made.
One way to solve this in pure js try this with the string
getNewChar(str){
return str[str.length - 1];
}
To get only the newly entered text you can use the onChange function of TextInput as below:-
<TextInput
onChange={(event) => {console.log(event.nativeEvent.data)}}
onChangeText={(val) => {console.warn(val)}}
/>
As specified the onChangeText will give you the complete text but you can use the event from onChange to get the newly eneterd letter.
EDIT
According to your react native newer versions you get the complete new text in event.nativeEvent.text and no data in event.nativeEvent.data. So for your requirement you can use the code below for now :-
<TextInput
onChange={(evnt)=>{
let newText = [];
let oldText = [];
for(let i=0;i<evnt.nativeEvent.text.length;i++) {
newText.push(evnt.nativeEvent.text[i]);
if(this.state.val[i]) {
oldText.push(this.state.val[i]);
}
}
let newLetter = '';
for(let j=0;j<newText.length;j++) {
if(newText[j] !== oldText[j]) {
newLetter = newText[j];
break;
}
}
console.log(newLetter);
}}
onChangeText={(val)=>{
console.log(val);
this.setState({val});
}}
/>
You will get the newly entered letter inside your console of newLetter. I will let you know if i find anything else related to this but for now you can get working with this :)

Categories

Resources