I'm using react-date-picker, but on mobile the native keyboard shows up when clicked causing the date-picker to open on top, which doesn't look great. The online solution is to put the readonly attribute on the input field the date picker is bind with. But the read-date-picker component won't let me pass that prop...
Any nice solutions for this?
The readOnly is a good option to prevent the browser from showing the keyboard and typing on mobile. With the readonly set you will still be able to launch a click event on it.
When talking about the react-date-picker module the this will be also useful in non-mobile devices.
It is possible to add the option readOnly={true}, but it will disable completely the date picker inputs on all devices, as we can see on the following issues:
Datepicker does not open with readOnly=true #1443
make disable or readonly input field #961
Also, you will need to handle the onClick event and I don't think that this is a good idea.
Current workaround
At the moment, the solution to make the keyboard disabled on mobile and set the readOnly for all datePickers inputs will be edit the input properties on the component componentDidMount event:
componentDidMount() {
const datePickers = document.getElementsByClassName("react-datepicker__input-container");
Array.from(datePickers).forEach((el => el.childNodes[0].setAttribute("readOnly", true)))
};
A working solution using React hooks
const pickerRef = useRef(null)
useEffect(() => {
if (isMobile && pickerRef.current !== null) {
pickerRef.current.input.readOnly = true;
}
}, [isMobile, pickerRef]);
return (<DatePicker ref={pickerRef} ... />)
<DatePicker
. . . . .
onFocus={(e) => e.target.readOnly = true}
/>
This works for me.
So I ended up modifying the input-element in the componentDidMount lifecycle, like so;
document.getElementsByTagName("input")[0].setAttribute("readonly", "readonly");
This prevents the native visual keyboard on my phone to display. However it creates this "not allowed" red ugly cursor on desktop when hovering the input field, so I fixed that with by targeting my date-picker input.
.react-datepicker-wrapper input[readonly]{cursor: pointer;}
I welcome alternative solutions though.
A variation on Caroline Waddell's answer that got me unblocked on react-datepicker 2.8.0. The id of the date picker element is date-picker-input so modifying the the attribute after getting it by the id:
componentDidMount() {
document.getElementById('date-picker-input').setAttribute('readonly', 'readonly');
}
Did the trick for me if you have more than one input on the page.
Just hit this myself. Create a custom input with a button that opens the picker with the text of the selected value.
const ReadonlyInput = ({ value, onClick }: any) => (
<button onClick={onClick}>
{value}
</button>
);
return (
<ReactDatePicker
selected={fieldValue}
...
customInput = {<ReadonlyInput />}
/>
)
React datepicker has className react-datepicker__input-container.
So
const datePickers = document.getElementsByClassName(
"react-datepicker__input-container"
);
This returns an HTML collection which needs to be converted to an array. You can use Array.from but this is not supported in IE 11.
So, it is better to use native for loop.
So
for (let i = 0; i < datePickers.length; i++) {
datePickers[i].childNodes[0].setAttribute("readonly", true);
}
I used something like this onChangeRaw={(e)=>handleDateChangeRaw(e)} which allowed me to disable keyboard type option and i made the cursor pointer .
const handleDateChangeRaw = (e:React.FormEvent<HTMLInputElement>) => {
e.preventDefault();
}
<DatePicker
selected={(value && new Date(value)) || null}
onChange={val => { onChange(name, val); }}
dateFormat={ dateFormat }
minDate={new Date()}
timeIntervals={1}
onChangeRaw={(e)=>handleDateChangeRaw(e)}
/>
.react-datepicker__input-container input {
cursor: pointer;
}
JSX (React) Create a Custom Input with readOnly option
const DateCustomInput = ({ value, onClick }) => (
<input className="classes" readOnly onClick={onClick} placeholder='Date of
Birth' value={value}/>
);
Use this with datePicker
<DatePicker
id="preferred-date" name="EnquireNow[prefered_date]"
selected={date}
customInput={<DateCustomInput />}
/>
This will ensure calendar still pops up (which is not happening with readOnly props with DatePicker) but native keyboards do not pop up. This will not allow to edit the input even in desktop mode. To allow that use readOnly with mobile devices only
You can blur it onFocus to keep the keyboard closed but the datepicker options open, like:
<Datepicker onFocus={e => e.target.blur()} />
Related
I am using react bootstrap AsyncTypeHead. I type keywords and it suggests values from the backend, then I click one of the suggestions and try to get the value selected, but it seems event does not exist. It throws all kind of errors. What could be the issue? I am trying to do it through onChange attribute with event.target.value:
<AsyncTypeahead
filterBy={filterBy}
id="async-example"
isLoading={isLoading}
labelKey="login"
minLength={3}
onSearch={handleSearch}
onChange={ (event) => setCitiesSend([...citiesSend, event.target.value])}
If instead event.target.value I put alert('test') it throws alert multiple times. It seems to be changing on each typed letter.
Full example: React Bootstrap Typeahead - Asynchronous Searching
The onChange function returns a value.
So, your code will be.
<AsyncTypeahead
filterBy={filterBy}
id="async-example"
isLoading={isLoading}
labelKey="login"
minLength={3}
onSearch={handleSearch}
onChange={ (value) => setCitiesSend((previous) =>[...previous, ...value])}
/>
im currently trying to create an dynamic form that uses a sub component to render out some input fields as createing them static would exceed a limit. I pass the states for the the form i made aswell as some date and the change form. But when i render the form as it does so fine! as soon as i change the state its sends a warning about uncontrolled components that you can read about it here
I have tried pre-setting all the fields with empty defaults but it doesnt help.
Am i doing it somewhat correct or totally wrong? or what is the correct way, or what am i doing wrong. thanks in adbance.
As for the code looks like this:
Edit.js
export default function InventoryItemEdit() {
const [form, setForm] = useState({});
function handleFormChange(e) {
setForm({ ...form, [e.target.name]: e.target.value });
}
const variants = (
<ItemVariants
form={form}
onChange={handleFormChange}
fields={form.sizes}
/* ^^ fields data fetched from the server i set via use effect hook when loading the page */
/>
);
const updateItem = async (event) => {
event.preventDefault();
/* Do form submit post */
};
return (
<form onSubmit={updateItem}>
<div>
<p htmlFor="name">Name</p>
<input
id="name"
name="name"
onChange={handleFormChange}
value={form.name}
type="text"
required
placeholder="Name of Item"
/>
</div>
{variants}
</form>
);
}
As for the sub component ItemVariants it looke like this
ItemVariants.js
export default function ItemVariants({
form = {},
onChange = '',
fields = [],
}) {
return (
<>
{fields.map((row, index) => (
<div>
<span>
{row.name}
</span>
<input
type="text"
id={`variant${index}`}
name={`variant${index}`}
onChange={onChange}
value={form[`variant${index}`]}
required
min="0"
placeholder="0"
defaultValue="0"
/>
</div>
))}
</>
);
}
Controlled component: is when your input value is coming from a single source of truth a state(meaning for an input value to change, you need to update the state holding the value)
Uncontrolled component: is when your input value is not coming from a state but rather it's coming from something we call useRef/createRef which helps to reference to react syntactic DOMNODE thus giving us the ability to interact with input in a false-actual-DOM(as if we were query an actual DOM input-node in pure-JS). Meaning if your input value is not coming from a state, it must come from a ref(ref.current.value which is equivalent to document.querySelector(theInputLocator).value).
Answer to your bug: I see that everything is okay, but the only issue is that you didn't set the initial state with the name key. Thats an analysing issue because in your code you doing [e.target.name]:e.target.value and the way inputs works generally is that event is triggered but must recent value is emitted when the event happens next. it works like a++.
Do this:
const [form, setForm] = React.useState({ name: '' });
The general rule of thumb is that always describe your form input keys when your inputs are predefine and not dynamic(in this case your name input is predefined).
So After digging reading this post i have to thank! #juliomalves for solution with value={form[`variant${index}`] ?? ''} or value={form[`variant${index}`] || ''}
I also found out i was accidently adding defaultvalue aswell as value which cannot be set at the same time i found out. After i tested it removed the default value and set it correctly to be a string! it now works like a charm!
Also thanks to #Emmanuel Onah for the explaination it really helped me understand more about the react states!
Thanks again for everyone that helped
I am using TextField material-ui component in my code. I want to check if the value entered by user is an iframe. How I can do that? I am using ReactJS.
I am using window.parent.frames.length > 0; to check if page has an iframe but it is not working for TextField case. I want to handle this case on onChange not on page level, it seems like window.parent.frames.length > 0; works on page level. I want the have a check inside my onChange in the TextField
Here is my code:
<TextField
label="Enter iframe"
variant="outlined"
onChange={({ target }) => {
const value = target.value;
//I want to check if `value` is an iframe
handleChange(value)
}}
multiline
/>;
You could use a regular expression to check if the input value contains an iframe with something like
const containsIframeRE = /<iframe(?: [^>]*?)?(?:\/>|>.*?<\/iframe>)/i;
if (containsIframeRE.test(inputValue)) alert("Iframe found!");
You can see the regex working and play with it on https://regex101.com/r/uMfLFS/1
I have a very interesting situation.
This is my component:
export const checkbox = ({ data }) => {
const inputRef = useRef(null);
console.log(inputRef); // Does not appear
return (
<FormGroup>
{data.data.map(item => (
<FormGroup>
<Input
ref={inputRef}
/>
</FormGroup>
</FormGroup>
);
};
It is a child of other component which basically get values and submits to form.
but to no avail..
How can I fix this? I just need it to keep the focus, so I can continue typing. Should I use React.memo() for this?
Also, please note that I have checked all the references I could find on SO and nothing helped. I have spent 3 days on this.
Based on our chat, the root cause was elements having a dynamic key prop which changed on each render. This was causing a new textarea element to be rendered with each change event and the new element didn't have focus.
The solution is to use a deterministic key which doesn't change between renders.
I'm newbie in making atom plugins. I have to make a field which will take an input. I'm using etch for component management. In the render method, I've made this input field
<input
name={'component'}
type={'text'}
onchange={this.onInputChange}
value={this.componentName}
/>
I've made this onInputChange method which looks like :
onInputChange = (event) => {
this.componentName = event.target.value;
etch.update(this);
}
but I'm getting an event which comes after some time (kinda debounced event), furthermore I'm not able to delete the text from input. What is the right way to make an input.
<div class="native-key-bindings">
<input/>
</div>
Try wrapping it in this way. It will also fix the delete issue.