Javascript/JQuery wait for user input - javascript

I'm working on a text-based browser game made using Javascript and JQuery.
I've run into a problem with user input.
What I used to do was just use a prompt() because it was easy to use, allowed me to save the input to a variable and made the code wait for input.
Now I want it to look better, so I've made my own input field with a nice chatbox above it.
What I wanted to know was how to stop the code from executing untill the user has pressed enter (I already detect the enter press and the text is being appended to the dialog box, I just need the code to wait for that to happen before it continues).
Here's some of my code:
Function for input
function input_field() {
var inputField = $('#dialog-input');
var messageField = $('#dialog-text');
inputField.keyup(function (e) {
if (e.keyCode == 13) {
window.userInput = inputField.val();
if(userInput != '') {
messageField.append('You: ' + window.userInput + '<br>');
inputField.val('');
messageField.scrollTop(999999999);
}
}
});
}
What I'd like to do is just save the data to a variable and then check it with a switch-case just like with prompt(), but as it stands now it just gives me an error because it tries to execute all the code instead of wait untill the user has given input.

It is possible with asynch+await.
Please note, that it is currently not fully supported by all browsers (http://caniuse.com/#search=await) and that there are probably better solutions to this kind of problems.
Using await myAsyncFunction() makes the browser treat the function like it is synchrounous, therefore it stops further execution of this function until a result is returned by the awaited function. It does not block other code on the website from running.
await may only be used inside a async function, otherwise the browser will throw an error.
Here is an example showing how you could wait for user input with await+async:
async function handleForm() {
let userInput = '';
console.log('Before getting the user input: ', userInput);
userInput = await getUserInput();
console.log('After getting user input: ', userInput);
};
function getUserInput() {
return new Promise((resolve, reject) => {
$('#myInput').keydown(function(e) {
if (e.keyCode == 13) {
const inputVal = $(this).val();
resolve(inputVal);
}
});
});
};
handleForm();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="myInput">

You have to thing differently, while javascript stop and wait for a returned value when using prompt(), you can't directly achieve that with a custom prompt.
var result = [];
for(var i = 0; i > 5; i--){
result.push( prompt('tip something') ); // Ok
};
javascript will break until prompt return something
but you can't tell your code to stop, like the browser does when promprting. You'll have to execute a code when closing the modal (on button click or keypress enter) that open/update the next modal.

Related

How to make a function in Node JS run only once

I am creating a simple tictactoe terminal game in JS. I use the variable named player1Input to get user prompt. If the prompt is not equal to "X", I call the function again to make sure the user input the right input. If I enter the wrong input multiple times, the function (player1Game) ends up being called multiple times instead of once. How do I get it to just be called once. I put a snippet of my code at the bottom.I commented the part of the code that makes the function run twice
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
//the function runs multiple times here instead of once.
// How do I get it to run only once.
}
You still aren't showing the whole context here, but perhaps you just need to return after you call it again so that the rest of the function doesn't execute when the function doesn't meet the input requirements:
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
// return so it doesn't execute any more of the function
return;
}
// code here will only get called if the `player1Input`
// meets the above critera
// Rest of your code here...
}
Or, you could use an if/else:
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
} else {
// code here will only get called if the `player1Input`
// meets the above critera
// Rest of your code here...
}
}
FYI, there's nothing special here. This is just normal function control flow in Javascript. If you want no more of the function to execution then insert a return statement. Or protect branches of code with an if/else so a condition will control what code executes.

How to get enter key to emulate a button press?

