I am working on a form including a sort of tag input. If a user inputs a tag and hits enter it will add the tag to a certain array. But, when I hit enter, it will also submitting the form. Ofcourse, I can add the e.preventDefault() trick but then again, it will still run the JavaScript code, something I don't want when I am trying to input a tag.
So I've tried to add a if statement to notice if the key is equel to enter but the form don't get notified which button is clicked, I guess.
So this function will run If I hit enter on the form.
handleForm(e) {
e.preventDefault();
// Not working..
if(e.keyCode === 32) {
alert('Enter..') // prevent submitting further here or something
} else {
let state = { ...this.state.product }
if (state.name == '' || state.price == 0 || state.ingredients.length <= 0) {
alert('Naam, prijs en ingredienten zijn verplicht');
} else {
console.log(state);
}
}
}
How can I totally block the enter key for submitting? How can I use that key code for instance with a form or something? I've tried to add a event listener but that didn't work out since it will submit when I hit a other button than Enter.
For context, my tag input function which got fired from a keyup event.
handleKeyPress(e) {
// if the event key == enter key (is working..)
if (e.keyCode === 32) {
// Check if there is a ingredient supplied
if(this.state.tag == '') {
alert('Vul een ingredient in')
} else {
// Get the value of the ingredient input
let tag = this.state.tag;
// Copy state of just the ingredients (not the product)
let ingredients = [...this.state.product.ingredients];
// Create an array including only the names of the ingredients
let names = ingredients.map((item) => {
return item.name;
});
// Check if the array already includes the ingredient
if (names.includes(this.state.tag)) {
// Alert if the ingredient already exists
alert('Deze ingredient is al toegevoegd');
} else {
// Set the ingredient with value
let ingredient = { name: tag, value: 1 };
// Push the ingredient to the ingredients array of product
ingredients.push(ingredient);
// Get the product state
let product = this.state.product;
// set the ingredients of the product object with new ingredient
product.ingredients = ingredients;
// Change and set the state of proudct and empty out the tag input (ingredient)
this.setState({ product: product }, () => {
this.setState({ tag: '' });
});
}
}
}
}
When you use a form, it will always trigger onSubmit event when you hit enter, so assuming you want to use "enter" to keep adding tags, you can leave your add tags code in the submit function and add a button with type="button" (so the button wont submit on clicks) for when you are done with the form and use its onClick event to finish the form.
Example:
constructor(props) {
super(props);
this.handleDoneWithForm = this.handleDoneWithForm.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleDoneWithForm() {
// Code for when the form is finished
}
handleSubmit(event) {
event.preventDefault();
// Add tag code
}
render() {
return (
<form onSubmit={this.handleSubmit}> // will be triggered on enter
// form inputs
<button type="button" onClick={this.handleDoneWithForm}> // will be triggered on click
Done with form
</button>
</form>
);
}
Related
I need to enable the submit button as soon as all input fields has value enterred. I have two input fields type text and type password and a button which is disabled (I set its class as "disabled" than use CSS to change color etc..), I would like to remove that class whenever the above condition is met. I added 'change' and 'input' event listeners to all field like below:
const inputs = [...document.querySelectorAll('input[type="text"], input[type="password"]')];
const continueBtn = document.querySelector('continuebtn');
const signinForm = document.querySelector('#sign-in-form');
inputs.forEach((input) => {
input.addEventListener('input', function(e){
if (input.value !== '') {
continueBtn.classList.remove('disabled');
}else{
continueBtn.classList.add('disabled');
}
}
});
Tried with e.target.value.trim() === '' as well
I guess the above would be applied to all inputs and check if they're empty when the user is typing, but I'm not able to make it work: the button is being activated no matter what I do.
I would need some help in plain Javascript as this is what I'm currently learning. no jQuery. Thanks
Use the every() method to check all the inputs, not just the one that the user is currently editing.
const inputs = [...document.querySelectorAll('input[type="text"], input[type="password"]')];
const continueBtn = document.querySelector('#continuebtn');
const signinForm = document.querySelector('#sign-in-form');
inputs.forEach((input) => {
input.addEventListener('input', function(e) {
if (inputs.every(input => input.value.trim())) {
continueBtn.classList.remove('disabled');
} else {
continueBtn.classList.add('disabled');
}
});
});
#continuebtn.disabled {
background-color: grey;
}
<input type="text">
<input type="password">
<button id="continuebtn" class="disabled">Continue</button>
I have made this code to validate if all input fields have been filled. If not submission is not allowed, but when it is correct I have to click twice on the submit button, the first time it validates and adds the eventListener and the second time it runs because it has the event listener. How can I modify the code so that I only have to click once?
function validaInput() {
const inputs = document.querySelectorAll(".input-field");
let validez;
inputs.forEach(function(input) {
if (input.value !== "") {
validez = true;
} else {
validez = false;
}
});
if (validez) {
submitBtn.addEventListener("click", calculaPromedio);
submitBtn.addEventListener("click", addMateria);
} else {
alert("No ha llenado todos los campos.");
}
}
Just call the relevant functions instead of adding a listener. (Also, you would otherwise add new duplicate listeners every time the button is clicked.)
if (validez) {
calculaPromedio();
addMateria();
} else {
alert("No ha llenado todos los campos.");
}
If you use this inside those function, you'd need instead e.g. calculaPromedio.call(this).
Not able to reference when user presses an enter or escape key.
I've created a calculator app. I wanted the buttons and the keyboard to be usable. Where my problem lies is figuring out how to reference the value of an enter key usage or an escape key usage. the onChange event doesn't seem to give a value to those?
I'm using a class component in React for this...
my function that gets called onChange is:
handleKeyboard = (e) => {
let userInput = e.target.value;
console.log("beginning of handleKeyboard fx: ", userInput);
this.setState({
screenDisplay: userInput
});
this.userEntersNonNumber(e);
}
this function then accesses the following function to determine what to do when the user enters a non number....
userEntersNonNumber = (e) => {
let userInput = e.target.value;
if (userInput.includes("+") === true) {
console.log('a plus sign was used');
this.addition();
} else if (userInput.includes("-") === true) {
console.log('a minus sign was used');
this.subtraction();
} else if (userInput.includes("*") === true) {
console.log('a multiplication sign was used');
this.multiplication();
} else if (userInput.includes("/") === true) {
console.log('a division sign was used');
this.division();
} else if (userInput.includes("enter")) {
console.log('the enter key was pressed');
/* I have a function that does the math which would be referenced here */
} else if (userInput.includes("escape")) {
console.log('the enter key was pressed');
/* I have a function that clears the calculator which would be referenced
here */
} else {
console.log('keep typing')
}
}
where the function is called is:
the screenDisplay state is a way to display what the user has entered into the calculator thus far. It is a string and with each key entered or button pushed, the value of that key/button gets added on to the end of the string.
The user should be able to use the enter key or the escape key on their keyboard to call the solve or clear functions which either calculate their entries or clears the calculator. The buttons are operational, but the keystrokes are not.
The input tags have another event listener called onKeyDown which is triggered when the user presses a key. You can create a brand new event-handler that handles logic for when the user presses the escape or enter key.
You just need to capture the keyCodes from the event, there are corresponding keyCodes for every key.
class App extends React.Component {
handleKeyDown = e => {
if (e.keyCode === 13) {
console.log("Enter action"); //replace with your code
} else if (e.keyCode === 27){
console.log("Escape action") //replace with your code
}
};
render() {
return <input onKeyDown={this.handleKeyDown} />;
}
}
You can still use this event-listener in simultaneously with your existing onChange event.
I figured it out! I had to add an onKeyDown event to reference the userEntersNonNumber function to reference the value of the enter and escape keys. Fixed it by:
<input className="screen" type="text" onChange={this.handleKeyboard} value={this.state.screenDisplay} **onKeyDown={this.userEntersNonNumber}**></input>
And:
userEntersNonNumber = (e) => {
let userInput = e.target.value;
**var x = e.key;**
console.log("Key pressed: ", x);
if (userInput.includes("+") === true) {
console.log('a plus sign was used');
this.addition();
} else if **(x === 'Enter')** {
console.log('the enter key was pressed');
this.solve();
} else if **(x === 'Escape')** {
console.log('the escape key was pressed');
this.clearEntry();
}
So I have a button that whenever clicked appends whatever the user entered below the input field. I want to make it so when clicked with an empty field nothing appends (essentially the function does not run).
Here is my code:
var ingrCount = 0
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
var ingredientSpace = $("<p>");
ingredientSpace.attr("id", "ingredient-" + ingrCount);
ingredientSpace.append(" " + ingredientInput);
var ingrClose = $("<button>");
ingrClose.attr("data-ingr", ingrCount);
ingrClose.addClass("deleteBox");
ingrClose.append("✖︎");
// Append the button to the to do item
ingredientSpace = ingredientSpace.prepend(ingrClose);
// Add the button and ingredient to the div
$("#listOfIngr").append(ingredientSpace);
// Clear the textbox when done
$("#ingredients").val("");
// Add to the ingredient list
ingrCount++;
if (ingredientInput === "") {
}
});
So I wanted to create an if statement saying when the input is blank then the function does not run. I think I may need to move that out of the on click function though. For the if statement I added a disabled attribute and then removed it when the input box contains something. But that turns the button another color and is not the functionality I want. Any ideas I can test out would help. If you need any more information please ask.
If you're testing if ingredientInput is empty, can you just return from within the click event?
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
if(ingredientInput === '') { return; }
// rest of code
Simply use :
$("#addIngrButton").on('click', function() {
var ingredientInput = $("#ingredients").val().trim();
if (ingredientInput.length == 0) {
return false;
}
// ..... your code
I'm jumping in on a pretty big React JS project which is using react-data-grid to display a bunch of editable data. Right now, you have to click an Update button to send changes to the server. My task at hand is to create auto-save functionality like so:
User selects cell to edit text
User changes text
User either moves to another cell or clicks away from data-grid
Changes are persisted to the server
Here's what I've tried:
onBlur event on each column. The event will fire, but it seems like the event was attached to a div and not the underlying input control. Therefore, I don't have access to the cell's values at the time this event is fired.
onCellDeselected on the <ReactDataGrid> component itself. It seems like this method is fired immediately upon render, and it only gets fired subsequent times when moving to another cell. If I'm editing the last cell and click away from the data-grid, this callback isn't fired.
Using react-data-grid, how can I effectively gain access to an editable cell's content when the user finishes editing?
The commits on react-data-grid are handled by the EditorContainer. The commit logic is simple. An editor commits a value when:
The editor unmounts
Enter is pressed
Tab is pressed
In some cases when the arrows are pressed (will skip this part is it may not be necessary for you, you can look at the logic for this on the EditorContainer)
Based on that the way I would recommend to do the autosave is:
Create an an EditorWrapper (HOC) the editors where you want auto save to be turned on
const editorWrapper(WrappedEditor) => {
return class EditorWrapper extends Component {
constructor(props) {
base(props);
this._changeCommitted = false;
this.handleKeyDown.bind(this);
}
handleKeyDown({ key, stopPropagation }) {
if (key === 'Tab' || key === 'Enter') {
stopPropagation();
this.save();
this.props.onCommit({ key });
this._changeCommitted = true;
}
// If you need the logic for the arrows too, check the editorContainer
}
save() {
// Save logic.
}
hasEscapeBeenPressed() {
let pressed = false;
let escapeKey = 27;
if (window.event) {
if (window.event.keyCode === escapeKey) {
pressed = true;
} else if (window.event.which === escapeKey) {
pressed = true;
}
}
return pressed;
}
componentWillUnmount() {
if (!this._changeCommitted && !this.hasEscapeBeenPressed()) {
this.save();
}
}
render() {
return (
<div onKeyDown={this.handleKeyDown}>
<WrappedComponent {...this.props} />
</div>);
}
}
}
When exporting you editor just wrap them with the EditorWrapper
const Editor = ({ name }) => <div>{ name }</div>
export default EditorWrapper(Editor);
Use one of the start or stop event callback handlers at the DataGrid level like onCellEditCommit
<DataGrid
onCellEditCommit={({ id, field, value }, event) => {
...
}
/>
or a valueSetter for a single the column definition:
const columns: GridColDef[] = [
{
valueSetter: (params: GridValueSetterParams) => {
// params.row contains the current row model
// params.value contains the entered value
},
},
];
<DataGrid columns={columns} />