My input Tag is here:
<Input
value={isNaN(currentCount) ? '' : currentCount}
onKeyUp={(e) => {
onKeyup(e);
if (e.key === 'Enter') {}
}}
onChange={(e) => {
handleChange(e);
}}
/>
onKeyUp is working, but onChange is not working now.
I found that the value of the input tag does not change when I enter a value in the textbox.
Please let me know if you have had the same problem as me or know how to fix it.
You should create a state and set your input value in it like below:
const [value, setValue] = useState('')
const onChange = (event) => {
setValue(event.target.value)
}
return (
<Input
value={value}
onKeyUp={(e) => {
onKeyup(e);
if (e.key === 'Enter') {}
}}
onChange={handleChange}
/>
)
const [ currentCount, setCurrentCount] = useState('');
const handleChange = (e) => {
setCurrentCount( e.target.value || '');
}
return (
<input type="text" value={ isNaN(currentCount) ? '' : currentCount } onChange={ (e) => handleChange(e) }/>
)
Related
On my site, I'm using TagsInput, which allows the user to enter data into an input field, hit the enter button, and see it displayed as tags.
But I have one problem: the user can enter data with the same value as many times as he wants. I would like to restrict this ability and not allow the same data to be entered.
I already have some validation that displays a message if the user has entered an invalid data format.
Thus, I would like to add the ability to not accept data if it is already in the tags and display the corresponding message.
export default function TagsInputRequestURL(props) {
const {tags, setTags} = props;
const [input, setInput] = useState("");
const [isValid, setIsValid] = useState(true);
const onChange = (e) => {
const { value } = e.target;
if (e.target.value) {
setIsValid(() => /^(ftp|https?):\/\/[^ "]+$/.test(e.target.value));
} else {
setIsValid(true);
}
setInput(value);
};
const onSubmit = (e) => {
e.preventDefault();
if (isValid) {
setTags((tags) => [...tags, input]);
setInput("");
}
};
const deleteTag = (index) => {
setTags((prevState) => prevState.filter((tag, i) => i !== index));
};
return (
<div className={classes.container}>
{tags.map((tag, index) =>
<div className={classes.tag}>
<ClearIcon
className={classes.del}
fontSize="big"
onClick={() => deleteTag(index)}
/>
{tag}
</div>
)}
<form onSubmit={onSubmit}>
<input
className={classes.input}
value={input}
placeholder={props.inputPlaceholder}
onChange={onChange}
/>
{!isValid && <small style={{ color: "red" }}>Invalid URL</small>}
</form>
</div>
);
}
export default function TagsInputRequestURL(props) {
const {tags, setTags} = props;
const [input, setInput] = useState("");
const [isValid, setIsValid] = useState(true);
const onChange = (e) => {
const { value } = e.target;
if (e.target.value) {
setIsValid(() => /^(ftp|https?):\/\/[^ "]+$/.test(e.target.value));
} else {
setIsValid(true);
}
setInput(value);
};
const containsString = (str) => {
if(!str || str === '') return false
const strLower = str.toLowerCase();
let isExist = false
for(let i=0; i<tags.length; i++){
let itemLower = tags[i].toLowerCase();
if(strLower === itemLower){
isExist = true;
break;
}
}
return isExist;
}
const onSubmit = (e) => {
e.preventDefault();
if (isValid && !containsString(input)) {
setTags((tags) => [...tags, input]);
setInput("");
}
else{
console.log("You already hame same value in the 'tags' array. Try with different string.")
}
};
const deleteTag = (index) => {
setTags((prevState) => prevState.filter((tag, i) => i !== index));
};
return (
<div className={classes.container}>
{tags.map((tag, index) =>
<div className={classes.tag}>
<ClearIcon
className={classes.del}
fontSize="big"
onClick={() => deleteTag(index)}
/>
{tag}
</div>
)}
<form onSubmit={onSubmit}>
<input
className={classes.input}
value={input}
placeholder={props.inputPlaceholder}
onChange={onChange}
/>
{!isValid && <small style={{ color: "red" }}>Invalid URL</small>}
</form>
</div>
);
}
const [formData, setFormData] = useState({});
useEffect(() => {
fetch("/formdata")
.then((res) => res.json())
.then((data) => setFormData(data));
}, []);
console.log("Form Data", formData);
//Sorting by order
let attr;
form.forms.map((y) => {
return (attr = y.formAttributes.sort((a, b) => {
return a.order < b.order ? -1 : 1;
}));
});
return (
{attr.map((attri, index) => {
return (
<TextField
key={index}
label={attri.label}
value={formData[attri.datakey] || ""}
onChange={event => {const {value} = event.target; setFormData({formData: value})}}
/>
);
})}
)
I would like to ask help on how to manage multiple fields in Textfield onChange area? Currently, if I am going to input a value there are no changes that is happening.
Here's my code.
Tried the approach of using e.target.value however it would still stay the same.
You should add a name attribute, where the 'name' is the key of the key-value-pair in your object.
e.g.
<TextField
key={index}
name="somename"
label={attri.label}
value={formData[attri.datakey] || ""}
onChange={handleChange}
/>
Then you can update the field like that.
setFormData({
...formData,
[e.target.name]: e.target.value // becomes "somename: some value"
})
I want to use search filter in sidebar so i created search filter and implemented but its now working shown only input field. and i stuck with how to map the items to search filter.
here i attached some of my working code:
state = {
search : ""
}
onchange = e =>{
this.setState({search : e.target.val })
}
const Menu = ({ resources, onMenuTap, translate }) => {
const {search}=this.state;
if (search !== "" && resources.name.toLowerCase().indexof(search.toLowerCase()) === -1 ){
return null
}
onchange = e =>{
this.setState({search : e.target.val })
}
return (
<Card className={classes.sidebarCard}>
{/* Search */}
<input placeholder="Search" onChange={this.onchange} />
//
....
//
);
};
for your onchange, try to use that :
onchange = e =>{
this.setState({search : e.target.value })
}
and in your search input :
{/* Search */}
<input placeholder="Search" value={this.state.search} onChange={(e) => this.onchange(e)} />
Because you're using functional component. You need to use useState hook:
const [search, setState] = useState("");
if (
search !== "" &&
resources.name.toLowerCase().indexof(search.toLowerCase()) === -1
) {
return null;
}
onchange = (e) => {
setState(e.target.val);
};
The attached sanbox code is based on your code. But it seems it doesn't render:
You are using functional component. So you need to change your code in this way:
const Menu = ({ resources, onMenuTap, translate }) => {
const [search, setSearch] = useState(""); //<-- this is your state
const onchange = e =>{
setSearch(e.target.val); //set the state
}
if (search !== "" && resources.name.toLowerCase().indexof(search.toLowerCase()) === -1 ){
return null
}
return (
<Card className={classes.sidebarCard}>
{/* Search */}
<input placeholder="Search" onChange={onchange} value={search} /> //<-- set value equal to search state
{permissions === "Administrator" && (
<>
<MenuItemLink
className={classes.MenuItemLink}
activeClassName={classes.active}
to="/_apps"
primaryText={translate("easyadmin.apps")}
leftIcon={
<AppsOutlined fontSize="small" className={classes.iconColor} />
}
onClick={onMenuTap}
/>
<MenuItemLink
className={classes.MenuItemLink}
activeClassName={classes.active}
to="/_entitys"
primaryText={translate("easyadmin.customobjects")}
leftIcon={
<SettingsOutlinedIcon
fontSize="small"
className={classes.iconColor}
/>
}
onClick={onMenuTap}
/>
)}
);
};
on react docs forms section there is the following example using class components:
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
Considering Hooks can only be called either in a React function component or a custom React Hook function is there a way of doing it using hooks instead?
you can clean up #adam 's final solution a bit by not using the useCallback hook, and instead simply using the useState hook as a controlled component.
const MyComponent = () => {
const [inputs, setInputs] = useState({});
const handleChange = e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.value }));
return (
<>
<input name="field1" value={inputs.field1 || ''} onChange={handleChange} />
<input name="field2" value={inputs.field2 || ''} onChange={handleChange} />
</>
)
}
example
const MyComponent = () => {
const [inputs,setInputs] = useState({});
return (
<>
<input key="field1" name="field1" onChange={({target}) => setInputs(state => ({...state,field1:target.value}))} value={inputs.field1}/>
<input key="field2" name="field2" onChange={({target}) => setInputs(state => ({...state,field2:target.value}))} value={inputs.field2}/>
</>
)
}
you can pass in initial values like this:
const MyComponent = (initialValues = {}) => {
const [inputs,setInputs] = useState(initialValues);
...
}
EDIT: A nice short onChange according to #hamidreza's comment
const MyComponent = (initialValues = {}) => {
const [inputs,setInputs] = useState(initialValues);
const onChangeHandler = useCallback(
({target:{name,value}}) => setInputs(state => ({ ...state, [name]:value }), [])
);
return (
<>
<input key="field1" name="field1" onChange={onChangeHandler} value={inputs.field1}/>
<input key="field2" name="field2" onChange={onChangeHandler} value={inputs.field2}/>
</>
)
}
etc, etc, etc
Maybe, on the last example onChangeForField('...') will be triggered on each render, so maybe you have to write onChange={()=>onChangeForField('...')} or if you want the event to get passed onChange={(e)=>onChangeForField('...', e)}
I was looking for the same answer,but i was finding difficulty to understand the previous solutions,so i tried in my own way ,and i found a solution.
const [inputs,setInputs] = useState({
'field1':'',
'field2':'',
});
const handleChange = (e) => {
const name = e.target.name; //it is the name of that input
const value = e.target.value; //value of that input
setInputs((prev) => {
prev[name] = value;//changing the updated value to the previous state
return prev;
});
};
return (
<>
<input key="field1" name="field1" onChange={handleChange} value={inputs.field1}/>
<input key="field2" name="field2" onChange={handleChange} value={inputs.field2}/>
</>
adding to Adam's answer and for those who are looking towards typescript solution,
interface MyIType {
field1: string;
...
}
//Partial from typescript to make properties optional
interface MyFormType extends Partial<MyIType> {}
const [inputs,setInputs] = useState<MyFormType>(initialValues);
const onChangeForField = useCallback(({target}) =>
setInputs(_state => {
return {
..._state,
[target.name]: target.value,
};
}),
[]
);
If you were like me, having multiple inputs on multiple pages using the same input id/name/key, try value={data.xxx || ''} .
Full code:
const [data, setData] = useState<any>({});
const handleValueChanges = e => {
setData({
...data,
[e.target.name]: e.target.value,
});
};
<InputText (using prime react)
id="firstName"
name="firstName"
value={data.firstName || ''}
onChange={handleUpdate}
/>
As of v6 you can use .forEach(), Please refer to the migrate guide
[{name: "firstName", value: "Safwat" }, {name: "lastName", value: "Fathi", }].forEach(({name, value}) => setValue(name, value));
What's wrong with my way to handle input in react? I want to detect keycode and prevent them to be entered into the input, but now below code doesn't seem working.
const Input = ({ placeholder }) => { const [inputValue, setInputValue] = useState("");
const handleKeyDown = e => {
console.log(e.target.value);
if ([188].includes(e.keyCode)) {
console.log("comma");
} else {
setInputValue(e.target.value);
} };
return (
<div>
<input
type="text"
value={inputValue}
onKeyDown={handleKeyDown}
placeholder={placeholder}
/>
</div> ); };
https://codesandbox.io/s/ancient-waterfall-43not?file=/src/App.js
you need to call e.preventDefault(), but also you need to add onChange handler to input:
const handleKeyDown = e => {
console.log(e.key);
if ([188].includes(e.keyCode)) {
console.log("comma");
e.preventDefault();
}
};
const handleChange = e => setInputValue(e.target.value);
...
<input
type="text"
value={inputValue}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder={placeholder}
/>
When you update the value of input, you should use onChange().
But, If you want to catch some character and treat about that, you should use onKeyDown().
So, in your case, you should use both.
this is an example code about backspace.
const Input = (props) =>{
const [value, setValue] = React.useState('');
function handleChange(e){
setValue(e.target.value);
}
function handleBackSpace(e){
if(e.keyCode === 8){
//Do something.
}
}
return (
<div>
<input onChange={handleChange} onKeyDown={handleBackSpace} value={value} type="text" />
</div>
)
}
```
Pass the value from Parent to child. Please check the below code.
import React, { useState } from "react";
import "./styles.css";
const Input = ({ placeholder, inputValue, handleKeyDown }) => {
return (
<div>
<input
type="text"
value={inputValue}
onKeyDown={handleKeyDown}
placeholder={placeholder}
/>
</div>
);
};
export default function App() {
const [inputValue, setInputValue] = useState();
const handleKeyDown = e => {
console.log(e.keyCode);
console.log(e.target.value);
if ([40].includes(e.keyCode)) {
console.log("comma");
} else {
setInputValue(e.target.value);
}
};
return (
<div className="App">
<Input
placeholder="xx"
value={inputValue}
handleKeyDown={handleKeyDown}
/>
</div>
);
}
onKeyDown, onKeyUp, and onKeyPress contain the old value of the target element.
onInput event gets the new value of the target element.
check the below link I add some console log. which help you to understand which event contains the value
https://codesandbox.io/s/ecstatic-framework-c4hkw?file=/src/App.js
I think you should not use the onKeyDown event on this case to filter your input. The reason is that someone could simply copy and paste the content into the input. So it would not filter the comma character.
You should use the onChange event and add a Regex to test if the input is valid.
const Input = ({ placeholder }) => {
const [inputValue, setInputValue] = useState("");
const handleChange = e => {
const filteredInput = e.target.value.replace(/[^\w\s]/gi, "");
setInputValue(filteredInput);
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={handleChange}
placeholder={placeholder}
/>
</div>
);
};
But how it works...
So the regex is currently allowing any word, digit (alphanumeric) and whitespaces. You could for example extend the whitelist to allow # by doing const filteredInput = e.target.value.replace(/[^\w\s#]/gi, ""); Any rule inside the [^] is allowed. You can do some regex testing here https://regexr.com/55rke
Also you can test my example at: https://codesandbox.io/s/nice-paper-40dou?file=/src/App.js