Javascript - Waiting for user input (callbacks) - javascript

I've been looking at other questions trying to get my head around callbacks but I just can't make sense of it enough to use in my context. I'm writing a text based game which uses purely text input. When needed, I want the game to ask a question with a varying amount of answers and then wait until a valid response is given. Below is an example that doesn't work but explains what I'm trying to do. Can anyone provide me with any guidance? Thanks.
//main code
pEQUIP = ["foo", "foo", "foo"];
exItem = "ball";
function prompt(numPrompts, callback) {
//waits until user types a number <= numPrompts and presses enter, then returns the valid result entered
}
$('#gametext').append("<p>" + "What slot would you like to use to hold this item?" + "</p>");
//where a function would be stopping the code until a valid answer is given
if (prompt == "1") {
pEQUIP[0] = exItem;
} else if (prompt == "2") {
pEQUIP[1] = exItem;
} else if (prompt == "3") {
pEQUIP[2] = exItem;
}
//Just a quick n dirty way of testing it worked below:
$('#gametext').append("<p>" + pEQUIP[0] + pEQUIP[1] + pEQUIP[2] + "</p>");
//parses user info unsure if this could be used or would have to be copied
$(document).ready(function() {
$(document).keypress(function(key) {
if (key.which === 13 && $('#userinput').is(':focus')) {
var value = $('#userinput').val().toLowerCase();
$('#userinput').val("");
//playerInput(value); Is usually here, would lead to
//a switch which parses commands typed by the user.
//Unsure if it can be used for this problem as pausing
//the code I think would stop the switch?
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="gametext"></div>
<input id="userinput">
</body>

It appears as though you're thinking of functions incorrectly.
Functions are:
A series of steps that may return data when they're invoked. You
invoke a function by passing arguments to the function name, even if
the arguments are nothing () - a.e. alert(string) or myFunction()
Not comparable to anything but themselves. In your code you have prompt == "1" this isn't going to work. prompt is a function name and it isn't invoked so you are literally comparing the function itself to the string "1".
Able to return data when invoked. That data can be compared.
Note: Also, very importantly, prompt is the name of a default function(like alert or console) and you shouldn't overwrite it. It isn't considered a reserved keyword by the language but altering it will cause havok if any other library you're using, or any other programmer doesn't know it's been overwritten, and tries to invoke it.
prompt("this is a normal prompt");
Furthermore you have the document setup to check the value of the text box itself on keypress. You should probably change this to an event listener on the text box, but there isn't any reason to continuously loop a function beyond this while waiting for the box to match some predefined input.
The Flow is this:
type in the box
hit enter
check value
if value is 1 or 2 or 3 or any other acceptable answer do something
If that's all you need currently then you do not need to work so hard for the functionality when a single event listener could do the trick:
$("#input_box").on("keypress", function(e) {
if(e.keyCode === 13) {
let value = $("#input_box").val();
if(value === "1" || value === "2" || value === "3") {
//do whatever
}
}
});
$("#input_box").on("keypress", function(e) {
if(e.keyCode === 13) {
let value = $("#input_box").val();
if(value === "1" || value === "2" || value === "3") {
console.log("accepted");
}
$("#input_box").val("");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="input_box">

Related

If-causes with boolean in javascript (Beginners)

Is there a possibility to write this "If" more efficient?
if((text.val(“Hello“) == false)&& (text.val(“This“) == true)&&(text.val(“Is“) == false)&&(text).val(“Me“) == false))
{
text = "This"
}
This “if“ should check, whether a value is set true or not. It should display only the “true“ one. If I make it in this way, I have to make a lot of If’s in order to have all possibilities. Is there a way to make it more efficient and better? In database all values are boolean.
To test for one of multiple conditions you could use:
var txt = text.val();
switch(txt){
case "Hello":
case "This":
case "Is":
case "Me":
case "Whatever Else":
text.val("This");
break;
}
This will allow you to test very simply for multiple conditions and respond accordingly. In this case it will return true is any of these conditions are true. To require all would be:
if (txt=="This" && txt=="Hello" && txt=="Is" && txt=="Me"){...}
This is the only way to test that all conditions are true, unless you want to use arrays and a true-false marker.
I think you might be confused as to how .val() works. If the parameter is left empty, it returns the value. If it has a parameter, it sets the value. (jQuery API Documentation) If I read your if statement correctly, it will only execute if the value of the text is equal to "This". This could be simplified by the following:
if(text.val() == “This“) {
text.val("This");
}
In case you wanted your statement rewritten, here is how it might look:
if((text.val() != “Hello“) && (text.val() == “This“) && (text.val() != “Is“) && (text).val() != “Me“))
{
text.val("This");
}
I would also recommend looking through the documentation in link above and even looking through W3Schools.com
This is an efficient way without jQuery or other library:
var text = "Hello This Is Me";
var textSplit = text.split(' ');
var count = textSplit.length;
for(i=0;i<=count;i++){
if(textSplit[i] == 'This'){
text = 'This';
alert(text);
break;
}
}

JavaScript "if" statement wont run

(Using Javascript)
If I enter text in the textbox or not, the alert will not come up.
I know this is a simple fix but I can not figure it out!
(This is for learning purposes.)
Workout Log Test
<script type="text/javascript">
function myResults() {
myExercise();
myWeight();
mySets();
myReps();
myFunction();
}
function myExercise() {
var txtExercise = document.getElementById("txtExercise");
var txtOutput = document.getElementById("txtOutput1");
var name = txtExercise.value;
txtOutput1.value = "You destroyed, " + name + "!"
if (txtExercise.length === 0) {
alert ('Do you even lift?');
return;
First off, you're checking the "length" property of the element rather than the value of the input.
Second of all, you're checking against an integer value. If you were to simply read the value of the element, you're going to get text.
I'm guessing, what you want is something like:
var exercise = parseInt(txtExercise.value, 10);
if(exercise === 0) {
alert('Do you even lift?');
return;
}
But that's assuming txtExercise is an input element. Without seeing your markup, it's hard to be sure that any given answer will work.
Here you go, all fixed. You need an event handler, and this is a better if/else use case.
http://codepen.io/davidwickman/pen/vOKjqV
// Check the .value.length instead of just the .length
if (txtExercise.value.length === 0) {
alert('Bro, do you even lift?');
} else {
txtOutput1.value = "You destroyed, " + name + "!";
}
Assuming you have closed the function and if statement properly, you are missing a semi colon just before the if statement.
txtOutput1.value = "You destroyed, " + name + "!"; <---- here

Simple arithmetic challenge function with limited attempts

Recently began studying Javascript, trying to read out of Javascript: The Definitive Guide and Eloquent Javascript, while going off on my own to experiment with things in order to really etch them in my memory. I thought a good way to get my head around arithmetic operations and conditional statements, I'd build a series of little games based around each Math operator, and began with addition.
function beginAdditionChallenge() {
var x = Math.ceiling(Math.random()*100);
alert(x);
for (var i = 0; i < 3; i++) {
var a = Number(prompt("Provide the first addend.", ""));
var b = Number(prompt("Provide the second addend.", ""));
if (a + b === x) {
alert("Well done!");
break;
}
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
else {
alert("Fail.");
}
}
}
function initChallenge() {
var button = document.getElementById("challengeButton");
button.addEventListener("click", beginAdditionChallenge);
}
window.addEventListener("load", initChallenge);
You can see the whole thing thus far on JSFiddle, here. The idea is that clicking the button generates a random number between 1 and 100, displays it to the user, then prompts them to provide two addends, giving them 3 attempts. If the sum of these addends is equal to the RNG number, it congratulates the user and ends the program. If they do not provide suitable addends, the loop prompts them to try again, until they've hit 3 attempts, at which point the program snarks at them and ends.
I know the event listener is not the failure point here, as when I change beginAdditionChallenge to simply display a test alert, it works, but I don't know what exactly is wrong with the loop I've created.
You did it correctly. However, Math.ceiling isn't a function and should be Math.ceil. In addition, your code (in jsfiddle) should be set to wrap in head. Why? Because right now you call initChallenge when the page loads. However, in your jsfiddle example, the code runs onLoad so the load event never gets called. Essentially, you're adding a load event after the page has loaded.
http://jsfiddle.net/rNn32/
Edit: In addition, you have a for loop that goes up to three. Therefore
else if (a + b !== x && i < 3) {
alert("Please try again.");
}
should be
else if (a + b !== x && i < 2) {
alert("Please try again.");
}
because when i === 2, the user's last chance has ended.
Everything is fine. Just change:-
var x = Math.ceiling(Math.random()*100);
to:-
var x = Math.ceil(Math.random()*100);

Checking textbox if it's empty in Javascript

I wrote a simple html file with a textbox and submit button, and it generates and document.write's a response dependant on what you submit. I want to have it generate a response saying to enter content if the box is empty. The textbox's id is chatinput, so I have the following the code in the beginning
var chatinput_box=document.getElementById('chatinput');
var chatinput=chatinput_box.value;
Then a have a conditional, although I can't get it to work correctly; I've tried
if(chatinput==""){}
if(chatinput.length=0){}
if(chatinput=null){}
and others but none have worked correctly. Does anyone have another idea?
It should be this:
var chatinput = document.getElementById("chatinput").value;
if (chatinput == "" || chatinput.length == 0 || chatinput == null)
{
// Invalid... Box is empty
}
Or shorthanded:
if (!document.getElementById("chatinput").value)
{
// Invalid... Box is empty
}
The = assigns a value whereas == checks whether the values are equal.
Just offering an alternative, not trying to steal thunder ...
Create an isEmpty function to reuse on a variety of items.
function isEmpty(val){
return ((val !== '') && (val !== undefined) && (val.length > 0) && (val !== null));
}
Then you can apply it to whatever element you want:
if(!isEmpty(chatinput)){
// hooray its got a value!
}
Not exactly original, its the concept stolen from PHP, but it comes in handy a lot.

What is the most efficient way of toggling a DOM elements value based on the state of another element?

Imagine we have a text field that executes the code below on each keydown event:
if( $('#my_input').val() == '' )
$('#my_span').html('my input is blank');
else
$('#my_span').html('My input is not blank');
Obviously we are executing code that possibly sets the state of something (#my_span element) to what it already is and this seems inefficient. But I am curious as to what the alternative is? Adding more checks like:
if ( $('#my_input').val() == '' ){
if ( $('#my_span').html() != 'my input is blank' )
$('#my_span').html('my input is blank');
}
else if ( $('#my_span').html() != 'My input is not blank' )
$('#myspan').html('My input is not blank');
Is the latter more efficient? It would seem to me more 'correct', but obviously it's more code and I'm not sure how much more efficient it is than the first example.
I know that the former always involves a DOM manipulation, which will factor in computing the relative efficiency, but I've encountered situations like this before in non-DOM related code, so wondering what is the best approach in all cases. Should you always do the extra check on the value of something before setting it to a new value?
EDIT:
My final version actually uses a combination of the answers here so thanks to all for the great replies. So to sum, I now:
Cache the jquery objects in a closure
Uses state to determine the assignment to a new state
Also as an aside, the setTimeout on the keydown is a very nice way to get a input fields value immediately. Thanks again.
I would cache the jQuery objects and use a boolean to store the state and not call html when you don't have to :
(function(){
var i = $('#my_input'), s=$('#my_span'), blank, check = function() {
if (i.val()=='') {
if (blank!==true) s.html('my input is blank');
blank = true;
} else {
if (blank!==false) s.html('my input is not blank');
blank = false;
}
};
i.keyup(check);
check(); // so that the span is initially filled
})();
Note that what you need isn't keydown but keyup, so that the value of the input is changed before you get the event.
This method even works if you keep pressing the key ;)
Performance? Go Pure JS. Fiddle
//before event binding
var my_input = document.getElementById('my_input'),
my_span = document.getElementById('my_span');
$(my_input).on('keydown', function () {
//inside event handler
var value = my_input.value
, prevVal = my_input.prevVal
;
if (value && prevVal && prevVal !== value) {
return;
}
//timeout to return event handler execution early
//(ie: differ DOM manipulation from the event handler.
//So, UX will extra smooth ;) )
setTimeout(function () {
fieldStatusUpdater(my_input.value);
}, 1);
});
function fieldStatusUpdater(value) {
if (my_input.value === '') {
my_span.innerHTML = 'my input is blank';
} else {
my_span.innerHTML = 'My input is not blank';
}
my_input.prevVal = value;
}
This is the fastest and nicest I can come up with:
function keyUpEvent(){
var state = null,
input = $('#my_input'),
span = $('#my_span');
return function(){
var test = input.val() === '';
if( test === state) return;
if(test)
span.html('my input is blank');
else
span.html('My input is not blank');
state = test;
}
}
$('#my_input').keyup(keyUpEvent());
http://jsfiddle.net/TMb8T/
This uses closures to store the input and span elements after initialization. And you can use it (almost) as if its a normal function, so u can bind it do multiple events and it still works.
Note that you have to execute keyUpEvent when you bind the event.
Addition:
You can now also do something like this:
function keyUpEvent(input, span){
var state = null;
return function(){
var test = input.val() === '';
if( test === state) return;
if(test)
span.html('My input is blank');
else
span.html('My input is not blank');
state = test;
}
}
$('#my_input').keyup( keyUpEvent($('#my_input'), $('#my_span')) );
$('#my_input2').keyup( keyUpEvent($('#my_input2'), $('#my_span2')) );
http://jsfiddle.net/TMb8T/2/
Like this you can easily check every input of a whole form with one single event handler.
Addition 2: If you want to make version 2 work even when the key is kept down ;)
Replace this:
$('#my_input').keyup( keyUpEvent($('#my_input'), $('#my_span')) );
With this:
$('#my_input').keydown(function(){
setTimeout(keyUpEvent($('#my_input'), $('#my_span')),1);
});
http://jsfiddle.net/TMb8T/4/
It really depends on how often you are executing the code. If it executes only when the user presses a button or something like that it would be fine to use the first one, it it runs on a quick timer then it might not.
Do like this:
var text;
if ( $('#my_input').val() == '' )
text = 'my input is blank';
else
text = 'My input is not blank';
if ( $(#my_span).html() != text )
$('#my_span').html(text);
Init:
var isBlank = true;
$('#my_span').html('my input is blank');
keyup:
if(!isBlank){
if( $('#my_input').val().length == 0){
isBlank = true;
$('#my_span').html('my input is blank');
}
} else {
if($('#my_input').val().length){
isBlank = false;
$('#my_span').html('my input is not blank');
}
}
This way you are only manipulating the DOM if the state changes.
Also testing the length property may actually be faster than testing the string against "", because the interpreter won't have to create a String object from the string literal.
You can simplify it with a ternary
$('#my_span').html( $('#my_input').val() == '' ? 'my input is blank' : 'My input is not blank' );
More readable
var text = $('#my_input').val() == '' ? 'my input is blank' : 'My input is not blank';
$('#my_span').html(text);
And it you care about speed, it comes up is a DOM redraw faster that reading content. That really will depend on the page strucutre/size,browser. JSPerf is your friend if you want to see how many milliseconds you will save with 1000's of iterations. You really should be looking for the fastest if you see a performance problem.
No Check, Writing content
You have the penalty of updating the DOM if data changed or did not change
Check, Writing content
You have the penalty of reading the HTML
You have penalty of updating DOM
Check, no write needed
You have the penalty of reading the HTML
Now Is the HTML most likely going to be different, the same, etc?
The solution depends on what you want to do. Caching the jQuery element will speed up the lookup/write. It will be slower than just a write.
How about saving the current value to a variable and just testing the variable to see if you have to change it. No messing with the DOM until you need to change it. (You could also use a boolean named isBlank to get good effect here):
var currValue;
if ( $('#my_input').val() == '' ) {
if ( currValue != 'my input is blank' ) {
currValue = 'my input is blank';
$('#my_span').html(currValue);
}
} else if ( currValue != 'My input is not blank' ) {
currValue = 'My input is not blank';
$('#my_span').html(currValue);
}
You also mentioned this is in the keydown event handler.
Don't forget to run this code one time at the start so it sets the display field to show the input field is blank to start with.
Don't forget that the user can select the text and right click to choose 'cut' and empty the field or choose 'paste' to add text to the field. Similarly, a drag and drop action can conceivably add or remove text.
Alternate Train of Thought
You might be better off with periodic, timed event that checks. Some people can type bursts of keys around 3 or 4 a second. If you timed it to look at the field every 1 second, you could cut down the short term slowdown due to this code running and replace it with a long term constant use of CPU cycles. But remember that there is no reason to not use CPU cycles if the computer isn't doing anything interesting.

Categories

Resources