react bootstrap readonly input within formcontrol - reactjs

I am using react bootstrap and this framework provides some nice FormControls.
But I would like to make the Input field that is generated within the FormControls to have a prop of readonly="readonly". This way, this field looks the same as my other FormControls, but does not give a keyboard input on IOS.
In my case, the input will be provided by a calendar picker which will be triggered by an popover.
Does anyone know how to give FormControl the parameter readonly="readonly", so that the generated Input field in the browser will have the prop readonly="readonly"?
Many thnx for the answers!

It doesn't look like a problem with react-bootstrap, but rather with react itself.
React is not transferring the 'readonly' prop to the generated (real) DOM element:
React-bootstrap create the following react virtual dom input:
Yet, react generated the following real DOM element, omitting the readonly attribute:
Maybe using 'disabled' could help in your case:
<FormControl
disabled
type="text"
placeholder="Enter text"
onChange={this.handleChange}
/>
For differences between readonly & disbabled see here:
https://stackoverflow.com/a/7730719/1415921
I have created an issue in React's github repo: #6783
UPDATE
After getting an answer in the above issue. You need to write it with camelcase: readOnly.
So it should be:
<FormControl
readOnly
type="text"
placeholder="Enter text"
onChange={this.handleChange}
/>

Old problem, new approach: Take advantage of onChange event to control if you'll call handleChange event or not. I defined editForm as a props value controlled by buttons, to see if i'm in view or edit mode.
Example:
<TextField
name="id"
label="ID
value={entityState.entity.Id || ""}
onChange={(a) => (props.formEdit ? handleChange(a) : "")}
/>

On the basis of values this attribut will be readOnly={!!value} to make input field disable to edit
class Input extends React.Component {
render () {
const { defaultValue, value, onChange } = this.props
const nothing = () => {}
return (
<input
type='text'
defaultValue={defaultValue}
value={value ? value.toUpperCase() : undefined}
readOnly={!!value}
onChange={value ? nothing : onChange}
/>
)
}
}
class App extends React.Component {
constructor () {
super ()
this.state = {
value: 'arr'
}
}
handleChange (e) {
const { target: { value }} = event
this.setState({ value })
}
render () {
const { value } = this.state
return (
<div>
<Input
onChange={this.handleChange.bind(this)}
defaultValue={'patata'}
/>
<Input
value={value}
/>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('arr'))

Related

How do I use "onfocus" &. "onblur" for input type date in React Functional Component?

Does anyone know how to make this code work in a React Functional Component?
onfocus="(this.type='date')" onblur="(this.type='text')"
I am trying to get placeholder text to appear prior to the user clicking on the input element. Then when clicked, the input will change to MM/DD/YYYY.
Trying to emulate something like this in my React project: https://stackoverflow.com/a/34565565/14677057
Would appreciate any help! Thank you!
Have a state variable for the type, then use it in what you render:
const Example = () => {
const [type, setType] = useState('text');
return (
<input
type={type}
onFocus={() => setType('date')}
onBlur={() => setType('text')}
/>
)
}
you can useRef for focusing. onBlur will work in camel case.
eg:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
const textInput = useRef(null);
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
Handling events with react elements is syntactically different from DOM elements.
events are named using camelCase, rather than lowercase.
We need to pass a JSX function, rather than a string.
`
function HandleInputField(){
const onChange=()=>{//your code}
const onFocus=()=>{//your code}
const onBlur=()=>{//your code}
return <input onChange={} onFocus={} onBlur={}/>
}
`

Able to type inside input text field without onChange method

I am learning React and below one is sample code I am trying out. I am able to render this component and able to type in characters in input field without any handleChange() method ? Is this fine ? because what I know is, in order to make input fields available for typing, we need to add handleChange method something like below
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
import React from "react";
class StudentForm extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<form>
<h1>Student Form</h1>
<input type="text" name="firstname"></input>
</form>
</div>
);
}
}
export default StudentForm;
handleChange is for setting the state value.
without onChange handler you can type in but your value is not getting stored anywhere.
For example, if you try to access your state this.state.firstname you will always get undefined.
You should have controlled component. Which is a simple and cleaner way access and store value in state.
To make your component controlled, you should have value and onChange props on input,
<input type="text" name="firstname" value={this.state.firstname} onChange={this.handleChange.bind(this)}></input>
Yes, consider the following
<input type="text" name="firstname" />
This is an uncrontrolled input which means React doesn't now about it's value nor how to change it. To make an input controlled you need to explicitly specify the value and onChange properties to bind this input to React's state
const Input = () =>{
const [value, setValue] = useState('')
return <input value={value} onChange={e => setValue(e.target.value)} />
}
Now the input is fully controlled by React, which provides the value it must print and a way to change it
After making below changes, I made this input element as controlled element and now I am not able to type in anything without using onChange handler.
import React from "react";
class StudentForm extends React.Component {
constructor() {
super();
this.state = {
firstname: ""
};
}
render() {
return (
<div>
<form>
<h1>Student Form</h1>
<input
type="text"
name="firstname"
value={this.state.firstname}
></input>
</form>
</div>
);
}
}
export default StudentForm;