I'm developing a weather app, and I only want the code to execute once the Enter key is pressed or when a user clicks on Submit. The problem is, the code executes whenever any key is pressed, and I'm not sure why? It wouldn't ordinarily be a big deal, but it's requesting the API every time and I only get 60 requests a minute, so two or three searches in that time will reach that limit.
let button = document.querySelector("#button");
let searchBox = document.querySelector("#search-box");
let city = document.querySelector(".city");
let feelsLike = document.querySelector(".feels-like");
let temperature = document.querySelector(".temp");
let weatherDescription = document.querySelector(".weather");
let windSpeed = document.querySelector(".wind");
let icons = document.querySelector(".icons");
searchBox.addEventListener("keypress", function (event) {
if (event.key === "Enter") {
document.getElementById("button").click();
}
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=" +
searchBox.value +
"&units=metric&appid="
)
...Rest of code to be executed
)};
I think it would make sense for the enter key to emulate a button press, but I'm not entirely sure how to do that - and any resources I've used online haven't helped, unfortunately.
In your listener searchBox.addEventListener("keypress", function (event) {..} you're executing the fetch function everytime when a keypress occurs. Since the if-condition does not enclosure the your fetch execution.
Try this:
if (event.key === "Enter") {
document.getElementById("button").click();
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=" +
searchBox.value +
"&units=metric&appid="
)
}
You should put the (fetch) logic in the click handler for the button.
Some other points:
If you need code to execute after you get the response from your fetch, then put that code in a chained then callback. Note that the promise that fetch returns, resolves to a response object, and you'll need to call one of its methods to get yet another promise back, which in turn will resolve to the actual data.
Don't call .click(). It is better to put the targeted code in a named function, and then call that function both here, and in the button's click handler.
You already had a variable for the button, so no need to call again getElemebtById.
function process() {
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=" +
searchBox.value +
"&units=metric&appid="
).then(function (response) {
return response.json(); // <-- maybe? or .text() ?
}).then(function (data) {
//...Rest of code to be executed
});
});
button.addEventListener("click", process);
searchBox.addEventListener("keypress", function (event) {
if (event.key === "Enter") process();
)};
As stated by Amacado, the fetch is outside the if.
Moreover, if the search box is actually an HTML <input type="search"> element, there is already an OnSearch event handler that takes account of both the enter key and the magnifying glass icon in the phone keyboard (search event).

DataTable. How to stop a search.dt event from being fired from inside the event handler

