ReactJS: Conditional rendering submits form data before handleSubmit function - reactjs

I have a form that upon completion renders a button with form data.
The form takes two inputs: 1. Title (text rendered in button) & 2.) URL for the button.
The form works with the conditional statement if I paste in a URL. However if I begin manually typing a URL, it generates the button based on the first character I type because the string is no longer empty.
export default class URLButton extends Component {
constructor(props) {
super(props)
this.state = {
links: [],
url: '',
title: ''
}
}
// onChange
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault()
}
render() {
if (this.state.url === "") {
return (
<>
<form onClick={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placeholder="your-link.com"
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button type="submit">Submit</button>
</>
)
} else {
return (
<>
<div>
{this.state.title}
</div >
</>
)
}
}
}
Since the onChange and onSubmit function works, I've narrowed it down to the conditional statement if (this.state.url === "") {... I've tried setting it to null and false instead of an empty string but the form doesn't render if I try those statements.

Yeah, you're right, your problem is that, when you typed something, the url state is not empty anymore, you'll have to validate that the url is valid in order to submit the form, I've made a StackBlitz with the solution of the problem, I hope this helps.

If you want to finish typing and than generate the button
you can change your onChange to onBlur as
<input
name="url"
type="url"
placeholder="your-link.com"
onBlur={e => this.setState({ url: e.target.value })}
/>
Now when you type out and blur out of input than button will be gernerated
Hope it helps

First of all you should pass yours input states to input:
...
<input
name="url"
type="url"
value={this.state.url} // here
placeholder="your-link.com"
onChange={e => this.setState({ url: e.target.value })}
/>
...
By this edit onChange would pass to set state not only character you've just wrote, but all of previous charecters plus last one.
Then look at your code here:
...
if (this.state.url === "")
...
It would be false right after the FISRT charecter in state.url setted.
If you need to check for correct URL you should use regexp in if condition, to check if state.url looks like correct url by your expectations and ONLY after that render the other part of component.

Related

How do I get input from user by using <button> and <input> in React?

I want to create a form by using <input> and <button> like so:
I'm not sure how to pass the value I get from the text input field into a couple of functions on the frontend when I press the button "Send now". How do I make a <form onSubmit={}> without using forms, rather just an input field and a button?
This is what I've tried so far and it's not working, I'm not sure how to get the input value and pass it into the function like this this.articleOnSubmit(*user input*). And also is the way i incorporated onChange={this.articleOnChange} correct? Here is my code:
const Input = ({ placeholder, name, type, value }) => (
<input
placeholder={placeholder}
type={type}
step="0.0001"
value={value}
name={value}
/>
);
class Publish extends Component {
constructor(props) {
super(props);
this.state = {
articleTitle: '',
};
}
articleOnChange = (event) => {
let title = event.target.value;
this.setState({ articleTitle: title.toLowerCase() });
}
articleOnSubmit = (event) => {
if (this.state.articleTitle) {
console.log(this.state.articleTitle);
this.hash(this.state.articleTitle)
.then(hex => {console.log(hex); return hex;})
.then(hex => this.addArticleHash(hex));
event.preventDefault();
}
return (
<Input placeholder="Article Name" name="article" type="text" onChange={this.articleOnChange} />
<div/>
{false
? (<Loader />)
: (
<button
type="submit"
onClick={this.articleOnSubmit(Input.name)}
>
Send now
</button>
)}
</div>
);
}
To make it work you have to fix 2 issues here:
Since Input is a component, you have to get in its props the onChange prop you pass to it, otherwise it won't work.
const Input = ({ placeholder, name, type, value, onChange }) => (
<input
onChange={onChange}
placeholder={placeholder}
type={type}
step="0.0001"
value={value}
name={value}
/>
);
React onClick should be a function. Not a call. A function. What you did here was onClick={this.articleOnSubmit(Input.name)} - which is a call.
The solution is to change it into a function () => this.articleOnSubmit(Input.name)

multiple input elements in form - React

It's a simple form which updates the state object onChange and displays that state object when submitted. I was not able to get it to work when there are multiple input elements.
Can anyone tell me what's wrong in this code?
onSubmit works when there's only one input element, but not when there are multiple!
class ReactForm extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.validate = this.validate.bind(this);
this.state = {
name: "",
email: ""
};
}
handleChange(event) {
event.preventDefault();
const name = event.target.name;
const value = event.target.value;
this.setState({
[name]: value
});
}
validate(event) {
event.preventDefault();
console.log(this.state);
}
render() {
return (
<div>
<form onSubmit={this.validate}>
<div>
<input
type="text"
name="name"
value={this.state.name}
onChange={this.handleChange}
/>
<input
type="email"
name="email"
value={this.state.email}
onChange={this.handleChange}
/>
</div>
</form>
</div>
);
}
}
ReactDOM.render(
<ReactForm />,
document.getElementById("root")
);
You need to have a submit button if you have more than 1 input, you can add a hidden one if you want:
<input type="submit" hidden />
Here's a codesandbox: https://codesandbox.io/s/suspicious-almeida-e3f00
And here is the explanation in detail: Why does a FORM with one text INPUT submit on enter while one with two text INPUTs does not?
I really liked the approach of tudor.
Here is a different approach that can remove the state handling as well. But this may require polyfill for IE and Safari. You can use FormData to access the form values.
new FormData(e.target);
Here is the working sandbox link: https://codesandbox.io/s/long-wind-ybl1w
Hope this helps!
Please add an element input and button. Button should have type="submit" for submitting!
It will work!

