How to pass register to React Hook Forms Factory Component? - reactjs

I am trying to create a "factory" of sorts so:
This works:
<>
<span className={classes.p}>{"test"}</span>
<input ref={register} className={classes.input} name="legal_name_1" />
</>
But when I wrap the input in a function in a component it does not work:
const MyInput = ({ name, register, ...props }) => {
return (
<>
<span className={classes.p}>{AllDisasterAppFields[name]}</span>
<input ref={register} className={classes.input} name={name} {...props} />
</>
);
};
<MyInput register={register} name= name="legal_name_1" {...props} />
Any ideas?

I understand that you want to pass register as a prop.
If I'm right so You have to write your code like this (Don't use ref property but this {...register(name)}):
const MyInput = ({ name, register, ...props }) => {
return (
<>
<span className={classes.p}>{AllDisasterAppFields[name]}</span>
<input {...register(name)} className={classes.input} name={name} {...props} />
</>
);
};
<MyInput register={register} name="legal_name_1" {...props} />

Related

React - pass props into input component

What I need is to be able to customize textAreaCount and other props in each separate instance of <Texarea/>. The textAreaCount is different for each <Texarea/> so how do I modify the component to be able to pass in custom textAreaCount for each <Texarea/>?
https://codesandbox.io/s/rkv88-forked-vjo0rn?file=/src/App.js:0-948
import React, { useState } from "react";
const Textarea = (value, id, maxLength, textAreaLimit) => {
const [textAreaCount, ChangeTextAreaCount] = React.useState(0);
const [state, setstate] = useState({
headline: "",
title: ""
});
const { headline, title } = state;
const changevalue = (e) => {
setstate({
...state,
[e.target.name]: value
});
ChangeTextAreaCount(e.target.value.length);
};
return (
<>
<p>{textAreaCount}/{textAreaLimit}</p>
<textarea
type="text"
rows={5}
id={id}
value={value}
maxLength={maxLength}
onChange={(e) => {
changevalue(e);
}}
/>
</>
);
};
export default function FullWidthTabs() {
return (
<div>
<Textarea value={headline} id="test" maxLength={5} textAreaLimit={5}/>
<Textarea value={title} id="test2" maxLength={10} textAreaLimit={10}/>
</div>
);
}
Forward the props you need.
const Textarea = (props) => {
const [textAreaCount, setTextAreaCount] = React.useState(0);
const recalculate = (e) => {
setTextAreaCount(e.target.value.length);
};
return (
<>
<p>{textAreaCount}/5</p>
<textarea type="text" rows={5} maxLength={5} onChange={recalculate} {...props} />
</>
);
};
Now it will forward any props into the textarea element. This will set the id and will overwrite the rows prop.
<Textarea id="textarea-1" rows={4} />
<Textarea id="textarea-2" rows={5} maxLength={10} />
As we can see you try to pass props as below:
<Textarea value={title} id="test2" maxLength={10} textAreaLimit={10}/>
But In Your Textarea Component you received props argument as multiple args as below:
const Textarea = (value, id, maxLength, textAreaLimit) => {
return (
<>
</>
);
};
Instead that you need to destruct your props argument or you can set whole passed value props as single object props as below:
Method 1:
const Textarea = ({value, id, maxLength, textAreaLimit}) => {
return (
<>
<textarea type="text" id={id} value={value} rows={5} maxLength={maxLength} onChange={recalculate} textAreaLimit={textAreaLimit} />
</>
);
};
Method 2:
const Textarea = ({...props}) => {
return (
<>
<textarea type="text" id={id} value={value} rows={5} maxLength={maxLength} onChange={recalculate} textAreaLimit={textAreaLimit} />
</>
);
};
Method 3:
const Textarea = (props) => {
return (
<>
<textarea type="text" id={props.id} value={props.value} rows={5} maxLength={props.maxLength} onChange={recalculate} textAreaLimit={props.textAreaLimit} />
// Or Instead you can do as below
// <textarea type="text" rows={5} maxLength={5} onChange={recalculate} {...props} />
</>
);
};

