Two forms on the same level are submitted in react app - javascript

I have react app with with complex component layout with multiple forms.
I know that placing one form inside another is not allowed. But I have a component which renders a form and must be placed inside my form. To prevent forms be rendered one inside another I use react portal.
But when I try to submit form rendered with portal, first form is also submitted that is unexpected. Looks like I miss something important.
How to prevent first form submit when submitting the second?
Thank you
Simplified example is here
import { createPortal } from "react-dom";
const Portal = ({ children, elm }) => createPortal(children, elm);
export default function App() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 1");
}}
>
First form <input type="text" value="1" />
<Portal elm={document.querySelector("body")}>
Second form{" "}
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 2");
}}
>
<input type="text" value="2" />
<input type="submit" value="submit 2" />
</form>
</Portal>
</form>
</div>
);
}

I had the same problem, as #EisaRezaei said in the first comment, using e.stopPropagation() in the form inside the portal, and submit type buttons, everything worked fine

Related

React onClick not rendering

I am currently building my first, very basic react app. There is a button that triggers an API call using onClick. However, react just doesn't seem to be rendering the onclick to the DOM.
Within index.js I have, among other, the following content:
<NumberSelect
label={"Can I get your number?"}
id_input1={"number-input"}
placeholder={42}
onClickEvent={RequestFact}
cta={"Get Fact"}
/>
This is my NumberSelect.js:
import Button from "./Button.js";
import InputNumber from "./InputNumber.js";
import "./NumberSelect.css";
const NumberSelect = (props) => {
return (
<form id="number-select">
<label htmlFor={props.id_input1}>{props.label}</label>
<InputNumber
placeholder={props.placeholder}
id_input1={props.id_input1}
/>
<Button
cta={props.cta}
class={"btn mt-10"}
href={props.href}
onClickEvent={props.onClickEvent}
/>
</form>
);
};
export default NumberSelect;
And this is the entire Button.js
import "./Button.css";
const Button = (props) => {
return (
<a
id={props.id}
className={props.class}
href={props.href}
onClick={props.onClickEvent}
>
{props.cta}
</a>
);
};
export default Button;
What I would expect the HTML to look like is this (note: is defined in a separate Component):
<form id="number-select">
<label for="number-input">Can I get your number?</label
><input
type="text"
inputmode="numeric"
pattern="[0-9]*"
id="number-input"
placeholder="42"
spellcheck="false"
data-ms-editor="true"
/><a class="btn mt-10" onclick="RequestFact()">Get Fact</a>
</form>
But this is what the HTML actually looks like:
<form id="number-select">
<label for="number-input">Can I get your number?</label
><input
type="text"
inputmode="numeric"
pattern="[0-9]*"
id="number-input"
placeholder="42"
spellcheck="false"
data-ms-editor="true"
/><a class="btn mt-10">Get Fact</a>
</form>
Almost everything is the same, only the onclick="RequestFact() is missing.
Can anybody help me out? Do you need any other info?
Thanks for your help!
Edit: I tried to simplify the code a bit and not post everything here. But it seems I took away too much and it became unclear. Sorry for that. Above some additional code.
Info regarding the additional questions:
RequestFact ist located in index.js
Thanks for the tip regarding { for strings - will implement

vee-validate#4.x - how to manually validate field

While using
vee-validate#4.4.5
vue#3.1.4
I encountered following problem:
<Form #submit="onSubmit" :validation-schema="schema">
<div class="mb-3">
<label for="edit-email" class="form-label">E-mail</label>
<Field
id="edit-email"
class="form-control"
name="email"
type="text"
:validateOnInput="true"
/>
<ErrorMessage class="invalid-feedback" name="email" />
</div>
<button #click="checkEmail" type="button">Check e-mail address</button>
<!-- non-important part of the form -->
</Form>
I'd like to manually validate <Field /> when the button is clicked (error message should appear) and then I want to use the field's value to perform another action.
I wrote following code:
import { useFieldValue } from 'vee-validate';
// setup
setup() {
const schema = object({
email: string().required().email().label("e-mail"),
});
function verifyEmail(v) {
const emailValue = useFieldValue("email");
console.log(emailValue); // empty ComputedRefImpl
}
return {
schema,
verifyEmail,
};
},
}
And this doesn't work.
emailValue is returned as ComputedRefImpl with an undefined value.
I guess I'm mixing Components & Composition API flavors of vee-validate. But still don't know how to resolve this issue.
Created sandbox with this: https://codesandbox.io/s/vue3-vee-validate-form-field-forked-xqtdg?file=/src/App.vue
Any help will be much appreciated!
According to vee-validate's author:
https://github.com/logaretm/vee-validate/issues/3371#issuecomment-872969383
the useFieldValue only works as a child of a useForm or useField.
So it doesn't work when <Field /> component is used.

Form is not submitting from an outer button using react