ReactJS: OnChange handler auto submitting data before onClick

I'm still relatively new to React/Javascript & working with its functions. I created a component that takes user input and renders a button that allows a user to link to an outside URL.
The button title is created by the user and then the URL is added.
However, when a url is pasted or I begin typing it, the onChange handler automatically creates the button without using the onSubmit function. So if I begin typing a paste a url (even if the data is wrong), the onChange event takes whatever I've input without allowing me to click "submit first".
I'm following this tutorial as a guideline for creating my onChange/onSubmit functions: https://www.youtube.com/watch?v=qH4pJISKeoI&t=304s. His demo does not have the same issue and his input fields solve a different problem.
onChange & onSubmit Functions
this.state = {
links: [],
url: '',
title: ''
}
}
onChange = (e) => {
e.preventDefault(e)
this.setState({
[e.target.name]: e.target.value
})
}
// onSubmit
onSubmit = e => {
e.preventDefault(e)
}
...
render() {
if (this.state.url === '') {
return (
<>
<form>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.setState({ title: e.target.value })}
/>
<input
name="url"
type="url"
placholder="your-link.com"
onClick={(e) => { e.stopPropagation() }}
disabled={this.state.title === ''}
onChange={e => this.setState({ url: e.target.value })}
/>
<br />
</form>
<button onClick={this.onSubmit}>Submit</button>
</>
)
} else {
return (
<>
<div>
<p>{this.state.title}</p>
</div >
</>
)
}
}
}
I've tried separating the onChange events using onChange={this.title} and {this.url} , disabling the URL field until the title is added, and adding onClick={(e) => { e.stopPropagation() }} in the url input field to prevent autosubmission as shown in the code above.
Any help understanding what causes this problem would be appreciated.
Let's check what is happening:
We have onChange on input with url.
When anything is being changed in this input field,
On change is called and it triggers render method.
In render if (this.state.url === '') { this is no longer true so it creates link without needing to submit.
Prevent default will not work while you have params in it:
e.preventDefault(e)
// probably this may be a typo instead?
// it's preventing you to go further line due to error.
Remove e param and it should be fine:
e.preventDefault()
<form onSubmit={this.onSubmit}>
<input
name="title"
type="text"
placeholder="add button text"
onChange={e => this.onChange(e)}
/>
<input
name="url"
type="url"
placholder="your-link.com"
disabled={this.state.title === ''}
onChange={e => this.onChange(e)}
/>
<br />
<button type="submit">Submit</button>
</form>
do changes like this and check

Change the input type on-focus in JSX doesn't work

I have a text field which has the placeholder "Dates From". what I wanna do is to change It's input box type to a date type on the focus event. But
but the below mentioned solution doesn't work with JSX.
<input placeholder="Date" type="text" onFocus="(this.type='date')" id="date">
How to make this thing work on ReactJs or How to achieve the same goal?
Using an anonymous function should work, with e.target:
<input placeholder="Date" type="text" onFocus={(e) => e.target.type = 'date'} id="date" />
You can see it in action here.
Try this code
handleFocus(event) {
event.target.type = 'date';
}
render() {
return (
<label>
Name:
<input type="text" placeholder="please Enter date" onFocus={this.handleFocus.bind()} />
</label>
);
}
Perhaps you could take a state based approach to this, where you would update the state of the component to track the type of the input field when onFocus occours by doing something like this:
onFocus={ () => this.setState({ typeOfFocused : 'date' }) }
Doing this would trigger a re-render which in turn would cause the input element's type to switch to date via the following:
render() {
// Extract typeOfFocused from state
const { typeOfFocused } = this.state
// Render input type with typeOfFocused if present, or as text by default
return (<input placeholder="Date"
type={ typeOfFocused || 'text' }
onFocus={ () => this.setState({ typeOfFocused : 'date' }) }
onBlur={ () => this.setState({ typeOfFocused : '' }) }
id="date">)
}
Here's a working sample

How to fetch input from text box and print in React?

I am new to React trying to write a very simple project that fetches input of both text boxes and when button is clicked, the 'data' in text boxes is printed on paragraph.
How do I fetch text's in input text boxes when button is clicked?
class Input extends Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text">
</input>
<input
style = {textStyle}
placeholder="tag"
type="text">
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
You can add onChange event handler in each input.
class Input extends Component {
state = {
tagged: false,
message: '',
input1: '',
input2: '',
}
handleClick(e) {
// access input values in the state
console.log(this.state) // {tagged: true, input1: 'text', input2: 'text2'}
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
handleInputChange = (e, name) => {
this.setState({
[name]: e.target.value
})
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text"
onChange={(e) => this.handleInputChange(e, 'input1')}
>
</input>
<input
style = {textStyle}
placeholder="tag"
type="text"
onChange={(e) => this.handleInputChange(e, 'input2')}
>
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
There are two different ways of working with react inputs - you can either make them controlled or uncontrolled. When you say fetch text from inputs, this is called uncontrolled components and means that form data is handled by the DOM itself and not by react.
This is achieved by using ref and literally getting a reference to your input and fetching its value when you need it. you can read more about this approach in react docs.
According to react docs, it is recommended using controlled components
In most cases, we recommend using controlled
components to implement forms. In a controlled
component, form data is handled by a React component.
This means that you don’t use references to the inputs and instead handle changes of your inputs with an event handler and update state with the new values that the user has entered into the input fields. According to react docs here is how react handles form with controlled components:
the React component that
renders a form also controls what happens in that form on subsequent
user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
In your case you can do this if you choose controlled inputs:
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
tagged: false,
firstInput: '',
secondInput: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleClick(e) {
this.setState({ tagged: true });
e.preventDefault();
console.log('The link was clicked.');
}
render() {
const { firstInput, secondInput, tagged } = this.state;
return (
<div id="id">
{tagged && <p>{firstInput} {secondInput}</p> }
<input
value={firstInput}
name="firstInput"
onChange={this.handleChange}
type="text" />
<input
value={secondInput}
name="secondInput"
onChange={this.handleChange}
type="text" />
<button onClick={(e) => this.handleClick(e)}>
{tagged ? 'Tagged' : 'Tag '}
</button>
</div>
)
}
}
Here you put the inputs' values on state and update state when the user writes something in your inputs. If you however want to use uncontrolled components you can do it this way:
class UncontrolledInput extends React.Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
e.preventDefault();
const messageFromInputs = `${this.firstInput.value} ${this.secondInput.value}`;
this.setState({ tagged: true, message: messageFromInputs });
}
render() {
return (
<div id="id">
<p>{this.state.message}</p>
<input ref={(input) => this.firstInput = input} type="text" />
<input ref={(input) => this.secondInput = input} type="text" />
<button onClick={(e) => this.handleClick(e)}>
{this.state.tagged ? 'Tagged' : 'Tag '}
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still'}
</p>
</div>
)
}
}
Here you will actually fetch values from your inputs when the button is clicked.
I made a working example with both ways on codesandbox.

Resources