How to set state for text box in functional component

I am working on React JS. I have one text-box component and I want to show some default value in it. After that, the user should be allowed to change the value. Now I am unable to change the value. The text box is behaving like read-only. Below is my code
const EditStyleFormComponent = ({
submitting,
invalid,
}) => (
<form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage:'', value: 'Current' }} />
</InputGroup>
</form>
);
Below is my TextFieldWithValidation code.
export const TextFieldWithValidationComponent = ({
meta,
input,
noStyles,
...otherProps
}) => (
<TextField
state={noStyles ? textFieldStates.DEFAULT : getState(meta)}
errorMessage={meta.touched ? meta.error : null}
{...input}
{...otherProps}
/>
);
Below is my TextField code.
const TextField = ({
className,
label,
description,
state,
errorMessage,
isEditable,
spaceAtBottom, // Not used, but we don't want it in otherProps
...otherProps
}) => {
const inputId = _.uniqueId();
return (
<div className={className}>
{label &&
<label htmlFor={inputId}>{label}</label>
}
<div className="input-group" id={isEditable ? 'editable' : 'readonly'}>
<input
id={inputId}
readOnly={!isEditable}
{...otherProps}
/>
{getStatusIcon(state)}
{errorMessage &&
<Error>{errorMessage}</Error>
}
{description &&
<Description>{description}</Description>
}
</div>
</div>
);
};
Can someone help me to fix this issue? Any help would be appreciated. Thanks
You can use State Hook for manage state in functional component.
Example :
const Message = () => {
const [message, setMessage] = useState( '' );
return (
<div>
<input
type="text"
value={message}
placeholder="Enter a message"
onChange={e => setMessage(e.target.value)}
/>
<p>
<strong>{message}</strong>
</p>
</div>
);
};
Yu defined onChange as empty string in EditStyleFormComponent component. So on any change input component just do nothing.
onChange should be some function that will update value.
If you want to use functional components there are two possible solutions:
Lift state up to parent component of EditStyleFormComponent (in case parent is class based component)
Use React Hooks like so (just example!)
const EditStyleFormComponent = ({
submitting,
invalid,
}) => {
const [inputValue, setInputValue] = useState ('Current'); // default value goes here
return <form className={className} onSubmit={handleSubmit}>
<h2>LSPL (Low Stock Presentation Level)</h2>
<Line />
<InputGroup>
<TextFieldWithValidation name="lsplMan" label="LSPL Manual" input={{ onChnage: (e) => { setInputValue(e.target.value); }, value: inputValue }} />
</InputGroup>
</form>
};

Material-UI and Redux-form not styling when being mapped