class Index extends React.Component {
state = {isLoading: false}
onSubmit = (event) => {
console.log('here we go');
event.preventDefault();
// this.checkEmailExistance();
};
render() {
return (
<>
<form id="myForm" onSubmit={this.onSubmit} noValidate>
<CredentialsInputs />
</form>
<footer>
<Button type="submit" form="myForm" isPrimary isDisabled={!isValid}>
Continue
</Button>
</footer>
</>
)}
}
onSubmit function is not invoked
Note: the props (type and form) was passed well and check using the console elements
Is the problem something related to react?
You have written you submit button outside of form. You should move your submit button inside of form,
<form id="myForm" onSubmit={this.onSubmit} noValidate>
<CredentialsInputs />
<footer>
<Button type="submit" form="myForm" isPrimary isDisabled={!isValid}>
Continue
</Button>
</footer>
</form>
If you don't want to move footer inside of form, then you should have onClick on your Button
<form id="myForm" noValidate>
<CredentialsInputs />
</form>
<footer>
<Button type="submit" form="myForm" isPrimary isDisabled={!isValid} onClick={this.onSubmit}>
Continue
</Button>
</footer>
Put the button inside form. it will work.
You should always include a button element inside form to trigger onSubmit method automatic, Else you can call the method manually with onClick event of the button.
You can set a ref to the form, and then in the "Button onClick", you do ref.submit().
In that situation, you set an id to the form... So, if you want to make a really really ugly implementation, you could do something like document.getElementByid('myForm').submit()
If you want to do something better, you should do something like...
<form ref={ref => this.formRef = ref} ...
<button onClick={() => this.formRef.submit()}
Still... not super beautiful. I would recommend Hooks + useRef.

Call functional Component on button click in react

I have a functional component inside which I have a button. I want to call a functional component when that button is clicked.
When we click Submit button the Preview button shows up and when the user clicks the preview button then Preview functional component is called.
const Form =(props)=>{
handlePreview=(e)=>{
e.preventDefault();
return <Preview/>
}
return(
<input name="email" type="text"/>
<button type="submit" onClick={props.handleSubmit}>Submit</button><br/>
{props.render&&
<button type="submit" onClick={handlePreview}>Preview</button>
}
)
}
When I click the Submit button the Preview Button shows up but when I click the Preview Button it doesnt navigate to the <Preview> functional component
To render component you should return it from function Form. If you return any component from event handler it will be ignored.
So to show <Preview/> component you should create local state. In functional components it can be done with React Hooks like below
const Form =(props)=>{
const [isPreviewShown, setPreviewShown] = useState(false);
handlePreview=(e)=>{
e.preventDefault();
setPreviewShown(true); // Here we change state
}
return(
<input name="email" type="text"/>
<button type="submit" onClick={props.handleSubmit}>Submit</button><br/>
{props.render&&
<button type="submit" onClick={handlePreview}>Preview</button>
}
{isPreviewShown && <Preview/>}
)
}

React onSubmit handler on a form won't be called if I have a onBlur handler on an input? (Only happens when using Webstorm js debugger)

A simplified version of my code. If I click the submit button by itself, the onSubmit handler is called.
If I click submit right after editing the input box, the onSubmit handler won't be called. Is this how React is designed? How to call onSubmit in this case.
const EmailInput = React.createClass({
handleOnBlur(event){
console.log('onBlur')
},
render(){
return <div className="form-group">
<label htmlFor={this.props.name}>Email</label>
<input className="form-control"
type='text'
name={this.props.name}
onBlur={this.handleOnBlur}
value={this.state.val}
/>
</div>
}
})
const Form = React.createClass({
onSubmit(e){
console.log('onSubmit')
},
render(){
return <form onSubmit={this.onSubmit}>{this.props.children}</form>
}
})
ReactDOM.render(<Form>
<EmailInput />
<button type="submit" className="btn btn-primary" >Share</button>
</Form>, mountNode)
Based on Dhaval's answer, I found the reason of this.
When I use Webstorm js debugger, the submit event won't fire. When I just use the browser by itself. It works out fine.
This is so weird that I doubt I'm doing something wrong. Can someone try it on the Webstorm.
Please check the below mentioned Plunkar when I click on Share button it will called onSubmit
// Code goes here
var EmailInput = React.createClass({
handleOnBlur(event){
console.log('onBlur')
},
getInitialState:function()
{
return{
val:''
}
},
render(){
return <div className="form-group">
<label htmlFor={this.props.name}>Email</label>
<input className="form-control"
type='text'
name={this.props.name}
onBlur={this.handleOnBlur}
value={this.state.val}
/>
</div>
}
});
var Form = React.createClass({
onSubmit(e){
console.log('onSubmit')
},
render(){
return <form onSubmit={this.onSubmit}>{this.props.children}</form>
}
});
React.render(<Form><EmailInput /><button type="submit" className="btn btn-primary" >Share</button></Form>,
document.getElementById('example')
);
Demo

Categories

Resources