I developed a React App using Material-UI then I tried to create independent Components,
check the below independent components(<PanelDiv/>),
render() {
return (
<div className="panelDiv-component" style={{display:this.props.display}}>
<div className="panel-field-content">
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
/>
{/* <input defaultValue className="form-control"></input>*/}
</div>
</div>
);
}
I tried to use the component like this,
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
display={this.state.display[0]}
/>
But I can't update input field in this way.Also there is no error. How can i solve this? I want to update my input field.
Please check my input filed in the below image :
Because you are controlling the value of TextField by using value attribute but you are not updating the value by using onChange function, Since value of TextField is not changing so it becomes read only.
Solution:
Specify the onChange function with TextField and update the value inside that, Like this:
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
onChange={this.props._change}
/>
Inside parent component:
_Change(event, value){
//update the value here
}
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
_change={this._change}
display={this.state.display[0]}
/>
If you pass value as a prop to TextField you can't change that text!
On Material-UI official documentation they have used defaultValue="default val" as a prop.
So I used defaultValue as a prop! It worked fine for me!
<TextField
type="text"
defaultValue={this.props.val}
onChange={handleChange}
/>
Had the same error. I was not able to key in anything and it was because there was no name props included. example:
<TextField
type="email"
name='email'/>
Look at this example - https://jsfiddle.net/y857yeLq/
You should define a function, which is handles of text change and pass it to onChange property. In this example I used state for storing current text field value. I see, that you use props for that, but the principle is the same - function should update props in your case.
const { TextField, MuiThemeProvider, getMuiTheme } = MaterialUI;
class SliderExampleControlled extends React.Component {
state = {
value: '',
}
render() {
console.log(this.state);
return (
<div style={{width: '50%', margin: '0 auto'}}>
<TextField
hintText="Type here"
value={this.state.value}
onChange={(e) => this.setState(e.target.value)}
/>
</div>
);
}
}
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<SliderExampleControlled />
</MuiThemeProvider>
);
ReactDOM.render(
<App />,
document.getElementById('container')
);
I was running into this problem as well and I needed the onClick function to take more than just the event I also needed it to take the row number because my state had an array representing the rows in a table. I was able to do that using this chunk of code
onChange={(e) => this.nameChange(e.target.value, row.row_num)}
then in my function called nameChange I was able to update the value
Related
I have child Component with input, and in the parent I've a button that disabled based on this input.
I thought about creating 'top level' state and pass the values like this:
const Parent = () => {
const [projectName, setProjectName] = useState('')
return (
<>
<Child projectName={projectName} setProjectName={setProjectName} />
<button disabled={projectName.length === 6}/>
</>
)
}
My question is, Is it solid react way to implement this?
In the child component I'm getting undefined for both projectName and setProjectName, why is it happening and how can I solve this?
Child Component:
const Child= ({projectName, setProjectName}) => {
return (
<>
<h2><StyledInlineSpan>Projects / </StyledInlineSpan>Create New Project</h2>
<Input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
</>
)
}
You shouldn't get an undefined, I think it is a problem with your Input component. I created a codesandbox with the same use case. As you type into the input, the Child component will change the state variable and the parent uses it.
It is completely fine to create a controlled Child component like this.
Seems like you have mis-spelled Input.
In React if the first letter of any HTML tag is capital, then it is treated as a custom React component.
Simply rename this
<Input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
to
<input autoFocus placeholder="Project Name" value={projectName} onChange={({ target }) => { setProjectName(target.value) }} />
I have a functional SearchBar child component that is linked to the parent homepage. I pass it props of id and label from the parent component. The child component reads the props id and label as "undefined." I have this exact same code for another dropdown component and it works. My guess is that this may be because I am passing the props to a hoisted (above the functional component body) renderInput function? Can you pass props to a hoisted helper function? I am also using Redux Form, which I'm not sure if it complicates things. Input, which is a prop from Redux Form, works fine. This is my code:
//helper render function hoisted to prevent re-render of searchbar with every key stroke
const renderInput = ({ id, label input }) => {
return (
<div className="container position-relative" id={id}>
{label}
<input
{...input}
type="text"
placeholder="Search..."
className="py-4 px-5 border rounded-sm form-control"
/>
</div>
);
};
const SearchBar = ({ handleSubmit, submitSearch }) => {
const onSubmit = (formValues, dispatch) => {
submitSearch(formValues); //calls search action creator
dispatch(reset("SearchBar")); //clears search form after submission
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Field
name="search"
component={renderInput}
/>
</form>
);
}
This is the working code, if anyone else runs into the same issue. You have to pass the custom props of id and label to the Field component in Redux Form for the Redux Form component to read it.
<Field name="search" component={renderInput} id={id} label={label} />
When I enter a character in the input box
The state updates with the new character
Then I loose focus on the input box
so I can only modify the box 1 keypress at at time
The input box is nested in 4 other components which includes 1 higher Order component (see below)
Page component
header(Modify)
InputForm
When I move the form code to the Page component it works.
How I keep the components separate (and reusable) and have the functionlity I need?
The form code is below
<input
key={props.id}
id={props.id}
type='text'
value={props.currentObject.name}
onChange={(event) => {
userFunctions.modifyItem(
editorState,
props.currentObject,
stateModifier,
event,
'name'
);
}}
/>
The full code for the entiure component is here
mport React, { Fragment } from 'react';
const InputForm = (props) => {
//prepare props
console.log('currentObject', props.currentObject);
const { editorState, stateModifier, userFunctions } = props.editorEssentials;
// const urlFormVisible = props.urlFormVisible;
//Styles
const componentStyle = 'container-flex-column';
// console.log('MOdify: currentState', editorState);
// console.log('MOdify: targetObject', currentObject);
// console.log('MOdify: stateModifier', stateModifier);
console.log('currentObject.name', props.currentObject.name);
return (
<Fragment>
<form
className={componentStyle}
// onSubmit={(event) =>
// userFunctions.submitItem(editorState, currentObject, stateModifier, event)
// }
>
<input
key={props.id}
id={props.id}
type='text'
value={props.currentObject.name}
onChange={(event) => {
userFunctions.modifyItem(
editorState,
props.currentObject,
stateModifier,
event,
'name'
);
}}
/>
{props.urlFormVisible && (
<input
type='url'
value={props.currentObject.url}
onChange={(event) =>
userFunctions.modifyItem(
editorState,
props.currentObject,
stateModifier,
event,
'url'
)
}
/>
)}
</form>
</Fragment>
);
};
export default InputForm;
The function operates on the state and is bound in the master component
WHAT I HAVE TRIED
There are some similar posts on stack overflow but they do not seem to answer my problem.
Changed the Key value in the input (although my original version of this had a no ket defined)
Double checked that the modifyItem function is bound correctly - it looks like it is and I guess if it wasn't the state would not update at all
Tried simplifing code to reduce the number of functions needed to run
MOVING THE COMPONENT THE CODE HAS MADE
I am not sure why but the Higher order component was the problem
when I changed the config from
Page component
header(Modify)
InputForm
to
Page component
header
Modify
InputForm
/header
It worked
Any ideas why I had this problem?
I have a modal that has 3 components. Each component represents a stage, so for example the first component is inputing the user's first name when the user click next, and it will go to the next component, which is inputing address and then user clicks next and it will take the user to the last stage, inputing a nickname. On every input element from the components, it will have an autoFocus. So far in the last two components, the inputs have an autoFocus except for the first component.
Not sure why the first doesn't have it, when I initialise the modal I see the input doesn't have the autoFocus, then I hit next then the second component input has it and I go back to the first component - hit the back button - then I see the input from the first component has an autoFocus. Very strange, I've been trying so many way to resolve this, from setting autoFocus={false} to the modal, creating a ref for the first input but still not working.
It looks like it's an issue with the modal, where it's initialized the focus is somewhere but not on the input. Has anyone encountered this issue?
Example (pseudo) code
//Component Hosting the modal
render(){
if(this.state.modal_stage === 1){
<FirstName />
}else if(this.state.modal_stage === 2){
<LasgtName />
}else if(this.state.modal_stage === 3){
<NickName />
}
return(
<Modal
dialogClassName="locationModal customModal"
show={this.state.modalShow} onHide={this.hideModal}
autoFocus="false">
<Modal.Header>
<div className="closeModal" onClick={this.hideModal}></div>
</Modal.Header>
<Modal.Body>
{ current_stage}
</Modal.Body>
<Modal.Footer>
{backButton}
{nextButton}
</Modal.Footer>
</Modal>
);
}
//<FirstName /> component
constructor(props){
super(props)
this.inputRef = React.createRef();
}
componentDidMount(){
this.inputRef.current.focus();
}
....
render(){
return(
<div>
<input type="text" placeholder="firstName" ref={this.inputRef}/>
</div>
);
}
Your help will be appreciated!!
Note:
I tried to set this autoFocus="false" to autoFocus={false} in the modal but the issue still remains.
Here is a similar solution as the one from #dev_junwen using a functional component and hooks. Also no need for a timeout.
import React, { useEffect, useRef } from 'react';
const FirstInput = ({ item, save }) => {
const innerRef = useRef();
useEffect(() => innerRef.current && innerRef.current.focus());
return <input ref={innerRef} />;
};
Found out a solution that will fix your problem. You can add a little timeout for your component to focus on your input. This should fix your issue.
class FirstInput extends React.Component {
constructor(props) {
super(props);
this.innerRef = React.createRef();
}
componentDidMount() {
// Add a timeout here
setTimeout(() => {
this.innerRef.current.focus();
}, 1)
}
render() {
return <input ref={this.innerRef} />;
}
}
This is a working example: https://codesandbox.io/s/react-bootstrap-autofocus-efkve?fontsize=14
Apparently there is a bug with react-bootstrap that doesn't allow autoFocus on a Modal component. The workaround while this bug is fixed is disabling animations on the Modal component.
<Modal animation={false}>
<Form.Control autoFocus />
</Modal>
Just add autoFocus = {false} on modal and autoFocus = {true} on input.
<Modal autoFocus={false}>
<Form>
<ModalHeader>Type Your Input</ModalHeader>
<ModalBody>
<Input autoFocus={true} />
<Button>Submit</Button>
</ModalBody>
</Form>
</Modal>
Ref: https://simplernerd.com/js-reactstrap-modal-autofocus/
You can use the onShow callback (that will be called after the animation is over) to set the focus to the inner field.
import React, {useRef} from 'react';
const MyForm = () => {
const innerRef = useRef();
return (
<Modal onShow={() => {innerRef.current.focus()}}>
<Form.Control ref={innerRef} />
</Modal>
)
}
This is supplement to ALoR answer:
bootstrap docs suggest using onEntered callback which is fired after the Modal finishes transitioning in. It worked for me well.
Also suggested here "autoFocus = {false} on modal" is discouraged as it messes up with screen readers
It looks like you are using a string and not a bool when setting autoFocus="false" - should be autoFocus={false}. This is why it works the second time as you are setting the value correctly via the ref: this.inputRef.current.focus();
So I'm having issues using redux-form with react-select, this is what I have so far:
<Field
name="objective"
type="text"
component={prop => <FormSelect {...prop} options={options} />}
label="Objective"
/>
And then:
const FormSelect = ({ options, label, input: { value, onChange, onBlur } }) =>
<ControlGroup title={label} styleId={label}>
<Select
options={options}
simpleValue
onChange={onChange}
value={value}
onBlur={() => onBlur(value)}
id={label}
/>
</ControlGroup>;
But then the select value does not change..
I get a redux-form/CHANGE with a action.payload of awareness (which is the value I want to select), but right after there is another redux-form action redux-form/BLUR with an action.payload of "".
I've read a bunch of github issues about this, tried a lot of them but nothing seems to be working..
example:
https://github.com/JedWatson/react-select/issues/1129
https://github.com/erikras/redux-form/issues/82
I also tried: onBlur={() => onBlur('awareness')} and it did not change the value on the select, even both payloads were had the same value..
I forgot to add redux-form reducer to my reducers.. Thanks anyway