I have a webpage written in React (but it should not be strictly relevant to that question) that is composed by several inputs, let's call them Name, Surname and Code.
To work quickly, the insertion of the code is done with a Barcode Scanner that works as external keyboard. My idea is that if some field is focused, the keypress is inserted in the focused input but, in case no input is focused, I want to automatically focus and fill the Code input.
Is there a way to that it easily?
let inputName = document.querySelector('input[name="name"]');
let inputSurname = document.querySelector('input[name="surname"]');
let inputCode = document.querySelector('input[name="code"]');
let focusedInput = null;
[inputName, inputSurname, inputCode].forEach((input) => {
input.addEventListener('blur', () => {
focusedInput = null;
});
input.addEventListener('focus', () => {
focusedInput = input;
});
});
document.body.addEventListener('keypress', () => {
if (focusedInput == null) {
inputCode.focus();
}
});
<div>
<label>Name</label>
<input type="text" name="name" />
</div>
<div>
<label>Surname</label>
<input type="text" name="surname" />
</div>
<div>
<label>Code</label>
<input type="text" name="code" />
</div>
const surnameInput = document.getElementById('surname-input');
... (= do for all inputs)
let activeInput;
surnameInput.onFocus = () => { activeInput = surnameInput };
...
surnameInput.OnBlur = () => { activeInput = undefined };
...
document.addEventListener('keypress', (ev) => {
const input = activeInput ?? codeInput;
input.value += valueOftheKey;
}
You'd obviously have to evaluate if the key that was pressed has a value which you can add to the input, but I think this should give you an Idea of what to do. I haven't tried it out though, so it might not completely work.
Also: I'm not sure if it's the most efficient way, but it's an option.
EDIT: Answer by Kostas is better ;) except for the null...you should use undefined
Related
I don't want any space before the input and after the input like " text" and "text " does not allow so I replace the white space but when we copy "text " from notepad and paste over the input and want to remove the space it throws error like "can not read property of undefined reading target".so how to do like when user give space front and back its automatically replace whitespace
const handleKeyDown = (e) => {
if (e.key === " ") {
e.preventDefault();
}
};
const handleChangeWhiteSpace = (e) => {
if (e.target.value.includes(" ")) {
e.target.value = e.target.value.replace(/\s/g, "");
}
};
<MyInput
type="text" style={{width:'240px'}}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
onBlur={formik.handleBlur}
onChange={(e)=>{formik.handleChange(e);handleChangeWhiteSpace()}}
onKeyDown={handleKeyDown}
name="input"
id="input"
autoFocus={false}
autoComplete="off"
/>
using regex the following should work, you can test it at regex101:
e.target.value = e.target.value.replace(/^[ \t]+|[ \t]+$/gm, "");
the cleaner solution would be what sojin suggested
e.target.value = e.target.value.trim()
Replace
const handleChangeWhiteSpace = (e) => {
if (e.target.value.includes(" ")) {
e.target.value = e.target.value.replace(/\s/g, "");
}
};
With this
const handleChangeWhiteSpace = (e) => {
e.target.value = e.clipboardData.getData('Text').trim();
};
To register changes when you paste text inside the text field use the onPaste event
onPaste={handleChangeWhiteSpace}
Final Code
const handleKeyDown = (e) => {
if (e.key === " ") {
e.preventDefault();
}
};
const handleChangeWhiteSpace = (e) => {
e.target.value = e.target.value.trim();
};
<MyInput
type="text" style={{width:'240px'}}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
onBlur={formik.handleBlur}
onPaste={handleChangeWhiteSpace}
onChange={(e)=>{formik.handleChange(e);
handleChangeWhiteSpace()}}
onKeyDown={handleKeyDown}
name="input"
id="input"
autoFocus={false}
autoComplete="off"
/>
use normalize={(value, prevVal, prevVals) => value.trimStart()} after rules{[]} in form.item
for prevent whitespace before value in antd input
for example check selected code in image ==>
enter image description here
To dont allow to send only spaces you can use normalize prop
<MyInput
type="text" style={{width:'240px'}}
normalize={(value) => value.trimStart()}
error={formik.errors.input && formik.touched.input}
value={formik.values.input}
and then you can remove all of the spaces inside of this function
const onFinish = (values) => {
//values.input1=values.input1.trim() or whatever
}
btw this function you can use to remove all the spaces
const remove = (str) => str.trim().replace(/\s\s+/g, ' ')
I am new to JavaScript and tend to get stuck with some problems. I was trying to create a custom validation for a form, which consists from 4 inputs, but the code doesn't work for me. Does anyone have any ideas how can I fix it? Here is just one of the inputs:
<div class="inputWrapper">
<input class="formInput required type="text" name="Email" id="Email" placeholder="Email Address"/>
<img class="errorImg hidden" src="/images/icon-error.svg" />
<div id="emailError" class="errorMessage hidden">
<i>Email cannot be empty</i>
</div>
</div>
I also have two divs that should appear, when the input is submitted with error, before that they have a class "hidden" with display none.
"use strict";
const formInput = document.querySelector(`.formInput`);
const errorImg = document.querySelector(`.errorImg`);
const errorMessage = document.querySelector(`.errorMessage`);
const input = formInput.nodeValue;
const errorOccured = function () {
errorMessage.classList.remove(`hidden`);
errorImg.classList.remove(`hidden`);
};
form.addEventListener("submit", function () {
if (input === ``) {
errorOccured();
}
});
This is how the page looks like itself:
You should read input value in the event listener function
let form = document.querySelector("#form1");
form.addEventListener("submit", function (e) {
const input = formInput.value;
if (input === '') {
errorOccured();
e.preventDefault();
}
});
I have created a javascript script in which all clicks and action of a particular IP it tracked down when attached in a page. It all works fine except when the user searches something from an input field. I need to track that text which user has searched.
But I don't have any information regarding that input field i.e id or class also a page can have.
multiple input fields i.e A form for submission too.
I need to get that text when the enter key is pressed or any button(search) is pressed
In my case at present html page, I have below code.
<div class="navbar-form navbar-right">
<!-- Search Page -->
<div id="search-container" class="search-container" style="float: left;">
<div class="search-wrapper">
<div class="search-input-wrapper">
<input type="text" class="search-layouts-input" ng-model="searchQuery" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" placeholder="So, what are you looking for?" ng-keyup="$event.keyCode == 13 ? actionSearch() : null">
<button type="submit" class="s-layout-btn" ng-click="actionSearch();">
<svg id="Layer_1" width="20px" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#222">
<defs>
<style>.cls-1{fill:none;stroke:#222;stroke-miterlimit:10;stroke-width:2px;}</style>
</svg>
</button>
</div>
</div>
</div>
<!-- Search Page -->
</div>
Is this the kind of thing that you're looking to implement? Of course most of it is pseudo code, but it's pretty straight-forward, just get all relevant inputs and buttons and whatnot, attach some event handler to them and update the application state.
I've included some basic functions that you may wish to fire in certain scenarios, such as onStateUpdate, there may be no need for this function, but it probably wouldn't hurt to keep it for the sake of simplcity.
I've used mostly ES6 oriented syntax because it allows you to achieve the same results with less code, I'm just that lazy.
The reason why I used a self invoked function just so there's no issues with variable names and nothing can be manipulated on the global scope, etc. If you'd like to read or know more about why self invoked functions can be pretty good, then I suggest you read sources such as this.
// Self invoked anonymous function.
(function() {
// The application state.
const state = {};
// Lazy way to use querySelectorAll
const $e = qs => document.querySelectorAll(qs);
// Make a copy of the state and make it global.
const getState = () => {
window.state = { ...state};
console.clear();
console.log(window.state);
};
// A function to run when the state updates.
const onStateUpdate = () => {
// Do some other stuff...
getState();
};
// Handle the key up event.
const inputHandler = (i, index) => i.onkeyup = () => {
i.id == null || i.id == '' ? i.setAttribute("id", index) : null;
const id = i.id;
state[id] = i.value;
onStateUpdate();
};
// Handle a button being clicked.
const clickHandler = btn => btn.onclick = onStateUpdate;
// Handle the enter key being pressed.
const enterHandler = e => e.keyCode == 13 ? onStateUpdate() : null;
// Assign all relevant events to the relevant functions.
const dispatchEvents = () => {
const inputs = $e("#search-container input[type=text]");
const buttons = $e("#search-container button");
inputs.forEach((i, index) => inputHandler(i, index));
buttons.forEach(b => clickHandler(b));
window.onkeypress = enterHandler;
};
// Fire the dispatch function.
dispatchEvents();
}());
<!-- this one does nothing as it's outside of the search-container element -->
<input type="text" id="testing" placeholder="I do nothing!" />
<div id="search-container">
<input type="text" id="test" />
<input type="text" id="demo" />
<input type="text" id="markup" />
<input type="text" />
<button>Search</button>
</div>
Older Syntax
// Self invoked anonymous function.
(function() {
// The application state.
var state = {};
// Lazy way to use querySelectorAll
var $e = function(qs) {
return document.querySelectorAll(qs);
};
// Make a copy of the state and make it global.
var getState = function() {
window.state = JSON.parse(JSON.stringify(state));
console.clear();
console.log(window.state);
};
// A function to run when the state updates.
var onStateUpdate = function() {
// Do some other stuff...
getState();
};
// Handle the key up event.
var inputHandler = function(i, index) {
i.onkeyup = function() {
if (i.id == null || i.id == '') {
i.setAttribute("id", index);
}
var id = i.id;
state[id] = i.value;
onStateUpdate();
};
};
// Handle a button being clicked.
var clickHandler = function(btn) {
btn.onclick = onStateUpdate;
};
// Handle the enter key being pressed.
var enterHandler = function(e) {
if (e.keyCode == 13) {
onStateUpdate();
};
};
// Assign all relevant events to the relevant functions.
var dispatchEvents = function() {
var inputs = $e("input[type=text]");
var buttons = $e("button");
inputs.forEach(function(i, index) {
inputHandler(i, index)
});
buttons.forEach(function(b) {
clickHandler(b)
});
window.onkeypress = enterHandler;
};
// Fire the dispatch function.
dispatchEvents();
}());
<input type="text" id="test" />
<input type="text" id="demo" />
<input type="text" id="markup" />
<input type="text" />
<button>Search</button>
This is a follow up to my question, seen here
I am trying to write that when a user enters in their name (string) into the field and hits enter, it pushes it into an array. It works, kinda. But I get an error when I try it one and then it produces multiple arrays when I try it another. I don't want to use jQuery.
Here is the HTML
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
Here is my js that works but it creates multiple arrays instead of pushing everything into one array (because the nextElementSibling is not called, I know this, see next block
let namesOfPlayers = [];
let currentValue = document.getElementById("bind").value;
let button = currentValue.nextElementSibling;
document.addEventListener('keypress', function (e) {
const key = e.which || e.keyCode;
if (key === 13) {
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
}
});
Here is my js that throws an error (I don't want to use jQuery)
I want that when a user hits enter or clicks the button that the string is submitted and added into the empty array. I can't for the life of me figure out how to make that work.
Thanks for your help!
You fetch the value of the input too soon. You should fetch it only when the button is clicked, not before.
Secondly, the button does not have a keypress event, nor a keyCode associated with it. You need to listen to the click event.
So do this:
let namesOfPlayers = [];
let input = document.getElementById("bind");
let button = input.nextElementSibling;
button.addEventListener('click', function (e) {
namesOfPlayers.push(input.value);
console.log('namesOfPlayers', namesOfPlayers);
});
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names" />
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
Try this code, i added a click (for the button) and keypress (for the text input) events
so if you click enter when you focus on the text input the text in the input will be in the array.
and the same will happen if you click "Go" button
let namesOfPlayers = [];
let currentElement = document.getElementById("bind");
let button = currentElement.nextElementSibling;
let addPlayer = () => {
namesOfPlayers.push(currentElement.value);
console.log(namesOfPlayers); // Just for testing
}
currentElement.addEventListener('keypress', function (e) {
if (e.which === 13 || e.keyCode === 13) {
addPlayer();
}
});
button.addEventListener('click', addPlayer);
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="button" id="thego" class="pre enterteam" value="click">Go</button>
CurrentValue is defined outside of the event listener, so it only gets called once, on initialisation. That's why the push call only injects empty strings. Also, the button doesn't do anything because it doesn't have a listener.
Here's the updated code:
let namesOfPlayers = [];
// It's better to get the button by id instead of getting it by a previous child.
// This is because it might cause some unexpected behaviour if someone changed the HTML.
const button = document.getElementById("thego");
button.addEventListener('click', function (e) {
addItemToArray(namesOfPlayers);
});
document.addEventListener('keypress', function (e) {
const key = e.which || e.keyCode;
if (key === 13) {
addItemToArray(namesOfPlayers);
}
});
function addItemToArray(namesOfPlayers) {
const currentValue = document.getElementById("bind").value;
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
}
https://fiddle.jshell.net/4k4a9m6y/
But, you're better off with a form to improve performance.
let namesOfPlayers = [];
const form = document.getElementById("form");
form.addEventListener('submit', function (e) {
const currentValue = document.getElementById("bind").value;
namesOfPlayers.push(currentValue);
console.log('namesOfPlayers', namesOfPlayers);
});
<form id="form"
action="javascript:void(0);">
<input type="text"
class="theplayer pre"
name="Player"
id="bind"
placeholder="Enter Names"
/>
<button type="submit" id="thego" class="pre enterteam" value="click">Go</button>
</form>
https://fiddle.jshell.net/4k4a9m6y/2/
I have a controlled input that has a value initially showing.
I have set that input to autoFocus but the cursor appears at the beginning of the input when I am wanting it to appear at the end. I understand this might be because the autoFocus is added before the value is but I'm not 100% sure.
What would be the best way to accomplish the cursor initializing at the end of the input field?
var Test = React.createClass({
getInitialState: function() {
return {
teamId: 'fdsfds'
};
},
render: function() {
return (
<input type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />
);
},
setTeamId: function(event) {
this.setState({ teamId: id });
},
});
ReactDOM.render(
<Test />,
document.getElementById('container')
);
https://jsfiddle.net/69z2wepo/34486/
One solution:
<input
type="text"
autoFocus
value={this.state.teamId}
onChange={this.setTeamId}
onFocus={function(e) {
var val = e.target.value;
e.target.value = '';
e.target.value = val;
}}
/>
https://jsfiddle.net/o3s05zz4/1/
Adaptation of this answer: https://stackoverflow.com/a/2345915/1589521
This actually works:
componentDidMount() {
const input = this.input;
const length = input.value.length;
input.focus();
input.setSelectionRange(length, length);
}
render() {
return (
<input ref={ref => this.input = ref} ... >
)
}
PS. If you need to support IE8 and below you'll need to use IE-specific checks.
This way the text of the input will be selected, ready to edit
<input
type="text"
defaultValue="Untitled"
autoFocus
onFocus={e => e.currentTarget.select()}
/>
Setting the input value inside componentDidMount seems to do the trick, but it feels like a hack:
componentDidMount: function(){
this.inputElement.value = this.state.teamId;
},
render: function() {
var that = this;
return <input ref={function(ref){that.inputElement = ref;}} type="text" autoFocus value={this.state.teamId} onChange={this.setTeamId} />;
},
https://jsfiddle.net/yuk13tuu/
In TypeScript:
private inputDOM: HTMLInputElement | null;
public componentDidMount() {
if (this.inputDOM != null) {
this.inputDOM.value = '';
this.inputDOM.value = this.state.newRegionName;
}
}
public render() {
return <input ref={(ref: HTMLInputElement | null) => this.inputDOM = ref} type="text" autoFocus={true} value={this.state.inputValue} />;
}
Looks like the html attribute autofocus doesn't take any parameters to specify where the cursor should start. See mdn documentation.
Sitepoint has a great tutorial explaining your options for setting cursor position from within an input box.
As for the reacty side of things, you'll simply put your jQuery (or other cursor related code) in the componentDidMount lifecycle method.