conditionally set data-toggle attributes in React js - javascript

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.

Related

Action on blur except when specific element clicked with react OR how to get clicked element onBlur

I want to prevent onBlur event when I click on a specific element:
<input type="text" onBlur={<call when I click outside of element except when I click on a specific element>} />
What you could do is give the element that would stop the call an ID and then check for that ID via event.relatedTarget.id
const doSomething = (event) => {
if(event.relatedTarget.id === "badButton"){
return
}
//Do things
}
return(
<div className="DashboardHeader" onBlur={(e) => doSomething(e)}>
<button id="badButton">newbutton</button>
</div>
)

submitting form on enter

I'm having issue submitting search form on hitting enter as well as button click. The click works fine. Text is cleared, the /search page renders and search index shown. When I hit enter, the search text clears, but nothing else. I've added a functions handleSubmit, but it does't work. How do I make it search on enter?
handleSubmit(e) {
e.preventDefault(e);
document.getElementById("search-input")
.addEventListener("keydown", function (event) {
// event.persist();
if (event.keyCode === 13) {
document.getElementById("search-button").click();
}
});
this.setState( {
searchItem: "",
})
};
render() {
return (
<div id="search-form">
<form>
<input
type="text"
id="search-input"
placeholder="Search videos"
value={this.state.searchItem}
onChange={this.update()}
/>
<button type="submit" id="search-button" onClick={this.handleSubmit}>
<Link to={`/search?search=${this.state.searchItem}`}><img id="search-icon" src="https://image.flaticon.com/icons/svg/49/49116.svg" alt="" /></Link>
</button>
</form>
</div>
);
}
document.getElementById("id_of_your_textbox").addEventListener("keydown", function(e) {
// Prevent a blank line.
e.preventDefault();
// Enter is pressed.
if (e.keyCode == 13) {
this.submit();
}
}, false);
Simply, edit document.getElementById("search-button").click(); to document.getElementById("search-button").submit();
In forms, enter to submit is enabled by default, but you need to tell the form what to do on submit. So, add an onsubmit event to your form:
<form onSubmit={this.handleSubmit}>
...
</form>
Or, via JS's addEventListener:
form.addEventListener('submit', this.handleSubmit);
Edit: Oh, and you should add preventDefault() at the beginning of the event handler's function, something like:
handleSubmit(e) {
e.preventDefault(); //prevents the form from submitting before the end of this function
//do something here...
}
Your EventListener cant be inside the handleSubmit function.
form.addEventListener('submit', handleSubmit());

form.submit callback not getting invoked

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.

ReactJS - Avoid resetting state when updating an object within state

I am fetching some data from the server to populate a list of items, and each item got a onClick event binded to the items id, that changes the UI to be disabled when clicked.
My problem is that the UI changes to disabled perfectly on the first click, but when I go on to click on the next item it resets the first one, so there is only one button disabled at a time. How do I make it so I can disable all the items I want, without resetting the previous state?
class Video extends Component {
constructor () {
super()
this.state = {
isDisabled: false
}
}
handleClick(frag, voted, event){
event.preventDefault()
this.setState({
isDisabled: {
[frag]: true
}
})
}
Snippet of what I return in the UI that changes the disabled button
<button onClick={this.handleClick.bind(this, frags.id, frags.voted)} disabled={this.state.isDisabled[frags.id]} className="rating-heart-2">
<i className="fa fa-heart" aria-hidden="true"></i>
</button>
I would really appreciate all tips!
You are completely replacing isDisabled each time you update state, but you really just want to add a new property to it. Try the following:
handleClick(frag, voted, event){
event.preventDefault();
let {isDisabled} = this.state;
isDisabled[frag] = true;
this.setState({isDisabled});
}

Submit form with two submit buttons, each performing different actions issue

I have a JSP page, which has standard form on it. I have two buttons, each perform a different action when pressed, and the form is submitted - action 1 and action 2.
I originally had this set up for one button, so it was all done through the following and worked fine:
$('#form').submit( function() { .... }
But now I have two buttons, I want it to do the same, but how to find which button I pressed.
I could do this through the .click function, but I dont want to break my existing form.submit functionality.
Below is my code for this - which doesn't work:
$('#form').submit( function() {
// Set the field array variables with data
$('button[name="action1"], [name="action2"]').each(function(index) {
alert('index : ' + index );
alert('value : ' + this.value);
});
$('button[name="action1"]').click(function(e) {
alert('ac1 clicked');
});
$('button[name="action2"]').click(function(e) {
alert('ac2 clicked');
});
my html buttons are:
<button id="submitButton" name="action1" value="action1" type="submit">action 1</button>
<button id="submitButton" name="action2" value="action2" type="submit">action 2</button>
Is there a way I can do this inside my form.submit, or a way to do the .click, which then submits the form. I am a little lost for a solution on this?
Please help :)
You can read the related target of the event object.
$('#form').on('submit', function(evt) {
if (evt.relatedTarget && $(relEl).is('input[type=submit]')) {
/* related element is a button - do something */
}
evt.preventDefault(); //cancel form submit, as required
});
In the button's click handler, set a hidden field before submitting the form. Then read the value of that hidden field in the request handler to find out which action was requested.
Bind a event handler to your buttons
$('button').on('click', function(e) {
var buttonId = $(this).attr('name');
if(buttonId = 'action1') {
// action1 was pressed
} else {
// action2 was pressed
}
$('#form').trigger('submit'); // trigger submit of form.
e.preventDefault();
});
First of, never include two dom elements with the same id on the same page. The class attribute is for such things. Change the id's of the buttons to submitButton1 and submitButton2 respectively and then this ought to work:
$('#submitButton1').closest('#form').submit(function() {
// first button action
});
$('#submitButton2').closest('#form').submit(function() {
// second button action
});
For standard HTML form submission :
HTML:
<form method="..." action="...">
...
<input type="hidden" name="action">
<input value="action1" type="submit" value="action 1" />
<input value="action2" type="submit" value="action 2" />
...
</form>
Javascript:
$('button[type="submit"]').on('click', function() {
$("#action").val(this.value);//where "#action" selects an input field (in the same form) of type="hidden"
});
For AJAX submission, do the same but read the action field's value back into javascript in the submit handler.

Categories

Resources