React bootstrap select dropdown - reactjs

I am using ReactJS with BootStrap and is unable to get dropdown data that I am passing, in the event handler. The html is not built with option lists only input field is coming.
My code looks like:
import React from 'react';
import PropTypes from 'prop-types';
import { FormWithConstraints, FieldFeedback } from 'react-form-with-constraints';
import { FieldFeedbacks, FormGroup, FormControlLabel, FormControlInput } from 'react-form-with-constraints-bootstrap4';
class Select extends React.Component{
handleChange(event) {
//event.target.value
//do required changes
}
render(){
return(
<FormGroup for={this.props.name}>
<FormControlLabel htmlFor={this.props.name} style={styles.lableStyle}>{this.props.label}{this.props.required?<b
style={{color: "#2c3d4d"}}>*</b>:null}</FormControlLabel>
<FormControlInput
id={"Source"}
label={this.props.label}
placeholder="Select Country"
type="text"
// value={this.props.value}
onChange={this.handleChange}
// (event)=>{
// this.handleChange(event);
// this.props.onChange(event);
// }}
options={this.props.dropDownList}
required={this.props.required}
className="form-control"
optionsKey="name"
optionsValue="id"
// readOnly={this.props.readOnly}
// onClick={this.props.onClick}
/>
<FieldFeedbacks for={this.props.name} className="form-control-feedback"
style={styles.errorStyle}>
<FieldFeedback when="valueMissing" />
{(this.props.required)?
<FieldFeedback when={value => /^ *$/.test(value)}>Please enter valid text</FieldFeedback>:null}
</FieldFeedbacks>
</FormGroup>
);
}
}
and the drop data looks like
dropDownList=[
{name: "NAme",id:1,key:"Key"}];

Check the documentation of the widget you are using - FormControlInput
https://github.com/tkrotoff/react-form-with-constraints ?
Usually onChange callback gets only the event as input, and you can get the value from the event. eg:
event.target.value
More info:
React: Forms
https://react-bootstrap.github.io/components/forms/
React: Handling Events
https://reactjs.org/docs/handling-events.html

Any of these two possibilities are there.
Either you have to add an attribute as="select" to <FormControlInput> and remove type attribute, or Change type="text" to type="select"

Related

latest react-hook-form error handling with material-ui TextField

I have difficulties, using react-hook-form with material-ui.
I prepared a codesandbox example.
import { TextField } from "#material-ui/core";
import React from "react";
import { useForm } from "react-hook-form";
import "./styles.css";
interface IMyForm {
vasarlo: string;
}
export default function App() {
const {
handleSubmit,
formState: { errors },
register
} = useForm<IMyForm>();
const onSubmit = (data: IMyForm) => {
alert(JSON.stringify(data));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First Name</label>
<TextField
variant="outlined"
margin="none"
label="Test"
{...register("vasarlo", {
required: "error text"
})}
error={errors?.vasarlo ? true : false}
helperText={errors?.vasarlo ? errors.vasarlo.message : null}
/>
<input type="submit" />
</form>
);
}
How can I properly use the register function, to get error message, write to input field, also the onSubmit function to work?
I couldn't find answer in the documentation for this scenario.
In react-hook-form v7, this is how you register an input:
<input {...register('name')} />
Calling register() will return necessary props for your input like onChange, onBlur and ref. These props make it possible for react-hook-form to keep track of your form data. Now when you use register with Material-UI TextField like this:
<TextField {...register('name')} />
You pass the ref property directly to the TextField while the correct place to put it is in the inputRef:
<TextField inputRef={ref} />
So you have to modify your code like this:
const { ref: inputRef, ...inputProps } = register("vasarlo", {
required: "error text"
});
<TextField inputRef={inputRef} {...inputProps} />
How can I properly use the register function, to get error message
There is nothing wrong with your error handling code. Though you can shorten you code a bit more using Typescript's optional chaining operator ?.:
<TextField
error={!!errors.vasarlo}
helperText={errors?.vasarlo?.message}
inputRef={ref}
{...inputProps}
/>
Live Demo
You're misusing Controller. react-hook-form's default functionality is using uncontrolled inputs. Remove <Controller/> and put this on your TextField
inputRef={register({
required: 'This is required',
validate: (data) => myValidationFunction(data)
})}
You'll only want to use a controller if you NEED to modify/intercept/format a value that is being displayed in the TextField that is different from what a user is typing, i.e a phone number getting shown as (xxx)-xxx-xxxx when only typing the digits.

