form.submit callback not getting invoked - javascript

I'm using the react-bootstrap-typeahead module in one of my application. This is working fine, except in one case.
I'm not able to submit the form by pressing the ENTER key if there are no results.
ie;
if there are suggestions provided by react-bootstrap-typeahead, I'm able to select one of the options and submit the form. In this case, able to invoke the callback onSubmit.
if there are no suggestions provided by react-bootstrap-typeahead, not able to submit the form.
If I submit the form using form.submit() method onKeyDown event, the form will be submitted, however, the page gets refreshed instead of invoking callback, which results in complete out of my control result.
The desired result: I should be able to invoke onSubmit callback even if there is no suggestion provided by if there are suggestions provided by react-bootstrap-typeahead.
Here is my code.
<form ref={(form) => this.form = form} onSubmit={this.sendMessage}>
<Typeahead
id="rbt-example"
dropup={true}
ref={(typeahead) => this.typeahead = typeahead}
onChange={this.valueChanged}
onInputChange={this.updateQuery}
onBlur={(e) => this.updateQuery(e.target.value, e)}
onKeyDown={(e) => {
// Submit the form when the user hits enter.
if (e.keyCode === 13) {
this.form.submit();
}
}}
options={options}
placeholder="Type your queries here..."
renderMenu={(results, menuProps) => {
// Hide the menu when there are no results.
if (!results.length) {
return null;
}
return <TypeaheadMenu {...menuProps} options={results} />;
}}
/>
<button type="submit">Submit</button>
</form>

The issue is likely calling this.form.submit(), which handles the form submission in the DOM (instead of React), and as you say, takes it out of your control. It's refreshing the page because you don't have control over the event to call event.preventDefault().
Instead of this.form.submit, you should call this.sendMessage when the user presses enter. Presumably you're calling event.preventDefault in sendMessage, so you should pass the event through from onKeyDown:
onKeyDown={e => {
if (e.keyCode === 13) {
this.sendMessage(e);
}
}}
This way, you will be handling form submission the same whether in response to the user pressing the submit button or enter.

If you noticed the code in my question, I'm handling multiple events. Especially onChange and onKeyDown.
Couple of things we need to understand about react-bootstrap-typeahead is
onChange, react-bootstrap-typeahead will pass the selected object to callback whereas onKeyDown react-bootstrap-typeahead will pass the event, from which, I will get the value using event.target.value
onChange will be triggered only after onKeyDown. therefore, if we want to do some operation based on the selected object and that value to be used in onKeyDown callback will not work.
To overcome this situation, I used setTimeout also removed form element.
so my solution simply becomes
<Typeahead
id="rbt-example"
dropup={true}
ref={(typeahead) => this.typeahead = typeahead}
onChange={this.valueChanged}
onInputChange={this.updateQuery}
onBlur={(e) => this.updateQuery(e.target.value, e)}
onKeyDown={(e) => {
// Submit the form when the user hits enter.
if (e.keyCode === 13) {
if (this.timerid) {
clearTimeout(this.timerid);
}
this.timerid = setTimeout(
() => {
this.sendMessage();
},
300
);
}
}}
options={options}
placeholder="Type your queries here..."
renderMenu={(results, menuProps) => {
// Hide the menu when there are no results.
if (!results.length) {
return null;
}
return <TypeaheadMenu {...menuProps} options={results} />;
}}
/>
<button onClick={() => this.sendMessage() }>Send</button>
This way, I'm calling sendMessage method onKeyDown and on button click. I'm also able to make use of the selected option object.

Related

(React.js + Hooks) How to reset input field after button click?

What I want to do is have an input that a user can type into. Upon clicking a button, take that input and process it and perform some backend operations with the database connected to the input. I'm trying to accomplish this with a state hook: onBlur, save input into state. On button click, do two things: 1) take the state variable and pass it to the backend resolvers, and 2) clear the input field so it's empty, and only the placeholder text exists.
I have this code:
const [inputVal, setInputVal] = useState("");
updateInput = (e) => {
const val = e.target.value;
setInputVal(val);
}
sendData = async () => {
//handle async backend processing with inputVal
setInputVal("");
//rerender
}
<Button className="input-button" onClick={sendData}>Send Data</Button>
<input className="input-field" placeHolder="Input name." defaultValue={inputVal} onBlur=(updateInput)></input>
However, I have two issues.
On button click, I want to first updateInput, and then handle the button click, so it always uses the new value. However, it seems as if there are some issues with that, possibly due to the asynchronous nature of sendData?
While inputVal may be an empty String, for some reason, the value in the input box doesn't reset to nothing, it stays exactly as it was (although the internal data would still have inputVal = 0). And onBlur it reupdates the inputVal.
for a controlled state input the most common approach is to use onChange rather than onBlur. This would also avoid your conflicts with blur and click events. Also you would pass inputVal to value input's property.
const [inputVal, setInputVal] = useState("");
const updateInput = (e) => {
const val = e.target.value;
setInputVal(val);
}
const sendData = async () => {
//handle async backend processing with inputVal
setInputVal("");
//rerender
}
return (
<>
<button className="input-button" onClick={sendData}>Send Data</button>
<input className="input-field" onChange={updateInput} placeHolder="Input name." value={inputVal}/>
</>
);
First, change defaultValue to value={inputVal} since it's a controlled input.
Secondly, please elaborate on what issues you have in 1.

