I have FormControl for password input with icon that toggles the mask, so u cant see the characters you are inputting. But whenever I toggle this mask I also want to re-focus the input field.
<FormGroup
className="input-text input-text--password"
controlId={id}
validationState={submitFailed && touched && error ? 'error' : validationState}
>
<FormControl
{...input}
disabled={disabled}
className="input-text__input"
autoFocus={autoFocus}
type={maskEnabled ? 'password' : 'input'}
onChange={this.handleFormControlChange}
maxLength={maxLength}
ref = { ref => this.textInput = ref }
/>
<div
className={'input-text__button ' + (maskEnabled ? 'mask-enabled' : 'mask-disabled')}
onClick={this.handleToggleInputMode}
/>
... I use this method to focus:
handleToggleInputMode() {
let newMaskEnabled = !this.state.maskEnabled;
this.setState({maskEnabled: newMaskEnabled});
this.textInput.focus();
}
But i keep getting error
Uncaught TypeError: this.textInput.focus is not a function
So i tried to put it in ComponentDidMount but then the whole componend stopped responding (didnt accept any char I typed in).
What am i missing?
Please check working demo
class App extends React.Component {
componentDidMount() {
this.textInput.focus();
}
render() {
return (
<div>
<div>
<input
defaultValue="It will not focus"
/>
</div>
<div>
<input
ref={(input) => { this.textInput = input; }}
defaultValue="with focus"
/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<div id="app"></div>
Edit
for FormControl you should use inputRef as per documentation
<FormControl inputRef={ref => { this.input = ref; }} />
According to the current docs (https://reactjs.org/docs/refs-and-the-dom.html), use:
this.textInput.current.focus();
So it should reference to the current to get the DOM node.
Related
I already built the form in React and it shows the input fields in red borders that'll change to regular borders once someone types it in. I used this example from this React form article link So everything is working except I wanted to add the error message under the input field that displays "Please fill in the blank field" that will disappear once someone starts typing in the field. How do I do this?
Here's my code in Form.js:
import React, { Component } from 'react';
import FormField from './FormFieldBox';
function validate(name, isin) {
// true means invalid, so our conditions got reversed
return {
name: name.length === 0,
isin: isin.length === 0
};
}
export default class PopupForm extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
isin: '',
country: '',
errormessage: ''
}
}
updateInput = (e) =>{
this.setState({[e.target.name]: e.target.value})
}
closePopupSubmit = (e) => {
if (!this.canBeSubmitted()) {
e.preventDefault();
}
let security = { //1.gather security data from form submit
name: this.state.name,
isin: this.state.isin,
country: this.state.country
}
this.props.submitPopup(security); //2.closePopup function, add security data
}
canBeSubmitted() {
const errors = validate(this.state.name, this.state.isin);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return !isDisabled;
}
cancelPopupSubmit = (e) => {
e.preventDefault()
this.props.cancelPopup();
}
render() {
const errors = validate(this.state.name, this.state.isin);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return (
<div className='popup'>
<div className='popup-inner'>
<form onSubmit={this.closePopupSubmit}>
<FormField onChange={this.updateInput} className={errors.name ? "input error" : "input"} label="Name" type="text" name="name" value={this.state.name} />
<FormField onChange={this.updateInput} className={errors.isin ? "input error" : "input"} label="ISIN" type="text" name="isin" value={this.state.isin} />
<FormField onChange={this.updateInput} label="Country" type="text" name="country" value={this.state.country} />
<button type="button" onClick={this.cancelPopupSubmit} className="button">Cancel</button>
<button type="submit" className="button" disabled={isDisabled}>Submit</button>
</form>
</div>
</div>
)
}
}
And my component FormField.js
import React from "react";
const FormBox = props => {
return (
<div className="field">
<label className="label">{props.label}</label>
<div className="control">
<input onChange={props.onChange}
className={props.className}
type={props.type}
name={props.name}
value={props.value}
placeholder={props.placeholder} />
{/* {props.errormessage} */}
</div>
</div>
)
}
export default FormBox;
const FormBox = props => {
return (
<div className="field">
<label className="label">{props.label}</label>
<div className="control">
<input onChange={props.onChange}
className={props.className}
type={props.type}
name={props.name}
value={props.value}
placeholder={props.placeholder} />
</div>
{Boolean(props.value.length) || (
<div className="err-msg">
Please fill in the blank field
</div>
)}
</div>
)
}
There are two ways you can achieve this
First : oninvalid attribute in HTML5 and calling a custom function on that.
Second : along with each element name object in state have a length attribute. In validation function you can check for the length and throw a custom error that you want to display.
In below image screenshot I make fields mandatory so click on register button If any fields then that empty field I want to highlight with red border in React how it is possible ?
(https://blueprintjs.com/docs/#core/components/text-inputs)
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
email: '',
password: '',
};
this.handleChange = this.handleChange.bind(this);
this.registerForm = this.registerForm.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
registerForm(){
if(this.state.firstName.trim() && this.state.lastName.trim() &&
this.state.email && this.state.password){
console.log("registration successfully..!!");
}else{
console.log("all * marked fields mandatory");
}
}
render() {
return (
<div>
<h2>Fill Registration Details..!!</h2>
<InputGroup placeholder="Enter First Name...*"
name="firstName" value={this.state.firstName} onChange={this.handleChange}/>
<InputGroup placeholder="Enter Last Name...*" name="lastName"
value={this.state.lastName} onChange={this.handleChange}/>
<InputGroup placeholder="Enter your email...*" name="email"
value={this.state.email} onChange={this.handleChange}/>
<InputGroup placeholder="Enter your password...*"name="password"
value={this.state.password} onChange={this.handleChange}/>
<Button intent="Primary" onClick={this.registerForm}>Register</Button>
</div>
)
}
One solution, as #Saraband stated, is to modify your node's class name depending on whether or not your input field contains an error:
<InputGroup
placeholder="Enter your password...*"
name="password"
className={this.state.password.length ? '' : 'error'}
value={this.state.password}
onChange={this.handleChange}
/>
You can then use it with the following CSS that will show a red border (for example) :
.error input
{
border-bottom: 1px solid #eb516d;
}
Another way is to use the native required attribute of the input tag, but this method is hard to customize :
<input type='text' required/>
https://www.w3schools.com/tags/att_input_required.asp
For those who might be looking for a solution to this question, the solution below will only validate once the submit button is clicked. You can add a custom css class to style the input tag.
import React, { useState } from 'react';
const ValidateInput = () => {
// set isSubmitting to false by default
// this will make sure error class is not added by default
const [isSubmitting, setIsSubmitting] = useState(false);
const [inputValue, setInputValue] = useState('');
const submitHandler = (event) => {
event.preventDefault();
// this will trigger the error validation
setIsSubmitting(true);
// add the rest of the logic here
};
return (
<form onSubmit={submitHandler}>
<input
value={inputValue}
onChange={(event) => {
setInputValue(event.target.value);
}}
className={isSubmitting && !inputValue ? 'error' : undefined}
/>
<button type="submit">Submit</button>
</form>
);
};
export default ValidateInput;
You can create a CSS class - let's say .red-border and add it to your input whenever their value is empty (your component need to be able to use this className prop and pass it down to your <input /> native component)
<InputGroup
placeholder="Enter your password...*"
name="password"
className={!this.state.password.length ? '' : 'red-border'}
value={this.state.password}
onChange={this.handleChange}
/>
Although it can be best to keep this sort of thing inside your InputGroup component thus confining the logic of your component to a single file
class InputGroup extends React.Component {
// code
render () {
return(
// code
<input
value={this.props.value}
className={!this.state.password.length ? '' : 'red-border'}
/>
);
}
};
I am working on a project and i want to display a hidden <div> below another <div> element using an event handler but when i click the icon that is meant to display the div, the whole page becomes blank
This is image I want:
This is what i get
I have tried to check through the internet for some places where i could get the solution. Well i found something similar to what i had done but the error still happens for me.
class PostItTeaser extends Component {
state = {
postIt: false,
moreIt: false,
}
togglePostIt = e => {
e ? e.preventDefault() : null
this.setState({ postIt: !this.state.postIt })
}
_toggle = e => {
e ? e.preventDefault() : null
this.setState({
moreIt: !this.state.moreIt,
})
}
Child = () => <div className="modal">Hello, World!</div>
render() {
let { postIt } = this.state
let { moreIt } = this.state
let {
type,
group,
disabled,
session: { id, username },
} = this.props
return (
<div>
<div
className="post_it inst"
style={{ marginBottom: type == 'group' && 10 }}
>
<img src={`/users/${id}/avatar.jpg`} alt="Your avatar" />
<div className="post_teaser">
<span
className="p_whats_new"
onClick={disabled ? null : this.togglePostIt}
>
What's new with you, #{username}? #cool
</span>
<span className="m_m_exp" data-tip="More" onClick={this._toggle}>
<MaterialIcon icon="expand_more" />
</span>
</div>
</div>
{moreIt && <Child />}
{postIt && (
<PostIt back={this.togglePostIt} type={type} group={group} />
)}
</div>
)
}
}
From skimming through the code I believe you need to bind the scope, since the function you're calling is using this.setState, it needs this to be the react component, not the event you're listening to:
onClick={this._toggle.bind(this)}
You can also bind the functions scope in the constructor. Or, a less memory performant & ugly way:
onClick={() => { this._toggle(); } }
I made a stateless component with an internal variable to reference an input, as below. This is working fine.
const MyStatelessComp = ({ team, teamProgress, onSet, editing, enableEdit }) => {
let input
return (
<div>
<div className="team__goal-target_header" >Team's Savings Target</div>
<div className="team__goal-target_value" >
M$
<input
ref={ el => input = el }
style={{width: '75px', border: 'none'}}
onChange={() => onSet({teamId: team.id, goalValue: parseInt(input.value, 10) || 0}) }
/>
<div
ref={ el => input }
style={{
display: !input || (!isNaN(parseFloat(input.value)) && isFinite(input.value)) ? 'none' : 'block'
}}
>Must be numeric</div>
</div>
</div>
)
}
I want to validate input and display a notification Must be numeric is the anything that cannot be converted to a number is entered into my input field. That is not working however. How do I make input in the context of the "warning div" reference the value of the input?
Realize that this is not an unorthodox way to working with stateless components, but it would save me lots of pain.
Thank you.
Why use a stateless component when he can be a simple statefull component ?
class App extends Component {
constructor(props) {
super(props);
this.state = {
value: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
render() {
const isNumber = !isNaN(this.state.value);
return (
<div>
<div className="team__goal-target_header">Team's Savings Target</div>
<div className="team__goal-target_value">
M$
<input
style={{ width: "75px", border: "none" }}
onChange={this.handleChange}
value={this.state.value}
/>
{isNumber ? "" : <div>Must be numeric</div>}
</div>
</div>
);
}
}
You can also toggle the div content or create a new alert component and toggle this component.
I am trying to use react-dates with redux-form. Did a render thing for it. I have handled text input and select fields pretty much the same way. Those are working fine.
Getting a funky error on either DateRangePicker or even SingleDatePicker, which I cannot make sense of. Any ideas/suggestions are greatly appreciated.
Did a render component as:
const renderDateRangePicker = ({
input,
focusedInput,
onFocusChange,
startDatePlaceholderText,
endDatePlaceholderText
}) => (
<DateRangePicker
onDatesChange={(start, end) => input.onChange(start, end)}
onFocusChange={onFocusChange}
startDatePlaceholderText={startDatePlaceholderText}
endDatePlaceholderText={endDatePlaceholderText}
focusedInput={focusedInput}
startDate={(input.value && input.value.startDate) || null}
startDateId="startDateId"
endDateId="endDateId"
endDate={(input.value && input.value.endDate) || null}
minimumNights={0}
/>
)
My class is just a form as:
class ActivityForm extends Component {
// values: ['startDate', 'endDate']
state = {
focusedInput: null
}
onFocusChange(focusedInput) {
this.setState({ focusedInput });
}
render () {
const { focusedInput } = this.state
const { handleSubmit, teams } = this.props
return (
<form onSubmit={handleSubmit} className="activity__form">
<div className="activity__form_row">
<Field
name="name"
label="Activity name"
component={renderTextField}
margin="normal"
validate={[required]}
className="activity__form_field_name"
InputLabelProps={{
shrink: true,
}}
/>
<div className="activity__form_spacer"/>
<Field
name="daterange"
onFocusChange={this.onFocusChange}
focusedInput={focusedInput}
component={renderDateRangePicker}
/>
<div className="activity__form_spacer"/>
<Button className="activity__form_button" type="submit">Save</Button>
</div>
</form>
)
}
}
export default reduxForm({ form: 'activity' })(ActivityForm)
For some reason, DateRangePicker causes a strange error: Uncaught TypeError: Cannot read property 'createLTR' of undefined.
What am I missing?
I believe this error is caused by missing or misplaced import of the initialization of react-dates, you can take a look at the Initialize section in (https://github.com/airbnb/react-dates)
import 'react-dates/initialize';
It also looks like there is an update to DateRangePicker:
So include starteDateId and endDateId as props to the DateRangePicker component.
<DateRangePicker
startDateId="2" // PropTypes.string.isRequired,
endDateId="1" // PropTypes.string.isRequired,
startDate={this.props.filters.startDate}
endDate={this.props.filters.endDate}
onDatesChange={this.onDatesChange}
focusedInput={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
showClearDates={true}
numberOfMonths={1}
isOutsideRange={() => false}
/>
It worked for me.