I have this code, and when I detect the filter typed by the user contains some bad characters like ' I don't want it to reach the Server.
I have this simplified code:
$table.on('search.dt', function () {
var value = getValue();
if (antiHackingHelper.isValid(value)) {
} else { // Contains charakter like "'" so don't call the server with this bad filter
// Don't send the request to the server with a filter with bad characters
}
});
You cannot prevent the search from being performed at this point. search.dt is already broadcasted at the time your $table.on('search.dt' listener... is executed, and it is not part of a chain where you can cancel the search "upstream".
Instead you could prevent illegal characters from being entered in the filter box in the first place :
var illegalChars = "',.-*)(";
$('.dataTables_filter input').on('keypress', function(e) {
if (~illegalChars.indexOf(String.fromCharCode(e.keyCode))) {
console.log('Illegal char entered, aborting');
return false;
}
})
demo -> http://jsfiddle.net/q39c3c0k/

Ajax call inside a timeout function getting called multiple times

I'm using this great piece of javascript (http://www.deadosaurus.com/detect-a-usb-barcode-scanner-with-javascript/) to recognize USB barcode scanners input (just really fast typed keyboard strokes) without having the focus on any input field in a website. The thing works great as it is, but what I need to do is to figure out if the scanned item is of type A or type B before I can do anything with the scan result, and that is where the Ajax-call comes into play like this:
$(document).ready(function() {
var pressed = false;
var chars = [];
$(window).keypress(function(e) {
if (e.which >= 48 && e.which <= 57) {
chars.push(String.fromCharCode(e.which));
}
console.log(e.which + ":" + chars.join("|"));
if (pressed == false) {
setTimeout(function(){
if (chars.length >= 10) {
var barcode = chars.join("");
console.log("Barcode Scanned: " + barcode);
// Here is the ajax-call.
checkItemType(barCode).success(function(response) {
// Do stuff with the response.
});
}
chars = [];
pressed = false;
},500);
}
pressed = true;
});
});
And the function:
function checkItemType(barCode) {
// Example parsing for the id I want to do work with.
var itemId = parseInt(barCode.substr(9, 6).replace(/^[ 0]/g, ''));
var data = { itemId: itemId };
return $.ajax({
type: 'POST',
url: 'Controller/CheckItemType',
traditional: true,
dataType: 'json',
data: data
});
}
For the first time when I scan the item, all things work fine. The second time I do a scan, the checkItemType-function gets called 2x and the third time it gets called 4x, usually capping at 8x.
I just cant get my head around this.. there is a if-clause for chars.length >= 10 and the chars list should clear out after the barcode scanners input stops. Removing the ajax-call fixes the issue as I said before, but I am unable to really figure out a way to make the call outside of the timeout function. Guess I should add that I'm still learning javascript and I'm really out of ideas for this one. Thanks in advance.
EDIT: Success code didn't really matter so removed it as suggested.
The bug you describe sounds like some other place in your code binds the handler again.
Do you somehow reload some portion of your page (maybe through ajax), which could trigger the $(window).keypress( ... ) binding a second time ?
I've had a look at the code and think I've got it fixed. I've simply added chars = []; pressed = false; after you have created the barcode and it then resets after a barcode is scanned. Have a look below:
JSFiddle
if (pressed === false) {
setTimeout(function () {
console.log("Timeout");
if (chars.length >= 10) {
var barcode = chars.join("");
chars = [];
pressed = false;
console.log("Barcode Scanned: " + barcode);
// Here is the ajax-call.
checkItemType(barCode).success(function (response) {
// Do stuff with the response.
});
}
chars = [];
pressed = false;
}, 500);
}
pressed = true;
I would say it is a timing/synchronization issue. You setup for each event/keystroke a timeout in 500 ms: that means that after 500 ms from the first keystroke you start to run your (first) function: chars.length > 10 and then while you do the Ajax call (because it is slow) the second timeout fires: chars.length is still > 10 so you go and run again checkItemType... and so on until the first call will set the chars = [].
The number of times checkItemType si executed is related to the delay between the keystrokes and the time to run checkItemType. If you only reset chars = [] after you check it for >= 10 you still can't be sure then the second timeout didn't already passed that condition.
One way to be sure that you run checkItemType only once would be to have only one timeout set on the first keystroke and then if chars.lenngth < 10 when it fires set it up again to run in another x ms...etc.
if (pressed == false) -> if(!pressed) or if(pressed === false)

javascripts works when I step through doesnt if I dont

Has anyone found that their javascript doesnt work, but when they step through the code it works fine ?
var cookie = getCookie('lusr');
var username = cookie;
if(!cookie){
$("#UserNav").load("loginform.html");
$("#loginbtn").click( function(){
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username,password);
});
}else{
$("#UserNav").load("user.htm");
$("#WelcomeUser").text("Welcome "+ username);
}
My issue occurs on this line :
$("#WelcomeUser").text("Welcome "+ username);
That's because load() is asynchronous: it returns right away, performs its work in the background, then calls a user-provided function when its task is complete. The stepping delay gives you the illusion that the function is synchronous and performs all its work before returning.
Therefore, you should pass a callback function to load() and perform your subsequent work inside that callback:
var cookie = getCookie("lusr");
if(!cookie) {
$("#UserNav").load("loginform.html", function() {
$("#loginbtn").click(function() {
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username, password);
});
});
} else {
$("#UserNav").load("user.htm", function() {
$("#WelcomeUser").text("Welcome " + cookie);
});
}
You are using the load() function which asynchronously fetches from the server. This means your form has not loaded by the time you go searching for its fields.
The reason it works when you step through is because it gives it time to load the form while you step.
You can use another version of load which has an asynchonous callback function, allowing you to provide functionality only to be called once the load is complete.
Check the jQuery docs for more info.

Categories