How to make react semantic UI TextArea with default value, but still allows user to change the value?

I have tried using defaultValue and value in TextArea but it wont allow user to change the value.
The parent div of the textarea is redux-form Field. And try to pass the value stored in redux state to the textarea
<Field
name="message"
component={renderField}
...
onChange={ (e: any) =>
triggerHoldResponse(e.target.value, conversation.id)
}
/>
const renderField = ({input, type, meta: { error }}: any) => (
<div>
<TextArea
className={styles.textarea}
{...input}
placeholder={placeholder}
type={type}
/>
<div className={styles.errorSignal}>
{error}
</div>
</div>
);
SUI TextArea is base class for Form.TextArea, and both uses the same prop value for setting the default Text Value for the textarea.
Following Code works for me:
import React from 'react'
import { Form, Input, TextArea, Button } from 'semantic-ui-react'
const FormTextAreaExample = () => (
<Form
<Form.TextArea
autoHeight
onChange={this.handleMessageChange}
label="Message"
value={mesg}
placeholder="Enter your request message"
rows={3}
/>
</Form>
)
export default FormTextAreaExample;
Where value={mesg}, sets the default state of textarea (is set).
If you are using Semantic UI react you can use a Form.Field tag
You can set a default value and do what you are asking by using
"defaultValue='default text you are trying to display'
You can see a Form.Field Example below.
<Form>
<Form.Field
name="description"
required control={TextArea}
width={8}
onChange={this.handleChange}
label="Event Description"
defaultValue="Default text..."
type="text"
placeholder="Describe your event!"/>
</Form>
Note: defaultValue will override your placeholder and the defaultValue will not be removed when the click on textarea.
If you want to just display info of what the textarea is for I would use placeholder.
You can link the value of the Textarea input to that of a value from state such that you can set the default text for the text but also allow for the state to be updated in turn updating the value. You can accomplish this using linkstate.
Also if you already have the date in in your store you can set it up on the ComponentDidMount lifecycle event. to set the value of the linked state value therefore setting a default value.
Example usage from the docs:
import linkState from 'linkstate';
class Foo extends Component {
state = {
text: ''
};
render(props, state) {
return (
<input
value={state.text}
onInput={linkState(this, 'text')}
/>
);
}
}
https://github.com/developit/linkstate
An alternative way is to use the textarea tag since I was not able to find proper solution
example:
<label className="wps-label">Message</label>
<textarea
name="message"
placeholder='Your message'
onChange={(e)=> setMessage(e.target.value)}
>
{message}
</textarea>
<Form.Checkbox
name='show_tooltip'
label='Show popup or tooltip when hovering over the spoiler'
value='yes'
onChange={onChange}
defaultChecked={data?.show_tooltip}
/>
or via react-final-form
<Form
initialValues={{
title: modalView === 'add' ? '' : data?.title?.rendered,
content: modalView === 'add' ? '' : data?.content?.rendered
}}
...

how react programmatically focus input

