Home:ALL Converter>Javascript event handling and flow control

Javascript event handling and flow control

Ask Time:2009-08-21T23:06:12         Author:intelligencer

Json Formatter

I'm attempting to build a webpage that loads depending on the input provided. I'm having some trouble wrapping my head around event handling in javascript, basically. Coming from python, if I wanted to wait for a specific keyboard input before moving on to the next object to display, I would create a while loop and put a key listener inside it.

Python:

def getInput():
  while 1:
    for event in pygame.event.get(): #returns a list of events from the keyboard/mouse
      if event.type == KEYDOWN:
        if event.key == "enter": # for example
          do function()
          return
        elif event.key == "up":
          do function2()
          continue
        else: continue # for clarity

In trying to find a way to implement this in DOM/javascript, I seem to just crash the page (I assume due to the While Loop), but I presume this is because my event handling is poorly written. Also, registering event handlers with "element.onkeydown = function;" difficult for me to wrap my head around, and setInterval(foo(), interval] hasn't brought me much success.

Basically, I want a "listening" loop to do a certain behavior for key X, but to break when key Y is hit.

Author:intelligencer,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/1312524/javascript-event-handling-and-flow-control
Joel :

Any good browser will crash when it encounters a script that runs too long. This is to prevent malicious websites from locking up the client application.\n\nYou cannot have a infinite loop in javascript. Instead, attach an event listener to the window and point do your processing in the handler (think of it as interrupts instead of polling).\n\nExample:\n\nfunction addEventSimple(obj,evt,fn) {\n if (obj.addEventListener)\n obj.addEventListener(evt,fn,false);\n else if (obj.attachEvent)\n obj.attachEvent('on'+evt,fn);\n} // method pulled from quirksmode.org for cross-browser compatibility\n\naddEventSimple(window, \"keydown\", function(e) {\n // check keys\n});\n",
2009-08-21T15:13:50
TJ L :

document.onkeydown = function(e) {\n //do what you need to do\n}\n\n\nThat's all it takes in javascript. You don't need to loop to wait for the event to happen, whenever the event occurs that function will be called, which in turn can call other functions, do whatever needs to be be done. Think of it as that instead of you having to wait for the event your looking for to happen, the event your looking for will let you know when it happens. ",
2009-08-21T15:14:18
stefita :

you could attach an event listener to the window object like this\n\nwindow.captureEvents(Event.KEYPRESS);\nwindow.onkeypress = output;\nfunction output(event) {\n alert(\"you pressed\" + event.which);\n}\n",
2009-08-21T15:14:36
bobince :

In JavaScript, you give up control of the main loop. The browser runs the main loop and calls back down into your code when an event or timeout/interval occurs. You have to handle the event and then return so that the browser can get on with doing other things, firing events, and so on.\n\nSo you cannot have a ‘listening’ loop. The browser does that for you, giving you the event and letting you deal with it, but once you've finished handling the event you must return. You can't fall back into a different loop. This means you can't write step-by-step procedural code; if you have state that persists between event calls you must store it, eg. in a variable.\n\nThis approach cannot work:\n\n<input type=\"text\" readonly=\"readonly\" value=\"\" id=\"status\" />\n\nvar s= document.getElementById('status');\ns.value= 'Press A now';\nwhile (true) {\n var e= eventLoop.nextKeyEvent(); // THERE IS NO SUCH THING AS THIS\n if (e.which=='a')\n break\n}\ns.value= 'Press Y or N';\nwhile (true) {\n var e= eventLoop.nextKeyEvent();\n if (e.which=='y') ...\n\n\nStep-by-step code has to be turned inside out so that the browser calls down to you, instead of you calling up to the browser:\n\nvar state= 0;\nfunction keypressed(event) {\n var key= String.fromCharCode(event? event.which : window.event.keyCode); // IE compatibility\n switch (state) {\n case 0:\n if (key=='a') {\n s.value= 'Press Y or N';\n state++;\n }\n break;\n case 1:\n if (key=='y') ...\n break;\n }\n}\n\ns.value= 'Press A now';\ndocument.onkeypress= keypressed;\n\n\nYou can also make code look a little more linear and clean up some of the state stuff by using nested anonymous functions:\n\ns.value= 'Press A now';\ndocument.onkeypress= function(event) {\n var key= String.fromCharCode(event? event.which : window.event.keyCode);\n if (key=='a') {\n s.value= 'Press Y or N';\n document.onkeypress= function(event) {\n var key= String.fromCharCode(event? event.which : window.event.keyCode);\n if (key=='y') ...\n };\n }\n};\n",
2009-08-21T15:35:10
Niko :

you should not use such loops in javascript. basically you do not want to block the browser from doing its job. Thus you work with events (onkeyup/down).\n\nalso instead of a loop you should use setTimeout if you want to wait a little and continue if something happened\n\nyou can do sth like that:\n\n<html>\n<script>\nvar dataToLoad = new Array('data1', 'data2', 'data3' );\nvar pos = 0;\nfunction continueData(ev) {\n // do whatever checks you need about key\n var ele = document.getElementById(\"mydata\");\n if (pos < dataToLoad.length)\n {\n ele.appendChild(document.createTextNode(dataToLoad[pos]));\n pos++;\n }\n}\n</script>\n<body onkeyup=\"continueData()\"><div id=\"mydata\"></div></body></html>\n\n\neverytime a key is released the next data field is appended",
2009-08-21T15:13:36
Lonecat :

For easier implementation of event handling I recommend you to use a library such as Prototype or Jquery (Note that both links take you to their respective Event handling documentation.\n\nIn order to use them you have to keep in mind 3 things:\n\n\nWhat DOM element you want to observe\nWhat Event you want to capture\nWhat action will the event trigger\n\n\nThis three points are mutually inclusive, meaning you need to take care of the 3 when writing the code.\n\nSo having this in mind, using Prototype, you could do this:\n\nEvent.observe($('id_of_the_element_to_observe'), 'keypress', function(ev) {\n // the argument ev is the event object that has some useful information such\n // as which keycode was pressed.\n code_to_run;\n});\n\n\nHere is the code of a more useful example, a CharacterCounter (such as the one found in Twitter, but surely a lot less reliable ;) ):\n\nvar CharacterCounter = Class.create({\n\n initialize: function(input, counter, max_chars) {\n this.input = input;\n this.counter = counter;\n this.max_chars = max_chars;\n Event.observe(this.input, 'keypress', this.keyPressHandler.bind(this));\n Event.observe(this.input, 'keyup', this.keyUpHandler.bind(this));\n },\n\n keyUpHandler: function() {\n words_left = this.max_chars - $F(this.input).length;\n this.counter.innerHTML = words_left;\n },\n\n keyPressHandler: function(e) {\n words_left = this.max_chars - $F(this.input).length;\n if (words_left <= 0 && this.allowedChars(e.keyCode)) {\n e.stop();\n }\n },\n\n allowedChars: function(keycode) {\n // 8: backspace, 37-40: arrow keys, 46: delete\n allowed_keycodes = [ 8, 37, 38, 39, 40, 46 ];\n if (allowed_keycodes.include(keycode)) {\n return false;\n }\n return true\n }\n\n});\n",
2009-08-21T15:39:07
yy