conditionally set data-toggle attributes in React js

I have a button (type='submit') inside a form that has an attribute (data-toggle='modal'). onclick the button triggers the modal immediately. But I want to validate the form first and then trigger the modal if all input field is validated.
so what I've tried. Below is the simplified version of the form.
*
<form onSubmit={this.handleSubmit}>
<button
data-toggle={this.state.validatedForm ? "modal" : ""}
data-target="#request_search_submit_popup_door_to_door"
type="submit"
className="search-button"
>
<span>
<i className="icofont-search-1"></i>
</span>
</button>
</form>
here I am initializing the state as below
this.state={
validatedForm:false
}
if all the input field is validated then only the handleSubmit method will be called. And in there I am changing the state to
handleSubmit =(event)=>{
event.preventDefault()
this.setState({validatedForm:true})
}
but for the first submit the button doesn't trigger the modal. I am assuming the data-toggle attribute is only checking the value of validatedForm once.Doesn't check the value of validatedForm again after the handleSubmit is called. How can I achieve the functionality without using jquery.
and point to be noted if I click on the button twice it works fine.
render() {
const conditionals = {};
if (this.state.validatedForm === "modal") {
conditionals['data-toggle'] = 'modal';
}
return <button data-target={"xxx"} { ...conditionals} />
}
I know it's not the cleanest solution. but I did a simple trick to get thing working for me. In handleSubmit method just click on the button again.
<form onSubmit={this.handleSubmit}>
<button
id="form-submit-button"
{...(this.state.validatedForm ?{'data-toggle': "modal"} : {})}
data-target="#request_search_submit_popup_door_to_door"
type="submit"
className="search-button"
>
<span>
<i className="icofont-search-1"></i>
</span>
</button>
</form>
handleSubmit = (event) => {
event.preventDefault();
this.setState({ validatedForm: true }, () => {
document.getElementById("form-submit-button").click();
});
}
In initial render this.state.validateFrom=false. so no data-toggle attribute is there on submit button. users clicks on the submit button if the form is not validated handleSubmit is not called. but if the form is validated handleSubmit method gets called. state is changed to validatedForm = true. Now data-toggle attribute is there on the submit button. just clicking on the button again triggered the modal for me.

React trouble with event.stopPropagation()

I have two components here, the first one is a table, and I have an on-click event attached to one of the <td>'s in every row that summons a little tooltip-like window:
<td onClick={ () => loadSelectorWindow(p.product_id) }>
{
p.selectorActive &&
<SelectorWindow
cancelWindow={this.cancelSelectorWindow}
product_id={p.product_id}/>
}
</td>
The function bound to the <td> click will search through all products in state and flip a boolean on the selected product to display the tooltip.
loadSelectorWindow = (product_id) => {
this.setState({ products: this.state.products.map( p => {
if (p.product_id == product_id) {
p.variationSelectorActive = true
} else {
p.variationSelectorActive = false
}
return p
})})
}
However, the tooltip also needs a button with a window cancel event linked to it:
// within <SelectorWindow />
<p onClick={ () => {cancelWindow(event)} }> X </p>
This function cycles through state and sets all of the display booleans to false.
cancelSelectorWindow = (event) => {
event.stopPropagation()
this.setState ({ products: this.state.products.map( p => {
p.variationSelectorActive = false
return p
})})
}
Putting breakpoints in the code I can see that the cancel button is correctly calling the cancel function and setting the displayTooltip boolean to false, temporarily. The problem is, the loadSelectorWindow is ALSO getting fired when the cancelWindow button is clicked, and the boolean is set back to true DX.
This is why I attempted to put the event.stopPropagation call in there but obviously something is still calling it. There is no other place in my code that the loadSelectorWindow function is mentioned... Any ideas how I can stop it from getting called?
I forgot to pass event to the cancelWindow callback function. React why is your syntax so confusing sometimes...
Fix:
<p onClick={ (event) => {cancelWindow(event)} }> X </p>
You have one html element nested inside the other, so if you click the inner one then you will receive onClick events for both. So that is what you are getting. You need to redesign the layout of the page so that does not happen.

