Javascript prompt alternative in Loop - javascript

So, instead of a prompt, I could use an <input type="text"> and a button to do stuff with the values of the input on button click, for example:
var x = [];
$('button').on('click', function(){
x.push($(input[type="text"]).val());
});
However, in a loop for example:
var y=0;
var z=[];
do {
z.push(prompt('input value'));
y++;
}
while (y<5);
The loop would prompt for a value, user inputs value, prompt assigns value to array, then the loop would prompt again until y reaches 5.
Instead of a prompt, I'd like to do this with my text field input and button. How can I get the loop to pause, wait for user to input text, and submit by clicking button, every time it reaches that part of the loop?
Edit: The pushing of 5 values into the array was just an example. Let's say I wanted to create a game where the loop would move up with an "up" and down with a "down" input. I want to be able to request user input during the loop, similar to how the prompt would do it, but without using prompts.

You don't. You completely change your logic, losing the loop entirely:
var z = [];
$('button').on('click', function() {
z.push($(input[type="text"]).val());
if (z.length === 5) {
// Do what you would have done after the end of the loop here
}
});
You've edited the question and commented below that what you do next might vary depending on the input. That's not a problem, you just apply the event-response model to your new requirement. For instance, you said
...Let's say I wanted to create a game where the loop would move up with an "up" and down with a "down" input.
Then:
$('button').on('click', function() {
switch ($(input[type="text"]).val().toLowerCase()) {
case "up":
// Do the "up" thing
break;
case "down":
// Do the "down" thing
break;
}
});
There are several different ways you might handle dispatching, not necessarily a switch. For instance:
var actions = {
up: function() {
// Do the "up" thing
},
down: function() {
// Do the "down" thing
}
};
$('button').on('click', function() {
var action = actions[$(input[type="text"]).val().toLowerCase();
if (action) {
action();
}
});
And so on. The key is that instead of working iteratively (I do this, I get that input, I do the next thing, I get more input), you're working reactively: I get input, I do something. That might require some kind of state management (remembering where you are) beyond what's shown above (the first example has state management: We check the length of z to see how many inputs we've collected).

Related

How can I reuse the same key for different things in javascript canvas?

In the canvas I want to be able to use the enter key to do one thing and then press it again to do another thing.
For example,
if(enterPressed) {
// do one thing
}
if (enterPressed) {
//Do some other thing
}
The problem is when I press enter once it automatically does both things at once whereas I want it to want it do each statement separately.
For more context what I want to do is similar to the style of text in pokemon games where the game will display some text then wait until you have pressed a button and then display the next set of text.
Your question is not specific to JavaScript or Canvas, but related more to general programming techniques. What you describe is different states of your program, rather than 2 actions that are done as a reaction to an event.
So think your program consist of multiple states:
Displayed first text to user -> Displayed second text to user
You will switch between these states based on certain actions user takes, in your case when they hit enter. There're many ways to hold program states, and switch between these ones, but one of the easiest ones I can give an example is, holding your text in an array and an index value that holds which one is the current index:
var currentIndex = 0;
var texts = ["This is first message", "This is second message"]
if (enterPressed) {
//you need to have boundary checks of course, skipping for simplicity
displayText(texts[currentIndex])
currentIndex++;
}
This is one way to hold the state of the program and switch between those states based on the user action.
The example code in the question has two statements in a row which I assume is how you want to handle enterPressed
To have a second (or third and more) action you will need to store the state of the enter actions. eg Is this the first press?
// this in the setup code.
var enterAction = "firstPress"
Then each time enterPressed is handled you must also check the state so that the correct action happens.
if (enterPressed && enterAction === "firstPress") {
When you handle the action you also set up the next state to be handled. Because you have two statements in a row that both check if enterPressed is true you need to also indicate that you have handled the press. This can just be setting enterPressed = false
enterAction = "secondPress";
enterPressed = false;
}
Thus you code would look like
// Init the first enter state
const FIRST = 1, SECOND = 2;
var enterAction = FIRST;
And replacing the questions code with
// Handling first press
if (enterPressed && enterAction === FIRST) {
enterAction = SECOND; // set action for next press
enterPressed = false; // clear press to indicate its been handled
// do one thing
}
// Handling second press
if (enterPressed && enterAction === SECOND) {
enterAction = FIRST; // set action for next press
enterPressed = false; // clear press to indicate its been handled
//Do some other thing
}

Only allow number to be entered once in input

Is there any way of using javascript/jquery to prevent a user entering the same number twice in an input box? The user can enter as many numbers as they want (one at a time), but I need to alert the user/take other action if they try to enter the same number a second time. I have tried creating an array:
function history() {
var numbers = [];
numbers.push(document.getElementById('inputBox').value);
}
and then running:
var n = document.getElementById('inputBox').value;
if ($.inArray(n, numbers)> -1) {
// alert, do something
}
but the new array ('numbers') never gets populated by the user input, so the if clause never fires.
Something like this, perhaps? I assume you are using jQuery because of the $.inArray in your code.
var numbers = [];
$('#inputBox').change(function () {
if ($.inArray($(this).val(), numbers)) {
// Alert the user/take other action
} else {
// Otherwise, add it to the array of numbers
numbers.push($(this).val());
}
});
It would be better if there was a button the user had to click to add the new number. Otherwise, it will be quite annoying.
It looks like your numbers variable is scoped to the history() function, so the numbers variable instanced that is being set is only accessibly by the history() function. This code will accomplish what you're trying to do without a global numbers variable and prevents any duplicate numbers from being entered by intercepting and canceling the key event.
$("#inputBox").on("keydown", function(e) {
var numbers = $(this).val();
var c = String.fromCharCode(e.keyCode);
return ~numbers.indexOf(c);
});

Jquery text change event

I need to fire an event anytime the content of a textbox has changed.
I cant use keyup nor can I use keypress.
Keyup and keydown doesn't work if you hold down on the key.
Keypress triggers before the text has actually changed. It doesn't recognize backspace or delete either.
So now I'm assuming I'm going to have to build some custom logic or download a plugin. Are there any plugins out there? Or if I should build one, what constraints should I look out for?
For eg. Facebook does it with their search at the top. you can press and hold.
another example is writing a stackoverflow question. Right below the editor, the contents are copied in real time, backspace and everythng works. How do they do it?
I just took a look at SO's source. It looks like they do something a lot like this:
function updatePreview(){
$('div').text($('textarea').val());
}
$('textarea').bind('keypress', function(){
setTimeout(updatePreview, 1);
}
);​
They do some extra stuff to make HTML tags for bold and italics and links and such and they time it. They increase the delay from 1 to longer if it takes too long to generate the HTML.
I had success using jQuery (in Chrome). If you hold a key down, it counts every change, not just the first one, and it counts non-print keys like backspace.
HTML
<input id="txt" type="text" />
<span id="changeCount">0</span>
JavaScript
$('#txt').keydown(function(event) {
// Don't count the keys which don't actually change
// the text. The four below are the arrow keys, but
// there are more that I omitted for brevity.
if (event.which != 37 && event.which != 38 &&
event.which != 39 && event.which != 40) {
// Replace the two lines below with whatever you want to
// do when the text changes.
var count = parseInt($('#changeCount').text(), 10) + 1;
$('#changeCount').text(count);
}
});
Like I said above, you'll want to filter out all of the key codes that don't change the text, like ctrl, shift, alt, enter, etc. There's also the boundary condition if you press the backspace or delete key when the textbox is empty or if the textbox has a maximum length and a printable key is pressed, but it's not terribly difficult to handle those either.
Here's a working jsfiddle example.
How about a poll? Do a setInterval and call a function that checks the text say every 500ms? You don't want to detect content change on every key anyway because it gets kinda slow in some older browser/older computer and you would notice a lag between typing and the text displaying.
You need a watcher type functionality.
It resorts to setInterval polling if the other features are not available: http://james.padolsey.com/javascript/monitoring-dom-properties/
I have a simple solution that we use happily in one of our project.
you can try it # http://jsfiddle.net/zSFdp/17/
var i = 0;
$('#text').bind('check_changed', function(){
var t = $(this);
// do something after certain interval, for better performance
delayRun('my_text', function(){
var pv = t.data('prev_val');
// if previous value is undefined or not equals to the current value then blablabla
if(pv == undefined || pv != t.val()){
$('#count').html(++i);
t.data('prev_val', t.val());
}
}, 1000);
})
// if the textbox is changed via typing
.keydown(function(){$(this).trigger('check_changed')})
// if the textbox is changed via 'paste' action from mouse context menu
.bind('paste', function(){$(this).trigger('check_changed')});
// clicking the flush button can force all pending functions to be run immediately
// e.g., if you want to submit the form, all delayed functions or validations should be called before submitting.
// delayRun.flush() is the method for this purpose
$('#flush').click(function(){ delayRun.flush(); });
The delayRun() function
;(function(g){
var delayRuns = {};
var allFuncs = {};
g.delayRun = function(id, func, delay){
if(delay == undefined) delay = 200;
if(delayRuns[id] != null){
clearTimeout(delayRuns[id]);
delete delayRuns[id];
delete allFuncs[id];
}
allFuncs[id] = func;
delayRuns[id] = setTimeout(function(){
func();
delete allFuncs[id];
delete delayRuns[id];
}, delay);
};
g.delayRun.flush = function(){
for(var i in delayRuns){
if(delayRuns.hasOwnProperty(i)){
clearTimeout(delayRuns[i]);
allFuncs[i]();
delete delayRuns[i];
delete allFuncs[i];
}
}
};
})(window);
Zurb has a great plugin which might be useful for you
http://www.zurb.com/playground/jquery-text-change-custom-event

ExtJS listening for global keystrokes with Ext.KeyMap

To polish up an application im developing I am adding keyboard shortcuts for common tasks. I can sue Ext.KeyMap to do this like so...
var map = new Ext.KeyMap("my-element", {
key: 13, // or Ext.EventObject.ENTER
fn: myHandler,
scope: myObject
});
But I want to detect "ss" or "qq" i.e. specific double key strokes of letters. Im not sure how to do this....
My idea is to detect the singular keystroke, add a listener to detect a following key stroke. And to handle the gap between them, set a delayed event that deletes the listener after x amount of time.
Any improvements/suggestions/warnings??
I'm not sure why you would need an additional listener here. Why not store the previous keystroke in a variable (with the timestamp when the keystroke occurred). Then you could just compare the latest keystroke to the previous keystroke. If they are the same, and the timestamp stored is not too far in the past, that's the double key you're after. If the key codes are not the same, or stored timestamp is too old, just update the stored keycode and timestamp with new values.
You don't have to remember all the keys pressed, just the last one. When you think at the double click event, it's similar, but since clicking two times is more popular, it's already implemented for us.
Something like this:
function defineDoubleKeyMap(element, cfg) {
var repeated, timer;
return new Ext.KeyMap(element, {
key: cfg.key,
fn: function() {
if (repeated) {
// when clicked the second time
// stop timer and call our callback
repeated = false;
clearTimeout(timer);
cfg.fn.call(cfg.scope);
}
else {
// remember we clicked once, forget after delay
repeated = true;
// adjust the delay as needed.
// current 1 sec is probably too long
timer = (function(){
repeated = false;
}).defer(1000);
}
}
});
}
defineDoubleKeyMap("my-element", {
key: Ext.EventObject.ENTER,
fn: myHandle,
scope: myObject
});
The probem with this code is that pressing quickly ENTER-DELETE-ENTER will also fire the event as if ENTER-ENTER was pressed. If that's not acceptable, then you have to keep track of all the keypresses - I think you'll have to use Ext.get("my-element").on("keypress") for that.

Mootools Shift-Tab Event Problem

Im using the most recent moo release and trying to write a function that evaluates the user given expression on event "keyup". As soon as my test's are passing I put the focus on the next input element automatically to improve the user experience and speed, since he uses the form many times.
So I came up with something like that:
var getNextInputElement = function(element){
returns the next input element
}
var checkDay = function(event){
var input = $('booking_day').get('value');
if (input.length > 1 && input < 32) {
$('booking_day').erase('class');
if (!(event.key == "tab")) {
getNextInputElement($('booking_day')).focus();
}
else {
$('booking_day').focus();
}
}
else if(input.length > 1) {
$('booking_day').set('class','error');
}
else {
$('booking_day').erase('class');
}
};
window.addEvent('domready', function() {
$('new_booking').reset();
$('booking_day').addEvent('keyup', checkDay);
$('booking_day').focus();
});
Works fine so far. But if I try to "shift-tab" back to my input field
getNextInputElement($('booking_day')).focus();
is evaluated and focus reset to the next input field. So the user cannot roll back to previosly entered data. I do not find any possibility to catch that shift-tab event. Since two keys are pressed, there are two events fired. One for "tab" and a second one, but not for "shift". The event.key.code of this event seems to be outside the scope that mootools realizes.
Anyone out there who can help on this problem?
Thanks.
Jason
You can add event for both "Shift+Tab" keys
Link : http://mootools.net/docs/more/Interface/Keyboard

Categories