I'm trying to implement a very simple use case, a UI feature, where:
There is a label with some content in it
If clicked, a text input replaces it with the content of label available
User can edit the content
When enter is pressed, the input hides and label is back with updated content
I could get finally all correct (in fact with a MongoBD backend, redux, etc.), and the only thing I couldn't ever do (paying a complete day in googling and reading S.O.F similar posts) was this:
When my text input appears, I can't transfer focus to it! First I tired this way:
<div className={((this.state.toggleWordEdit) ? '' : 'hidden')}>
<input id={this.props.word._id} className="form-control"
ref="updateTheWord"
defaultValue={this.state.word}
onChange={this.handleChange}
onKeyPress={this.handleSubmit}
autoFocus={this.state.toggleWordEdit}/></div>
<div className={((this.state.toggleWordEdit) ? 'hidden' : '')}>
<h3 onClick={this.updateWord}>
{this.state.word}</h3>
</div>
but autoFocus sure didn't work (I "guess" because the form is rendered, but in hidden state, making autoFocus useless).
Next I tried in my this.updateWor, many of suggestions I found on google and S.O.F.:
this.refs.updateTheWord.focus();
which together with similar suggestions all didn't work. Also I tried to fool React just to see if at all I can do something! I used real DOM:
const x = document.getElementById(this.props.word._id);
x.focus();
and it didn't work either. One thing I even could not understand to put into word is a suggestion like this:
having ref as a method (I "guess")
I didn't even try it because I have multiples of these components and I need ref to further get value of, per component, and I couldn't imagine if my ref is not named, how I could get the value of!
So could you please give an idea, helping me to understand that in case I'm not using a Form (because I need a single input box replacing a label) how I could set its focus when it's CSS (Bootstrap) class is losing 'hidden' please?
The way you have used refs is not the most preferred way or else its not the best practice anymore . try some thing like this
class MyClass extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
this.textInput.current.focus();
}
render() {
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
Update
From React 16.3 upwards you can use the React.createRef() API
class MyClass extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focus = this.focus.bind(this);
}
focus() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
From React 18.xx upwards you can use the useRef Hook
import React, { useRef } from "react";
export const Form = () => {
const inputRef = useRef(null);
const focus = () => {
inputRef.current.focus();
};
return (
<div>
<input type="text" ref={inputRef} />
<input type="button" value="Set Focus" onClick={focus} />
</div>
);
};
Just add autofocus attribute to the input. (of course in JSX it is autoFocus)
<input autoFocus ...
useFocus hook
// General Focus Hook
const useFocus = (initialFocus = false, id = "") => {
const [focus, setFocus] = useState(initialFocus)
const setFocusWithTrueDefault = (param) => setFocus(isBoolean(param)? param : true)
return ([
setFocusWithTrueDefault, {
autoFocus: focus,
key: `${id}${focus}`,
onFocus: () => setFocus(true),
onBlur: () => setFocus(false),
},
])
}
const FocusDemo = () => {
const [labelStr, setLabelStr] = useState("Your initial Value")
const [setFocus, focusProps] = useFocus(true)
return (
<> {/* React.Fragment */}
<input
onChange={(e)=> setLabelStr(e.target.value)}
value={labelStr}
{...focusProps}
/>
<h3 onClick={setFocus}>{labelStr}</h3>
</>
)
}
For a more complete demo click here.
In addition to the previous answers, I've added setTimeout to make it work
handleClick() {
if (this.searchInput) {
setTimeout(() => {
this.searchInput.focus();
}, 100);
}
}
where searchInput is the jsx ref of the input
<input
type="text"
name="searchText"
ref={(input) => { this.searchInput = input; }}
placeholder="Search" />
and the handleClick() is an onClick handler to any element
#BenCarp's answer in typescript
Pass the inputRef to an input and just call setFocus to set the focus to it.
export const useInputFocus = (): [MutableRefObject<HTMLInputElement | undefined>, () => void] => {
const inputRef = useRef<HTMLInputElement>();
const setFocus = (): void => {
const currentEl = inputRef.current;
if (currentEl) {
currentEl.focus();
}
};
return [inputRef, setFocus];
};
Use componentDidUpdate method to every time update the component
componentDidUpdate(prevProps, prevState) {
this.input.focus();
}
You can use "useRef" hook and make a reference to your input control, then use your reference.current.focus()

ReactJS: How-to set focus to input-element when it enters the DOM?

How to set focus to an input element when it enters the DOM?
Scenario
When a button is clicked the input element is displayed. How to set the focus to this element?
Code-Snippet
class Component extends React.Component{
constructor(props) {
super(props);
this.state = {
showInput: false
}
}
render() {
return (
<div>
<div onClick={() => {
this.setState({showInput: true});
ReactDOM.findDOMNode(this.refs.myInput).focus() // <- NOT WORKING
}}>
Show Input
</div>
{
(this.state.showInput) ? (
<input
type="text"
ref="myInput"
/>
) : ""
}
</div>
);
}
}
Calling ReactDOM.findDOMNode(this.refs.myInput).focus() after state change does not work. Also changing just the style or type property on state change does not work.
Assuming you only need one visible input on the page at a time to have autofocus Poh Zi How's suggestion of using the autofocus is probably the simplest.
<input type="text" autofocus/>
should do the trick, no JS needed!
In the componentDidMount and componentDidUpdate hooks do this:
ReactDOM.findDOMNode(this.refs.myInput).focus()
you should use ref
<input ref={(input) => { this.inputSearch = input; }} defaultValue="search ... " />
and use this code for focus
this.inputSearch.focus();
I had to define the variable as HTMLInputElement 1st...
private inputSearch: HTMLInputElement;
And then add this into the control:
ref={(input) => { this.inputSearch = input; }}
THEN I could get this to build/work:
this.inputSearch.focus();
From the docs:
"findDOMNode only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling findDOMNode() in render() on a component that has yet to be created) an exception will be thrown."
As mentioned by Piyush.kapoor, you need to place that incomponentDidMount and/or componentDidUpdate.

Resources