Angular2-modal confirm callback

I am programming in an Angular 2 project. I have a several component where I want to use the same dialogue confirm box. Therefore i have put the confirm code in a separate class. The dialogue box is supposed to check whether a user wants to continue or save data.
I am using Angular2-modal for this pupose.
When either button on the confirm is pressed, I want to be able to return this answer to the component that called this confirm so I can perform certain actions there.
My code looks like this:
This is the function I call from my component:
this._popup.confirmSaveTemp(this.modal);
This is the function with the confirm code. Currently I can print out OK or cancel in the two spots where I have placed "TODO".
confirmSaveTemp(modal, target, param){
console.log(target);
modal.confirm()
.size('lg')
.isBlocking(true)
.showClose(false)
.keyboard(27)
.title('Warning')
.body(`
<p><b>Some fields have been <span class="text-danger">marked with red</span> because of one or several following reasons:</b></p>
<ul>
<li>You forgot to fill out all input fields</li>
<li>Entered values are unrealistically high or low</li>
<li>Use of illegal characters (e.g. typing letters instead of numbers for a persons age)</li>
</ul>
<p><b>Please make sure that you have filled out the form correctly.</b></p>
<p>
<b>If you are finished entering all values for this page and want to permanently save, click <span class="text-success">Continue</span>.</b>
<br>
<b>If you expect to enter the remaining values at another time click <span class="text-warning">Save Temporarily</span></b>
</p>
<p></p>
`)
.footerClass('defaultPopupFooter')
.okBtn('Continue')
.cancelBtn('Save Temporarily')
.okBtnClass('btn btn-success')
.cancelBtnClass('btn btn-warning')
.open()
.then( (resultPromise) => {
resultPromise.result.then( (result) => {
//TODO - CALL SAVE FUNCTION
},
() => {
//TODO - SAVE TEMP
} );
});
}
* Question: How can I inform the "parent" component what the response of this dialogue is OR how can call a function from the "parent" component? *
You can pass functions as parameters like this from the parent class:
private okCallback() {
// do stuff on ok
}
private cancelCallback() {
// do stuff on cancel
}
openModal() {
// ...
this._popup.confirmSaveTemp(
this.modal,
target,
param,
this.okCallback.bind(this),
this.cancelCallback.bind(this)
);
}
And in the confirmSaveTemp:
confirmSaveTemp(modal, target, param, okCallback, cancelCallback){
console.log(target);
modal.confirm()
// ...
.open()
.then( (resultPromise) => {
resultPromise.result.then( (result) => {
//TODO - CALL SAVE FUNCTION
},
() => {
//TODO - SAVE TEMP
} );
})
// on OK click
.then(okCallback)
// on Cancel click
.catch(cancelCallback);
}

How do I use JavaScript or jQuery to submit a form by using the Enter key, when not the default form action

I have a page that has three "forms" that are apparent to the user. Under the hood, the page has only ONE form, using html:form as the JSP object controlling the entire page. When a user clicks on the image that is used for the individual submit buttons, it triggers an onClick() function, which bypasses the form's action and executes another action instead.
<html:form action="foo.do">
<html:text property="name" styleClass="input" />
<img src="bar.jpg" onClick="myFunction();" />
</html:form>
<script>
function myFunction(){
document.forms[0].action = "realPage.do";
document.forms[0].submit();
}
</script>
This script works, sending the user not to the default "foo.do" but rather to the destination of the function (realPage.do)
However, the problem is my users want to be able to submit the form just by hitting 'Enter' on their keyboard when in any one of the fields, of the particular "form" they want to submit. How can I use JavaScript or jQuery to recognize which "form" and, hence, which input field the user is in, detect the press of the 'Enter' key and submit using the same function as the button?
This should solve your problem
$(document).ready(function(){
$("input").keyup(function (e) {
if (e.keyCode == 13) {
// Submit your form here
}
});
});
I would probably arrest the form submit and detect which element has focus. Something like this, where each pseudo-form has an identified wrapper element:
$(function() { // document.ready
$('#myform').submit(function(event) {
event.preventDefault();
if ( $('#pseudoForm1 input').is(':focus') ) { ... }
else if ( $('#pseudoForm2 input').is(':focus') ) { ... }
else if ( $('#pseudoForm3 input').is(':focus') ) { ... }
});
});
You could start with this -
$('input').keypress(function(e) {
if(13 == e.keyCode) {
var closestForm = $(this).closest('form');
$(closestForm).submit();
}
});

Categories

Resources