I'm creating a NoteEditor, using react. I have 2 textarea in my popup, and when i'm trying to add my array of strings into object, i have a mistake, that my variable, which is contains this arrayOfStrings returns 'undefined', when i'm clicking the button add note.
There is my function onDescriptionChange, i take the e.target.value from my textarea and add to variable arrayOfStrings, where split this string into array with words:
let onDescriptionChange = (e) => {
setTextAreaHeight(e, '100px');
let stringToSplit = e.target.value;
let arrayOfStrings = stringToSplit.split(' ');
return arrayOfStrings;
};
There is a function addArrayToNote, where I'm trying to add this arrayOfStrings into description:
let addArrayToNote = (arrayOfStrings) => {
setNote({
...note,
description: arrayOfStrings,
});
addNote();
};
I will be very grateful if you help...
I believe you want to invoke the method addArrayToNote after generating the arrayOfStrings.
let onDescriptionChange = (e) => {
setTextAreaHeight(e, '100px');
let stringToSplit = e.target.value;
let arrayOfStrings = stringToSplit.split(' ');
// return arrayOfStrings; instead of returning the value
addArrayToNote(arrayOfStrings) // invoke the addArrayToNote with the strings.
};
let addArrayToNote = (arrayOfStrings) => {
setNote({
...note,
description: arrayOfStrings,
});
addNote();
};
I hope this helps.
Related
I have created a dynamic form which can have rows added and removed and are stored in a state array.
I need to remove the index passed into the function from the array, without storing a null or empty value.
This is my current code for removing the rows however this simply removes the last row and not the one required at index
const removeRow = (index) => {
setLocationRows((current) =>
current.filter((employee, i) => {
return index !== i;
})
);
};
This code removes the required index however sets the value to null / empty which messes up when after removing and adding rows.
setLocationsObj((current) => {
const copy = { ...current };
delete copy[index];
return copy;
});
Joe.
Im supposing you have something like this:
const [locationRows, setLocationRows] = useState([]);
const removeRow = (index) => {
setLocationRows(locationRows.filter((e,i)=> i !== index))
};
If so, try the above code.
For the complete CRUD operation you can use the following:
const addRow = (newRow) => {
setLocationRows([... locationRows, newRow])
};
const updateRow = (rowData) => {
setLocationRows(locationRows.map(e => {
if(e.id === rowData.id) return rowData;
else return e;
});
};
I hope this can help you!
I recently had to do something very similar and used the array splice method, as it allows you to remove the element at a specific index.
const removeRow = (index) => {
setLocationRows((rows) =>
// create deep copy
const newRows = JSON.parse(JSON.stringfy(rows));
// remove 1 element at index
newRows.splice(index, 1);
return newRows;
);
};
If you are dealing with any sort of nested array it's important to create a deep copy of that array, as the const copy = [...rows] method only creates a shallow copy and can cause all sorts of bugs when trying to manipulate the data further.
Hope this helps!
I am in almost desperate need of help. I am a mechanical engineer and I'm doing a type of calculator for my line of work. I have had an issue I've spent weeks on. I can't seem to solve it.
To not bore you with long code I will try to generalise it as much as possible.
I will first present an example code.
Then I will explain the expected behaviour and what is actually happening for me.
Finally I will explain what I have tried so far to solve this issue.
I will add more content at the bottom based on comments to help clarify my question.
CODE EXAMPLE
THE PARENT OBJECT
import {childObject} from "./childObject"
// in my code "childObject" are actually different from each other
const object1 = Object.assign({}, childObject);
const object2 = Object.assign({}, childObject);
const object3 = Object.assign({}, childObject);
const object4 = Object.assign({}, childObject);
const object5 = Object.assign({}, childObject);
const object6 = Object.assign({}, childObject);
const exampleObject = {
name: "foo",
otherInfo: "bar",
nestedObject:{
standardType: [object1, object2, object3],
specialType: [object4, object5, object6]
},
sumfunc(){}
}
THE CHILD OBJECT
export const childObject = {
name: "I'm losing my mind",
value: "" //<-- this will change
otherInfo: "please help me",
sumfunc(){}
}
EXPLAINING
What I am doing is the following:
Searchbar with all types of parentObjects.
Allowing user to select one or multiple of same or different parentObjects.
Storing the copied selection in a redux store.
Displaying the selection, each parentObject as a form. [see picture]
When typing in form the value of the nested object will change
Now... The issue is when I open the searchbar and select the same parentObject, thus copying it, all its values are mutated. As seen in picture above.
WHAT I HAVE TRIED
I have tried to use lodash clone and deepClone on the selected parentObject.
I have tried to use loads clone and deepClone on the selected childObjects.
I have tried, since the object have the same structure, to go through all key value pairs and shallow copy them.
I have tried to not send the parentObject via the searchbar component to the reducer, instead I just send a string and the reducer itself will add the parentObject to the store.
All methods that I've tried have not stopped the mutation. The deepClone method stopped the mutations, but in return the functions in the objects stopped working (maybe I need to bind it somehow?)
MORE CONTENT
The code that updates the value of the nestedObject
const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
const formCopy = Object.assign({}, formEQ);
const inputFieldName = e.target.name;
// if anything other than a empty, number or decimal inputted, then return
const isNum = e.target.value.match(/^(?:\d{1,8}(?:\.\d{0,8})?)?$/);
if (!isNum) return;
// Update priority list to calculate the last updated input
formCopy.priorityList = formCopy.priorityList.sort((a, b) => {
if (a === inputFieldName) return 1;
if (b === inputFieldName) return -1;
else return 0;
});
// Update selected input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === inputFieldName) {
input.value = e.target.value;
}
return input;
});
// If more than two inputs empty do not calculate
const emptyInputs = formCopy.inputs[calcmode].reduce(
(acc, nV) => (nV.value === "" ? (acc += 1) : acc),
0
);
// Calculate the last edited input field
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === formCopy.priorityList[0] && emptyInputs <= 1) {
const calculatedValue = formCopy.calculate(
formCopy.priorityList[0],
calcmode
);
input.value = Number(calculatedValue).toFixed(2);
}
return input;
});
// Final set hook, now with calculated value
setformEQ({ ...formCopy });
};
Please good people of StackOverFlow... Help me!
Your code has few problems :
you are filtering based on name property of child object and all of them has the same name. Always provide unique id to the objects so that they can be differentiated in easy manner.
Your filter logic is so wrong :
formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
if (input.name === inputFieldName) {
input.value = e.target.value; // < -- Culprit
}
return input;
});
Never mutate inline, always create a new copy.
This is how your code change function should be (I have removed dynamic key selection for clarity) :
const change = (e, id) => {
const inputFieldName = e.target.name;
// local copy of array
const nestedArr = [...qform.nestedObject.standardType];
// finding item to be updated
const index = nestedArr.findIndex((i) => i.id === id);
console.log({ index, inputFieldName, e, id });
if (index !== -1) {
const item = nestedArr[index];
item.value = e.target.value;
nestedArr[index] = item;
// deep copy till k depth where k is the key to be updated
const newObject = {
...qform,
nestedObject: {
...qform.nestedObject,
standardType: [...nestedArr],
},
};
setQform(newObject);
}}
Check this Example : Demo
I have a list like this :
[EMP004: BPCE-RNHC-25G8, EMP003: 8FIW-9JRB-NY4J, EMP005: 7QF2-6HI9-XKZZ, EMP002: SG8P-YQKG-ZV3C, EMP001: PBF7-WZHT-WPZR]
What I trying to achieve:
User input the first key and then the system will scan through the list and show them corresponding key. For example, if user input "EMP004", it should alert BPCE-RNHC-25G8 for them.
Idea:
How can I separate the first key and second key with : ? Other than that how can I know find the corresponding result? Does anyone know how can i solve this with JavaScript only ? Thanks in advance.
The sample list you have provided is syntactically incorrect. You can create an array object. Then you can create function that takes the key as the parameter like the following way:
const list = [
{ EMP004: 'BPCE-RNHC-25G8' },
{ EMP003: '8FIW-9JRB-NY4J' },
{ EMP005: '7QF2-6HI9-XKZZ' },
{ EMP002: 'SG8P-YQKG-ZV3C' },
{ EMP001: 'PBF7-WZHT-WPZR' }
];
const getValByKey = (key) => Object.values(list.find(o => Object.keys(o)[0] === key ))[0];
console.log(getValByKey('EMP004'));
console.log(getValByKey('EMP002'));
Update: For string items you can try the following way:
const list = ['EMP004: BPCE-RNHC-25G8', 'EMP003: 8FIW-9JRB-NY4J', 'EMP005: 7QF2-6HI9-XKZZ', 'EMP002: SG8P-YQKG-ZV3C', 'EMP001: PBF7-WZHT-WPZR'];
const getValByKey = (key) => list.find(item => item.split(':')[0].trim() === key ).split(':')[1].trim();
console.log(getValByKey('EMP004'));
console.log(getValByKey('EMP002'));
You can do like this:
function search(arr, sub) {
sub = sub.toLowerCase();
matchedIndex = arr.map((str, index) => {
if (
str.toLowerCase().startsWith(sub.slice(0, Math.max(str.length - 1, 1)))
) {
return index;
}
});
if(matchedIndex.length>0){
console.log(matchedIndex);
matchedIndex = matchedIndex.filter(function( element ) {
return element !== undefined;
});
return matchedIndex[0]
}
}
var arr = ["EMP004: BPCE-RNHC-25G8", "EMP003: 8FIW-9JRB-NY4J", "EMP005: 7QF2-6HI9-XKZZ", "EMP002: SG8P-YQKG-ZV3C", "EMP001: PBF7-WZHT-WPZR"];
var index = search(arr, 'EMP004');
if(index>-1){
matchedvalue=arr[index].split(':');
console.log(matchedvalue[1]);
}
else{
console.log("Not found")
}
I have a little problem.
this code is used as password validator.
classlist.add create checked icon when regexp return true.
How can I add a new class for all, when all regexp are true ?
Sorry for my English and thks for your help.
elf.controlPassword = function (event) {
const lenthNoSpace = new RegExp(/^(\S{8,20})$/);
const hasNumber = new RegExp(/\d+/);
const hasUpperCaseLowerCase = new RegExp(/(?=.*[A-Z])(?=.*[a-z])/);
const hasSpecialChar = new RegExp(/[^A-Za-z0-9\s]/);
const value = event.target.value;
toggleCheck(value, lenthNoSpace, validLenth);
toggleCheck(value, hasNumber, validNumber);
toggleCheck(value, hasUpperCaseLowerCase, validCase);
toggleCheck(value, hasSpecialChar, validSpecialChar);
}
const toggleCheck = function (value, regex, display) {
if (regex.test(value) === true) {
display.classList.remove('icon-dot');
display.classList.add('coucoutest');
return 1;
}
else
{
display.classList.remove('coucoutest');
display.classList.add('icon-dot');
return 0;
}
};
You can put the results of all the toggleCheck calls into an array, then check that all values are 1:
const results = [
toggleCheck(value, lenthNoSpace, validLenth),
toggleCheck(value, hasNumber, validNumber),
toggleCheck(value, hasUpperCaseLowerCase, validCase),
toggleCheck(value, hasSpecialChar, validSpecialChar),
];
if (results.every(r => r === 1)) {
for (const display of [validLenth, validNumber, validCase, validSpecialChar]) {
display.classList.add('somethingWhenAllRegexPass');
}
}
I'd also recommend
Using proper spelling to avoid bugs - you probably want length instead of lenth
Use more precise variable names - it sounds like validNumber and validCase, for example, are elements, which is not clear from their name
I am building a weather app for practice. I get to that point that I have to make an autocomplete input field with data from JSON object. When someone makes an input, it displays the matched data, but on click I want to get two properties from the object. I need to get the longitude and latitude properties from JSON object to make an API request to return the object with the weather data. The content displays properly but I can't make that onClick event listener work. I tried very different things and failed, either was a scope problem or something else. It is one of my first projects and I am in a downfall right now. Please help me. :)
P.S. You can find it on this link: https://objective-edison-1d6da6.netlify.com/
// Testing
const search = document.querySelector('#search');
const matchList = document.querySelector('#match-list');
let states;
// Get states
const getStates = async () => {
const res = await fetch('../data/bg.json');
states = await res.json();
};
// Filter states
const searchStates = searchText => {
// Get matches to current text input
let matches = states.filter(state => {
const regex = new RegExp(`^${searchText}`, 'gi');
return state.city.match(regex);
});
// Clear when input or matches are empty
if (searchText.length === 0) {
matches = [];
matchList.innerHTML = '';
}
outputHtml(matches);
};
// Show results in HTML
const outputHtml = matches => {
if (matches.length > 0) {
const html = matches
.map(
match => `<div class="card match card-body mb-1">
<h4>${match.city}
<span class="text-primary">${match.country}</span></h4>
<small>Lat: ${match.lat} / Long: ${match.lng}</small>
</div>`
)
.join('');
matchList.innerHTML = html;
document.querySelector('.match').addEventListener('click', function() {});
//Wconsole.log(matches);
//let test = document.querySelectorAll('#match-list .card');
//const values = matches.values(city);
}
};
window.addEventListener('DOMContentLoaded', getStates);
search.addEventListener('input', () => searchStates(search.value));
If I understand correctly, you're trying to access the lat and lng values of the clicked match, if that is the case, here is one way of doing it:
const outputHtml = matches => {
if (matches.length > 0) {
const html = matches
.map(
match => `<div class="card match card-body mb-1" data-lat="`${match.lat}" data-lng="`${match.lng}">
<h4>${match.city}
<span class="text-primary">${match.country}</span></h4>
<small>Lat: ${match.lat} / Long: ${match.lng}</small>
</div>`
)
.join('');
matchList.innerHTML = html;
document.querySelectorAll('.match').forEach(matchElm => {
matchElm.addEventListener('click', function(event) {
const { currentTarget } = event;
const { lat, lng } = currentTarget.dataset;
});
});
}
};
I've used the data-lat and data-lng attributes to store the required values in the element's dataset and I've used document.querySelectorAll('.match') to get all the elements that have the class match not just the first one.