Enzyme Shallow not finding a react-bootstrap Component

Below is a Sign In React SignIn Component made by using Redux-forms
const renderInput = ({input,label,type,placeholder}) => {
return (
<div>
<Form.Label>{label}</Form.Label>
<Form.Control type={type} placeholder={placeholder} { ...input}/>
</div>
)
}
export let signInForm = props => {
const { error,handleSubmit , pristine , submitting } = props
return (
<Container className="justify-content-md-center">
<Alert variant="primary">Sign in here if you already have an account</Alert>
<Form onSubmit={handleSubmit}>
<Form.Group>
<Field name="email" component={renderInput} label="Email" type="email" placeholder="Email" />
</Form.Group>
<Form.Group>
<Field name="password" component={renderInput} label="Password" type="password" placeholder="Password" />
</Form.Group>
<Button type="submit" disabled= { pristine || submitting }>Sign In</Button>
</Form>
</Container>
)
}
export default signInForm = reduxForm ({
form : 'signIn'
})(signInForm)
My enzyme-shallow test for this
import React from 'react';
import { shallow } from 'enzyme';
import {signInForm as SignIn} from './SignIn';
import Button from 'react-bootstrap/Button'
import { expect } from 'chai';
describe('Test SignIn component', () => {
it('Test click event', () => {
const mockCallBack = jest.fn();
let wrapper = shallow(<SignIn onSubmit={mockCallBack}/>);
expect(wrapper.find(Button)).to.have.lengthOf(1);
})
})
My test output says
AssertionError: expected {} to have a length of 1 but got 0
1) The test fails. The Button component is not found in the test. I am expecting it to have a length of 1
2) I am using chai method to.Have.lengthOf because I could not get the jest method toHaveLength to work. toHaveLength seems to be used for only checking arrays or strings size. How could I use jest to do this?
If you are trying to simulate the SignIn form submit, you would actually call the simulate event on the form itself and not on the button.
You can simulate that with this code:
wrapper.find('form').simulate('submit');
Here is some info on why that is from the Enzyme docs:
Currently, event simulation for the shallow renderer does not propagate as one would normally expect in a real environment. As a
result, one must call .simulate() on the actual node that has the
event handler set.
Even though the name would imply this simulates an actual event, .simulate() will in fact target the component's prop based on the
event you give it. For example, .simulate('click') will actually get
the onClick prop and call it.
As noted in the function signature above passing a mock event is optional. Keep in mind that if the code you are testing uses the
event for something like, calling event.preventDefault() or accessing
any of its properties you must provide a mock event object with the
properties your code requires.
https://airbnb.io/enzyme/docs/api/ShallowWrapper/simulate.html

Redux Form wrapper for kendo-react-ui Input error

I am using react-kendo-ui. I want to wrap Input from #progress/kendo-react-inputs to use it with ReduxForm. Please find my code below:
import React from 'react'
import { Input } from '#progress/kendo-react-inputs';
const InputText = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<Input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
)
export default InputText
Call the InputText from another component as below:
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import { Input } from '#progress/kendo-react-inputs';
import InputText from './input-text';
const validateNotEmpty = value => !value ? 'Must enter a value' : null;
const onSubmit = (values) => {
console.log(values);
}
const AddLoc= ({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<div>
<Field
label="Address"
name="address"
component={InputText}
validate={validateNotEmpty}
/>
</div>
<button type="submit">Submit</button>
</form>
)
export default reduxForm({
form: 'AddLoc'
})(AddLoc)
But while typing inside the input text it keeps giving the following error/warning:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property `nativeEvent` on a released/nullified synthetic event. This is set to null. If you must keep the original synthetic event around, use event.persist().
While typing inside the input text automatically outputs [object Object]. Please check the image above. Could anyone please let me know what is causing the error.
Thanks
The reduxForm works only with pure DOM <input />. Internally it clones the elements search the children and then attaches the onChange dynamically. So it will not work with the Input and the NumericTextBox from the #progress/kendo-react-inputs package. This statement is based on the official kendo documentation about integrating with the redux-form.
The same author of the redux-form have fork of it called react-final-form which could be used on any component that have Value and onChange props. By our tests it works with the components from #progress/kendo-react-inputs and #progress/kendo-react-dropdowns packages. It looks kendo already have an example using final-form in their integration section.

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
}}
...

