I have many same inputs for percentage purposes, each of them working normally if I'm using normal numbers data. If I'm entering wrong erroneous data like letters or other chars its changing to 0. But it is changing only in screen, data actually catching wrong. For example if I will type 0fsdfsd into input result in screen will be 0 but actual data in input will be 0f.
How to save actual data as0 but not as 0f?
I'm using intl to format data as decimal, and isNaN to catch NaN values.
Input in render()
<input
name="bonusCategory"
value={this.toCurrency(category.bonusrate)}
className="form-control"
style={{ width: "60px" }}
type="text"
onChange={this.inputChanged.bind(this, idx, category.value)}
/>
/>
toCurrency()
toCurrency(number) {
const formatter = new Intl.NumberFormat("ru-RU", {
style: "decimal"
});
let newValue = isNaN(number) ? 0 : number;
return formatter.format(newValue);
}
inputChanged()
inputChanged = (idx, index, e) => {
const { categories } = this.state;
let bonusCategory = e.target.value;
console.log(bonusCategory);
if (bonusCategory.length > 3) return;
categories.forEach(category => {
category.bonusrate =
category.value === index ? e.target.value : category.bonusrate;
});
this.setState(oldState => {
const newDisabledButtons = [...oldState.disabledButtons];
newDisabledButtons[idx] = false;
return {
categories,
isEdit: false,
inCart: true,
disabledButtons: newDisabledButtons
};
});
};
in console.log I can see changing data of bonusCategory and it shows wrong result.
pen: https://codepen.io/fatdrfrog/pen/rNBXwrW
If you want to use some parameters not event for the onChange handler, please try this.
inputChanged = (idx, categoryvalue) => (e) => {
... ... ...
};
You can go ahead and allow the toCurrency to for visual effect but change the input change function as follows
inputChanged = (idx, index, e) => {
const { categories } = this.state;
//check for the value attribute and either set it to zero or to actual value
let bonusCategory = isNaN(e.target.value) ? 0 : e.target.value;
console.log(bonusCategory);
if (bonusCategory > 999) return;
categories.forEach(category => {
category.bonusrate =
category.value === index ? bonusCategory : category.bonusrate; //note the use of bunus category
});
this.setState(oldState => {
const newDisabledButtons = [...oldState.disabledButtons];
newDisabledButtons[idx] = false;
return {
categories,
isEdit: false,
inCart: true,
disabledButtons: newDisabledButtons
};
});
};
You can either use input with type='number' (https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/number) or parse user input before saving it to category.bonusrate (use parseInt or parseFloat depending on your number format):
category.bonusrate = category.value === index ? parseFloat(e.target.value) : category.bonusrate;
Related
I have a lot of different checkbox with different array to filled.
here is my checkbox (i have 4 différents)
"required_licence":[]
"equipment":[]
...
<Checkbox
style={styles.checkbox}
value={props.box.cotier}
onValueChange={() => {
props.checked(
"cotier", ** My value to record inside my array **
"required_licence", ** the name of my array **
"box", ** the type of my values (because i also have input) **
props.isChecked ** to change if i'm true or false **
);
}}
color={props.box.cotier ? "#4630EB" : undefined}
/>
Also my fonction to add the value inside my state "form"
const checked = (value, fieldName, type, checked) => {
setBox((oldValue) => {
return {
...oldValue,
[value]: !box[value],
};
});
let values = [value];
if (type === "box") {
if (box[value] === false) {
setArray((oldValue) => [...oldValue, value]);
} else {
let index = array.indexOf(value);
array.splice(index, 1);
}
}
setForm((oldValue) => {
return {
...oldValue,
[fieldName]: [value]
};
});
};
when i click on my checkbox, the value is inside my array but delete the other one so i always have just one value .
My else is supposed to delete when my box is not selected.
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")
}
Example of code:
https://stackblitz.com/edit/react-filtering-hooks-search-category?embed=1&file=index.js
In the above StackBlitz example, I am attempting to filter a list of items from a search input as well as by filtering out by categories through buttons. I already have this working with the search input and one button toggle, but I am struggling to make this conditional to work with multiple category selections. I'm stuck on coming up with the expression that filters by searchText as well as all the combinations of category selections. as seen in the logic below:
React.useEffect(() => {
const searchRegex = searchText && new RegExp(`${searchText}`, "i");
const filteredData = items.filter(
(item) =>
(!searchRegex ||
searchRegex.test(item.title) ||
!searchRegex ||
searchRegex.test(item.source)) &&
(!productsFilter || item.type === "product")
);
setFilteredItems(filteredData);
}, [searchText, productsFilter, resourceFilter, extraFilter]);
I started by removing the individual state you had for each filter and created a new one, which simply represented Filter as a whole:
const [filter, setFilter] = React.useState(new Set());
As each filter is selected, we can check the Set if it's included. If it is, we can remove it, otherwise we can insert it:
const filterClick = (value) => {
if (filter.has(value)) {
setFilter(prevFilter => {
const newSet = new Set(prevFilter);
newSet.delete(value);
return newSet;
});
} else {
setFilter(prevFilter => {
const newSet = new Set(prevFilter);
newSet.add(value);
return newSet;
});
}
};
We can indicate the ToggleButton is selected by checking the filter state:
<ToggleButton
togglable={true}
selected={filter.has("product")}
onClick={() => filterClick("product")}
>
Finally I combine this, together with your Input Search so we can filter on both the Filter and the Input Search:
let filteredItems = items.filter(item => {
if (filter.size > 0 && !filter.has(item.type))
return false;
if (searchText.length > 0 && !`${item.title}${item.descriptoin}`.includes(searchText))
return false;
return true;
}).map((item, i) => <li>{item.title} <br/><span>{item.descriptoin}</span></li>);
btw: descriptoin is spelt incorrectly and should be description.
I have a working example here:
https://stackblitz.com/edit/react-filtering-hooks-search-category-fktr2w
I'm trying to implement a search function that returns find which has search word in the specified array. Let's say, a collection has [aa, ab, aaa], and search word is "a". In this case, return the object to display. Because at least one of the strings in the array has 'a'.
dataStructure
[
{
name:'aa',
searchWords:['aa','ab','bc'] <- I want to use this array for search
},
{
name:'bb',
searchWords:['bb','bc','de'] <- I want to use this array for search
},
...
]
I tried to fix the issue, by using includes(), filter(),indexOf(). However still it returns nothing or returns data when the search word is exactly matched.
How to fix the code to achieve aiming?
Thank you in advance!
this part works well
let filterStudents = students;
if (searchName.length > 0 && searchTag.length === 0) {
filterStudents = students.filter((student) => {
if (
student.firstName.toLowerCase().includes(searchName.toLowerCase())
|| student.lastName.toLowerCase().includes(searchName.toLowerCase())
) {
return true;
}
return false;
});
Problem happens on this part
} else if (searchName.length === 0 && searchTag.length > 0) {
filterStudents = students.filter(
(student) => {
console.log(student.tags);
student.tags.filter((tag) => {
console.log(tag);
tag.indexOf(searchTag) > -1;
});
},
);
} else if (searchName.length > 0 && searchTag.length > 0) {
} else {
console.log('both');
}
You don't return from the filter callbacks
As a sidenote, there is also String#includes:
filterStudents = students.filter(student =>
student.tags.some((tag) => tag.includes(searchTag))
);
If you only want to search for matches when the corresponding searchTag or searchName is filled out, use the conditional operator inside the filter callback to check whether the filter test should be carried out:
const students = [
{
name:'aa',
searchWords:['aa','ab','bc']
},
{
name:'bb',
searchWords:['bb','bc','de']
},
];
const doFilter = () => {
const [searchName, searchTag] = [...document.querySelectorAll('input')]
.map(input => input.value.toLowerCase());
const filtered = students.filter(({ name, searchWords }) => (
(searchName ? name.toLowerCase().includes(searchName) : true) &&
(searchTag ? searchWords.some(word => word.toLowerCase().includes(searchTag)) : true)
));
code.textContent = JSON.stringify(filtered);
};
window.addEventListener('change', doFilter);
<input placeholder="searchName">
<input placeholder="searchTag">
<div>
<code id="code"></code>
</div>
The reason why I use onKeyDown is the lang for typing is Korean.
I have several inputs and when users type over than 20 bytes, I want to stop them to keep typing.
//this calculates bytes
const getByteLength = (s,b,i,c) => {
for(b=i=0;c=s.charCodeAt(i++);b+=c>>11?3:c>>7?2:1);
return b;
}
.
handleLength = (e) => {
let currentBytes = getByteLength(e.currentTarget.value);
// checked : it calculates bytes successfully.
if (currentBytes > 20){
// checked : This is only working for English. When I type over than 20 bytes, this removes the lastest letter. but I still can type Korean.
e.currentTarget.value =
e.currentTarget.value.substring(0,e.currentTarget.value.length - 1);
}
}
<input onKeyDown={this.handleLength}>
You should save the value of your input in a state variable:
class Foo extends Component {
state = {
value: ''
};
handleLength = (e) => {
let currentBytes = getByteLength(e.currentTarget.value);
// checked : it calculates bytes successfully.
let value = e.currentTarget.value;
if (currentBytes > 20){
value = e.currentTarget.value
.substring(0,e.currentTarget.value.length - 1);
}
this.setState({ value });
}
And then use the value in the state, in your input:
<input value={this.state.value} onKeyDown={this.handleLength} />