CSSE 290 Web Programming
Lecture 19: More events, Ajax intro
Reading: 11.1, 12.1
Attribution:Except where otherwise noted, the contents of this document are
Copyright 2012 Marty Stepp, Jessica Miller, and Victoria Kirst. All rights reserved.
Any redistribution, reproduction, transmission, or storage of part
or all of the contents in any form is prohibited without the author's
expressed written permission.
Otherwise noted: Claude Anderson was given permission to modify the slides for CSSE 290 at Rose-Hulman by author Jessica Miller.
The authors' original slides, based on Web Programming Step by Step, can be seen at http://webstepbook.com.
Some of the examples in some days' slides are from David Fisher at Rose-Hulman, who was kind enough to allow me to use them.
My intention is to mark these examples with [DSF].
11.1: Event-Handling
-
11.1: Event-Handling
- 11.1.1 The Event Object
- 11.1.2 Mouse Events
- 11.1.3 Keyboard and Text Events
- 11.1.4 Form Events
- 11.1.5 Page Events
- 11.1.6 Timer Events
-
11.2: Case Study: Multiplication Quiz
JavaScript events
-
the
click
event (onclick
) is just one of many events that can be handled
-
problem: events are tricky and have incompatibilities across browsers
-
reasons: fuzzy W3C event specs; IE disobeying web standards; etc.
-
solution: Prototype includes many event-related features and fixes
Attaching event handlers the Prototype way
element.onevent = function;
element.observe("event", function);
$("play").observe("click", playNewGame);
-
to use Prototype's event features, you must attach the handler using the DOM element object's
observe
method (added by Prototype)
-
pass the event name as a string, and the function name to call
-
handlers must be attached this way for Prototype's event features to work
The event
object
function name(event) {
}
-
Event handlers can accept an optional parameter to represent the event that is occurring. Event objects have the following properties / methods:
method / property name
|
description
|
type
|
what kind of event, such as "click" or "mousedown"
|
element() *
|
the element on which the event occurred
|
stop() **
|
cancels an event
|
stopObserving()
|
removes an event handler
|
-
* replaces non-standard
srcElement
and which
properties
-
** replaces non-standard
return false;
, stopPropagation
, etc.
Mouse events
clicking
click
|
user presses/releases mouse button on the element
|
dblclick
|
user presses/releases mouse button twice on the element
|
mousedown
|
user presses down mouse button on the element
|
mouseup
|
user releases mouse button on the element
|
movement
mouseover
|
mouse cursor enters the element's box
|
mouseout
|
mouse cursor exits the element's box
|
mousemove
|
mouse cursor moves around within the element's box
|
Mouse event objects
The event
passed to a mouse handler has these properties:
property/method
|
description
|
clientX , clientY
|
coordinates in browser window
|
screenX , screenY
|
coordinates in screen
|
offsetX , offsetY
|
coordinates in element (non-standard)
|
pointerX() ,
pointerY() *
|
coordinates in entire web page
|
isLeftClick() **
|
true if left button was pressed
|
-
* replaces non-standard properties
pageX
and pageY
-
** replaces non-standard properties
button
and which
Mouse event example
<pre id="target">Move the mouse over me!</pre>
window.onload = function() {
$("target").observe("mousemove", showCoords);
};
function showCoords(event) {
$("target").innerHTML =
"pointer: (" + event.pointerX() + ", " + event.pointerY() + ")\n"
+ "screen : (" + event.screenX + ", " + event.screenY + ")\n"
+ "client : (" + event.clientX + ", " + event.clientY + ")";
}
The keyword this
this.fieldName
this.fieldName = value;
this.methodName(parameters);
-
all JavaScript code actually runs inside of an object
-
by default, code runs in the global
window
object (so this
=== window
)
-
all global variables and functions you declare become part of
window
-
the
this
keyword refers to the current object
Event handler binding
- event handlers attached unobtrusively are bound to the element
- inside the handler, that element becomes
this
(rather than the window
)
Fixing redundant code with this
<fieldset>
<label><input type="radio" name="ducks" value="Huey" /> Huey</label>
<label><input type="radio" name="ducks" value="Dewey" /> Dewey</label>
<label><input type="radio" name="ducks" value="Louie" /> Louie</label>
</fieldset>
function processDucks() {
if ($("huey").checked) {
alert("Huey is checked!");
} else if ($("dewey").checked) {
alert("Dewey is checked!");
} else {
alert("Louie is checked!");
}
alert(this.value + " is checked!");
}
- if the same function is assigned to multiple elements, each gets its own bound copy
Page/window events
name | description |
load ,
unload
|
the browser loads/exits the page
|
resize
|
the browser window is resized
|
error
|
an error occurs when loading a document or an image
|
contextmenu
|
the user right-clicks to pop up a context menu
|
-
The above can be handled on the
window
object. An alternative to window.onload
:
window.onload = function() { ... };
document.observe("dom:loaded", function() {
});
Keyboard/text events
name |
description |
keydown
|
user presses a key while this element has keyboard focus
|
keyup
|
user releases a key while this element has keyboard focus
|
keypress
|
user presses and releases a key while this element has keyboard focus
|
focus
|
this element gains keyboard focus
|
blur
|
this element loses keyboard focus
|
select
|
this element's text is selected or deselected)
|
-
focus: the attention of the user's keyboard (given to one element at a time)
Key event objects
property name
|
description
|
keyCode
|
ASCII integer value of key that was pressed
(convert to char with String.fromCharCode )
|
altKey , ctrlKey , shiftKey
|
true if Alt/Ctrl/Shift key is being held
|
Prototype's key code constants
Event.KEY_BACKSPACE
|
Event.KEY_DELETE
|
Event.KEY_DOWN
|
Event.KEY_END
|
Event.KEY_ESC
|
Event.KEY_HOME
|
Event.KEY_LEFT
|
Event.KEY_PAGEDOWN
|
Event.KEY_PAGEUP
|
Event.KEY_RETURN
|
Event.KEY_RIGHT
|
Event.KEY_TAB
|
Event.KEY_UP
|
|
|
|
-
issue: if the event you attach your listener to doesn't have the focus, you won't hear the event
-
possible solution: attach key listener to entire page body, outer element, etc.
Form events
event name
|
description
|
submit
|
form is being submitted
|
reset
|
form is being reset
|
change
|
the text or state of a form control has changed
|
-
Prototype adds the following methods to form controls' DOM objects:
Prototype form shortcuts
$F("formID")["name"]
-
gets parameter with given name from form with given id
$F("controlID")
Stopping an event
<form id="exampleform" action="http://foo.com/foo.php">...</form>
window.onload = function() {
$("exampleform").observe("submit", checkData);
};
function checkData(event) {
if ($F("city") == "" || $F("state").length != 2) {
alert("Error, invalid city/state.");
event.stop();
return false;
}
}
- to abort a form submit or other event, call Prototype's
stop
method on the event
12.1: Ajax Concepts
-
12.1: Ajax Concepts
-
12.2: Using XMLHttpRequest
-
12.3: XML
-
12.4: JSON
Synchronous web communication
- synchronous: user must wait while new pages load
-
the typical communication pattern used in web pages (click, wait, refresh)
-
web application: a dynamic web site that mimics the feel of a desktop app
-
Ajax: Asynchronous JavaScript and XML
- not a programming language; a particular way of using JavaScript
- downloads data from server in the background
- allows dynamic updates of page without making user wait
- avoids "click-wait-refresh" pattern
- Concept developed gradually in late 1990's and early 2000's
- First called "Ajax" in 2005
Asynchronous web communication
- asynchronous: user keeps interacting with page while new data loads
-
communication pattern made possible by Ajax
- JavaScript includes an
XMLHttpRequest
object that can fetch files from a web server
- supported in IE5+, Safari, Firefox, Opera, Chrome, etc. (with minor incompatibilities)
- it can do this asynchronously (in the background, transparent to user)
- the contents of the fetched file can be put into current web page using the DOM
- sounds great!...
- ... but it is clunky to use, and has various browser incompatibilities
- Prototype provides a better wrapper for Ajax, so we will use that instead
A typical Ajax request
- user clicks, invoking an event handler
- handler's code creates an
XMLHttpRequest
object
XMLHttpRequest
object requests info from server
- server retrieves appropriate data, sends it back
XMLHttpRequest
fires an event when data arrives
- we attach a handler function to this event (callback)
- callback event handler processes the data and displays it
An aside: Creating a new anonymous object
var name = {
fieldName: value,
...
fieldName: value
};
var p = {
x: 4,
y: 3,
distanceFromOrigin: function() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
};
alert(p.x + ", " + p.y + ", dist=" + p.distanceFromOrigin());
- in JavaScript, you can create a new object without creating a class
- the object can have methods (function properties) that refer to itself as
this
Prototype's Ajax model
new Ajax.Request("url", {
option : value,
option : value,
...
option : value
});
- construct a Prototype
Ajax.Request
object to request a page from a server using Ajax
- constructor accepts 2 parameters:
- the URL to fetch, as a String,
-
a set of options, as a set of key : value pairs in
{}
braces
(an anonymous JavaScript object)
- hides messy details of the raw
XMLHttpRequest
; works well in all browsers
Prototype options
option |
description |
method
|
how to fetch the request from the server (default "post" )
|
asynchronous
|
should request be sent asynchronously in the background? (default true , for good reasons)
|
parameters
|
query parameters to pass to the server, if any (as a string or object)
|
onSuccess
|
event: request completed successfully
|
onFailure
|
event: request was unsuccessful
|
onException
|
event: request has a syntax error, security error, etc.
|
others: contentType , encoding ,
requestHeaders ; events: onCreate , onComplete ,
on### (for HTTP error code ###, example on404)
|
Prototype Ajax example
new Ajax.Request("foo/bar/mydata.txt", {
method: "get",
onSuccess: myAjaxSuccessFunction
});
...
function myAjaxSuccessFunction(ajax) {
do something with ajax.responseText
;
}
- attach an event handler function to the request's
onSuccess
event
- the handler takes an Ajax response object as a parameter, which we'll name
ajax
property |
description |
status
|
the request's HTTP result code (200 = OK, etc.)
|
statusText
|
HTTP status code text
|
responseText
|
the entire text of the fetched file, as a string
|
responseXML ,
responseJSON
|
the entire contents of the fetched file, in other formats (seen later)
|
function myAjaxSuccessFunction(ajax) {
alert(ajax.responseText);
}
- most commonly used property is
responseText
, to access the fetched text content
Handling Ajax errors
new Ajax.Request("url", {
method: "get",
onSuccess: functionName,
onFailure: ajaxFailure,
onException: ajaxFailure
});
...
function ajaxFailure(ajax, exception) {
alert("Error making Ajax request:" +
"\n\nServer status:\n" + ajax.status +
" " + ajax.statusText +
"\n\nServer response text:\n" + ajax.responseText);
if (exception) {
throw exception;
}
}
- for user's (and developer's) benefit, show an error message if a request fails
Passing query parameters to a request
new Ajax.Request("lookup_account.php", {
method: "get",
parameters: {name: "Ed Smith", age: 29, password: "abcdef"},
onFailure: ajaxFailure,
onException: ajaxFailure
});
...
- don't concatenate the parameters onto the URL yourself with
"?" +
...
- won't properly URL-encode the parameters
- won't work for POST requests
- query parameters are passed as a
parameters
object, {}
braces with name : value pairs
- (the above is equivalent to:
"name=Ed+Smith&age=29&password=abcdef"
)
Creating a POST
request
new Ajax.Request("url", {
method: "post",
parameters: {name: value, name: value, ..., name: value},
onSuccess: functionName,
onFailure: functionName,
onException: functionName
});
method
should be changed to "post"
(or omitted; post
is default)