Enter key event handler on react-bootstrap Input component

I have an Input component with a button (buttonAfter property), I set an onClick handler associated to the button and so user can type some text and clic the button to fire the right action.
However, I would like user to be able to press [Enter] key (keycode 13) to achieve the same effect as clicking on the button, just to make the UI easier to use.
I could not find a way to do it, of course I tried onKeydown to register an handler for key down event but it is just ignored.
I think this question is related to React itself instead of react-bootstrap.
Look at this for some basics about React event system: https://facebook.github.io/react/docs/events.html
When you use onKeyDown, onKeyPress or onKeyUp React will pass to your handler an instance of say "target" object with the following properties:
boolean altKey
number charCode
... (for all see link above)
So you can do something like this:
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { Input } from 'react-bootstrap';
class TestInput extends React.Component {
handleKeyPress(target) {
if(target.charCode==13){
alert('Enter clicked!!!');
}
}
render() {
return (
<Input type="text" onKeyPress={this.handleKeyPress} />
);
}
}
ReactDOM.render(<TestInput />, document.getElementById('app'));
I tested above code and it works. I hope this is helpful for you.
The question can also be related to React-bootstrap.
React-bootstrap also has a way to handle instance when ever a button or enter key or any form element is pressed.
The below code explains how to handle an instance when enterkey is pressed without the involvement of React Handlers.(and that makes it cool)
import React from "react";
import ReactDOM from "react-dom";
import { FormGroup, FormControl } from "react-bootstrap";
class TestInput extends Component {
search() {
console.log("Enter Button Pressed");
}
render() {
return (
<FormGroup>
<InputGroup>
<FormControl
placeholder="Press Enter"
type="input"
onKeyPress={event => {
if (event.key === "Enter") {
this.search();
}
}}
/>
</InputGroup>
</FormGroup>
);
}
}
React Bootstrap does not support Input form element anymore.
Instead it introduced below items at your disposal
The FormGroup component wraps a form control with proper spacing, along with support for a label, help text, and validation state.
Wrap your form control in an InputGroup, then use for normal add-ons and for button add-ons.
The FormControl component renders a form control with Bootstrap styling.
References:
https://react-bootstrap.github.io/components.html#forms
https://react-bootstrap.github.io/components.html#forms-input-groups
The right way to do it in a form is the same like in regular JavaScript:
Don't use onClick on a button but use type="submit"
The form should be wrapped with <form onSubmit={handler}>
Handler should prevent page reload handler = (event) => event.preventDefault(); processForm()
Now both the button and pressing Enter on any field will call handler
Piece of functional component doing this
function register(event) {
event.preventDefault()
distpach(authActionCreator.register(username, email, password));
}
return (
<Card>
<form onSubmit={register}>
<Card.Body>
<Card.Title as="h4">Register</Card.Title>
<FormGroup controlId="username">
<FormLabel>Username</FormLabel>
<FormControl type="text" label="Username" placeholder="Username" onChange={handleChange} />
</FormGroup>
<FormGroup controlId="email">
<FormLabel>Email</FormLabel>
<FormControl type="email" label="Email" placeholder="Email" onChange={handleChange} />
</FormGroup>
<FormGroup controlId="password">
<FormLabel>Password</FormLabel>
<FormControl type="password" label="Password" placeholder="Password" onChange={handleChange} />
</FormGroup>
<ButtonToolbar>
<Button variant="primary" type="submit">Register</Button>
</ButtonToolbar>
</Card.Body>
</form>
</Card>
);
A somewhat abbreviated version of the already suggested solutions is:
import React from 'react';
import ReactDOM from 'react-dom';
import { Input } from 'react-bootstrap';
const TestInput = () => {
const handleSubmit = () => {
/* handle form submit here */
}
return (
<Input type="text" onKeyPress={event => event.key === "Enter" && handleSubmit()} />
);
}
ReactDOM.render(<TestInput />, document.getElementById('app'));
onKeyPress={event => event.key === "Enter" && handleSubmit()} will ensure handleSubmit is called when the Enter key is pressed.
Uncaught TypeError: Cannot read property 'charCode' of undefined
You have to use:
handleKeyPress(target) {
if (target.key === 'Enter') {
alert('Enter clicked!!!');
}
}

Resources