I've created this codesandbox - https://codesandbox.io/s/pk8p4lvl90
I can implement the material-ui instructions (https://redux-form.com/7.2.2/examples/material-ui/) fine without the mapping mechanism, but as soon as I apply the mapping I can't get the material-ui to implement the look for a textfield.
In my example I have commented out the code I have tried that works without mapping being involved.
Form -
<form onSubmit={handleSubmit}>
<div>
{/* <Field
name="firstName"
component={renderTextField}
label="First Name"
/>*/}
<FieldArray
name="firstName"
component={renderTextField}
label="First Name"
/>
</div>
</form>
TextField Render -
const renderTextField = ({ fields, input, label }) => (
<div>
{fields.map((newIntel, index) => (
{/* <TextField
name={newIntel}
key={index}
label={label}
placeholder={label}
component="input"
placeholder={label}
label={label} /> */}
<Field
name={newIntel}
key={index}
label={label}
placeholder={label}
component="input"
placeholder={label}
label={label}
/>
))}
<div
variant="fab"
color="primary"
className="jr-fab-btn"
aria-label="add"
onClick={() => fields.push()}
>
Click me
</div>
</div>
);
In order to use redux-form features with material-ui look, you need use redux-form's input component with render function that will return material-ui's component with appropriate props. You started doing so, but renderTextField should look a little bit differently, e.g.:
const renderTextField = ({
input,
label,
meta: { touched, error },
...custom
}) => (
<TextField
hintText={label}
floatingLabelText={label}
errorText={touched && error}
{...input}
{...custom}
/>
)
Having this, you can reuse it in, let's say renderForm function:
const renderForm = ({ fields, input, label }) => (
<div>
{fields.map((newIntel, index) => (
<Field
...
component={renderTextField}
...
/>
))}
...
</div>
);
That's based on what I've found in the redux-form Docs you linked. Take another look there as well, it's well described there as well.

with react final-form why is meta.touched always false with third party components?

using final-form, i have a third party input component. i've written an adapter for it. it has a validator as well, but meta.touched is always false. i've tried propagating the onFocus event up to the input, but no luck. what am i doing wrong?
const requiredValidator = value => (value ? undefined : 'is required');
const FloatingLabelInputAdapter = ({ input, meta, ...rest }) => (
<FloatingLabelInput
{...rest}
onChange={(event) => input.onChange(event)}
onFocus={(event) => input.onFocus(event)}
errorText={meta.touched ? meta.error : ''}
/>
)
// used like this:
<Field
component={FloatingLabelInputAdapter}
label="Email"
name="email"
type="text"
validate={requiredValidator}
/>
// and here's the render() of the component
render() {
const { children, label } = this.props;
const { focussing, used } = this.state;
console.log('FloatingLabelInput.props', this.props);
return (
<Group {...this.props} >
<TextInput
focussing={focussing}
innerRef={(comp) => { this.input = comp }}
onFocus={this.onFocusHandle}
onBlur={this.onBlurHandle}
onChange={this.onChange}
type={this.props.type} />
<Label
focussing={focussing}
used={used}>
{label}
</Label>
<Bar focussing={focussing} />
</Group>
);
}
}
annnnd as usual i answer my own question.
i had to propagate the onBlur() event as well, which makes sense since touched docs say it's true only after user has entered and left focus on the input.
<FloatingLabelInput
...
onBlur={(event) => input.onBlur(event)}
/>

ReactJS: Triggering event onBlur

I am having child component for input fields which is checking its validation onBlur event.
Child component usage:
<TextInput
id={'lastName'}
label={'Last name'}
required={true}
minChars={3}
maxChars={25}
/>
Child component code:
onBlur(event) {
// logic here
}
render() {
let props = this.props;
return (
<div>
<div className="form-group">
<label htmlFor={props.id}>{props.label}</label>
<input
id={props.id}
type={props.type}
className="form-control"
onBlur={this.onBlur.bind(this)}
/>
<p className="text-danger">{this.error}</p>
</div>
</div>
);
}
This works just fine.
When user submits form from parent component, I would like onBlur to be triggered across all inputs. How could I accomplish this?
In the parent component:
_handleBlur (eventData) {}
render () {
const handleBlur = this._handleBlur.bind(this);
return (
<form>
<ChildComponent onBlur={handleBlur} {...moreProps} />
<ChildComponent onBlur={handleBlur} {...moreProps} />
<ChildComponent onBlur={handleBlur} {...moreProps} />
<button type="submit" onClick={handleBlur}>Submit</button>
</form>
);
}
In the child component:
render () {
const props = this.props;
return (
<div>
<div className="form-group">
<label htmlFor={props.id}>{props.label}</label>
<input
id={props.id}
type={props.type}
className="form-control"
onBlur={props.onBlur}
/>
<p className="text-danger">{this.error}</p>
</div>
</div>
);
}
Based on eventData or other params, you can define which field needs to be blurred. I don't know what exactly needs to happen on blur. In some cases it might be better to split it into a handleBlur and handleBlurAll method.
Hope this helps

Resources