In this exercise, we will be practicing our accuracy by pulling out tiny parts of an HTML page.
Using the above HTML, only JavaScript, and the shortest most accurate selectors, attempt the following:
1. Highlight just the word putative in green.
2. Highlight just the word incondite in red.
3. Highlight just the word paronomasia in pink.
4. Highlight just the word sobriquet in purple.
5. Highlight just the word lascivious, but not the word anomie in grey.
6. Highlight just the word opprobrium in orange.
There are two ways to tackle this. The first and simplest would be to change the order of the questions, so by tackling question 4 first we get:
Let's look at how to put things on the page.
.html()
The html method lets us replace the contents of an element with our own code.
For example:
$('p').html('I ate all your paragraphs');
will replace the contents of every paragraph tag with the string 'I ate all your paragraphs'.
.append()
The Append Method appends code to the end of an element:
$('p').append('...');
.prepend()
The prepend method is similar to the append method, but adds the code at the start:
$('p').prepend('here it comes: ');
.before() and .after()
We also have before and after. These add your code outside the element, before and after respectively.
Events
Events are the basis of interactivity. Every time something happens on the page, from a page scroll to a mouse movement, to a keystroke, to an image load, an event is fired by the browser. JavaScript can detect these events and perform functions in response to them.
Handlers
A function that is called in response to an event is called an event handler, or sometimes just a handler. we tell the browser which handlers should respond to which events by binding them. We say that the handler is bound to the event.
Binding Events to Handlers
JQuery offers a very easy way to bind common handlers to browser events. Observe:
HTML
<!DOCTYPE html>
<html>
<head>
<title>Event Binding</title>
<script src="jquery-1.5.js"></script>
<script src="binding.js"></script>
</head>
<body>
<p class="clickable">Don't Click Me</p>
</body>
</html>
JavaScript - binding.js
$(function() {
$(".clickable").click(function() {
alert("you clicked it");
});
});
Here we've simply passed the click function to a handler. The first part is as we've seen so far:
$(function() {
$(".clickable").click();
});
We're detecting the click event on any paragraph, but there wouldn't be much point in doing this if we didn't pass the click event a function to execute when the click event occurs:
function() {
alert("you clicked it");
});
The paragraph click was the event. This is the handler.
Getting information about the event.
Sometimes we need to know a little more about the event. If this is the case, we can tell our event handler to receive an event object, which we can query. We do this like so:
$(function() {
$(".clickable").click(function(e) {
alert("mouse position: " + e.screenX + " : " + e.screenY);
});
})
Here the handler has received an object called e, which is an event object. We can query the event object in a number of ways. Here we are outputting the x and y position of the mouse at the time when the click took place.
Getting information about the DOM node the event happened to
We can also get access to the object (usually a DOM node) that the event happened to. This DOM node is bound to the "this" variable. Let's say that we bind a handler to more than one DOM node like so:
HTML
<!DOCTYPE html>
<html>
<head>
<title>Event Binding</title>
<script src="jquery-1.5.js"></script>
<script src="binding.js"></script>
</head>
<body>
<p class="clickable">Don't Click Me</p>
<p class="clickable">Do Click Me</p>
</body>
</html>
Here we have two paragraphs with the same class "clickable" Now let's do some binding:
JavaScript - binding.js:
$(function() {
$(".clickable").click(function(e) {
alert($(this).html());
});
})
This time we are alerting:
$(this).html()
Within handlers, "this" refers to the DOM node that the event happened to. Here we call .html() on it, which returns the element's inner html.
If we click on the first paragraph, "Don't Click Me" appears in an alert box. If we click the second "Do Click Me" appears in the alert box.
There are many different events that we can bind. Some of the more useful ones are:
dblclick: Fires when a double-click event occurs.
keyup: Fires when a key is released. Use this in forms to validate input.
focus: Fires when a form element gains focus. You could use this to show context-sensitive help.
Each Peach
JQuery selectors return an array of DOM nodes. This means that with a single selector, you can pull out all the paragraphs on the page, or all the hyperlinks with a particular class. When we apply methods to a jQuery object, we are generally working on all of the DOM nodes at the same time. This is part of the power of jQuery. For example.
$('p').hide();
will hide every single paragraph on the page without exception. It applies to hide to all paragraphs. The selector returns all the paragraphs as an array of DOM nodes, then the hide method iterates over all of the paragraphs, hiding them.
A selector may return just one DOM node, and this is fine, but it will still return it in an array with just one item:
$('.page_header h1')
will likely only match one item on the page, but it is still returned in an array. This common interface makes things very simple for us, provided we want to do exactly the same thing to every matched DOM node, but what if things aren't so simple.
Iterating with Each
What if we want to treat each element as a special case. What if we want to do a different thing to each element.
Fortunately, jQuery gives a really simple way to iterate over our elements one at a time using the .each function. .each accepts a function, and then applies the function to the nodes one at a time, passing in the node itself as "this".
Here we use each to create the beginnings of an image gallery:
HTML
<!DOCTYPE html>
<html>
<head>
<title>Each</title>
<script src="jquery-1.5.js"></script>
<script src="each.js"></script>
</head>
<body>
<img src="kitten.jpg" alt="kitten" />
<img src="puppy.png" alt="puppy" />
<img src="lemur.gif" alt="lemur" />
</body>
</html>
This HTML file contains three images, each of which has an alt attribute. For each image, we're going to pull out the alt attribute, pop it in a span, and put that after the image.
JavaScript - each.js
$(function() {
$("img").each(function() {
var img = $(this);
var alt_text = img.attr('alt');
img.after("<span>" + alt_text + "</span>");
});
});
Here we select every image on the page, then iterate over the resulting array using each. Each receives a function, and the function has access to the DOM node via the "this" variable. We convert "this" into a jQuery object, pull out the alt text, then append the alt text after the image.
Each Peach Exercises
We use each to iterate over a jQuery object, performing an action on each one in turn. Let's try that now
A big mess
You can generate a random integer between 0 and 500 using the following code:
Math.random() * 500
You can generate a jQuery object that contains everything on the page inside the body element like so:
$('body *');
Write a jQuery function that iterates over everything on the page using each, makes them all position:absolute, and assigns random top and left values. You need to use each here to give them all different random values.
JQuery UI
The jQuery UI library is a customizable, themeable series of extensions to jQuery that allow you to implement complex user interface features remarkably quickly. There are interactions, such as drag and drop, useful widgets that decorate your existing markup providing new features and commonly used effects that go beyond the basic jQuery effects.
Getting jQuery UI
jQuery UI comes in a big, custom-made bundle that is tailored to your specific project. You decide which parts of the library you'd like to use, and it constructs a bundle for you containing minified JavaScript code, CSS, and image files. You might find this loss of control disconcerting at first, as it does so much for you, but don't worry, it works well and in general, does things reasonably sensibly.
To download a copy visit http://jqueryui.com/ and click on "download". You'll be prompted to choose a subset of the library to get, the version of jQuery you're using, and a theme.
Choosing a theme.
If you'd like to see which themes are available, click "themes" and browse down the left hand side. You can choose a prebuilt theme, or roll your own. If you're using the jQuery UI library, I'd advise you, at least at first, to use the theme builder interface, rather than trying to write your own CSS. The generated markup is complex, and the theme builder saves some time. The generated CSS is very well commented so you can make changes to it later.
What's in the package?
Inside the package are three folders and an index file.
index.html
This file is a demo file. Open it to see examples of many of the widgets in action.
CSS
This folder contains your CSS theme file and any required images. You'll need to import this CSS file in your HTML when you start to code.
development-bundle
This folder contains the complete source code plus documentation. It's interesting to look at, but we won't be using it in our code
js
This folder contains minified copies of jQuery and jQuery UI. These are the JavaScript files you'll need to use. Import them in your header.
Object Orientation with JSON
There are several different syntaxes for declaring objects in JavaScript. Of these, the cleanest and most commonly used is JavaScript Object Notation (JSON), pronounced Jason.
Welcome to JSON
Packaging our code up into JSON gives us several significant advantages:
- It looks pretty.
- It reduces the number of objects in the global namespace.
- It's great for AJAX, smaller than XML, and readily parsable on both the client and server side.
In this series of exercises, we'll write some JSON, create an API and finally add a thin layer of listeners to hook it up to a jQuery User Interface.
JSON looks like this:
var mario = {
description:"Small and jumpy. Likes princesses.",
height: 10,
weight: 3,
speed: 12
}
var bowser = {
description: "Big and green, Hates princesses.",
height: 16,
weight: 6,
speed: 4
}
Here we have defined two objects, one called mario and one called bowser. As you can see, they consist of a series of name-value pairs. We can access the values like so:
alert(mario.description);
We can modify values like so:
mario.description = "Big and smashy, having eaten a mushroom"
We can even add new attributes like so:
mario.can_fly = true;
Objects are useful for keeping things neat and tidy. We have encapsulated all the information about Mario in a single place so it's easy to get at and understand.
Questions
- Enter the above code
- Alert the values of mario.description and bowser.description
- Use Firebug to add a breakpoint. Check the values of the JSON objects in the debugger.
- Add a can_fly attribute to Mario using the dot syntax. Again, check the debugger.
- Create an entry for Luigi. He's a bit thinner than Mario but slightly taller, and he wears a green outfit.
A Rather Dull Mario Game
If we wanted we could write a little Mario game using these objects. Let's create a little function to see who wins in a boss battle:
var boss_battle = function() {
if (mario.speed > bowser.speed) {
alert("Mario has escaped and saved Peach");
} else {
alert("Bowser has stomped all over Mario. Mario is dead.");
}
}
boss_battle();
As we can see, Mario wins. Let's swing the odds a little in Bowser's favour. Bowser can go into a powered-up mode where he swoops from side to side on the screen. We'll call this Bowser Boost.
Let's extend our game a little to add Bowser Boost:
var mario = {
description:"Small and jumpy. Likes princesses.",
height: 10,
weight:3,
speed:12
}
var bowser = {
description:"Big and green, Hates princesses.",
height: 16,
weight: 6,
speed: 4,
boost: 0
}
var boss_battle = function() {
if (mario.speed > bowser.speed + bowser.boost) {
alert("Mario has escaped")
} else {
alert("Bowser has stomped all over Mario")
}
}
boss_battle();
bowser.boost = 20
boss_battle();
Functions within JSON
This is all very well. We have Mario and Bowser objects and a function to compare them, but it seems a little artificial having all our functions scattered all over the place like this. Also, the more functions we have in our global namespace, the more likely it is that they will conflict, and we'll accidentally overwrite something important.
Let's see if we can improve things.
var mario_world = {
mario: {
name:"Mario",
description:"Small and jumpy. Likes princesses.",
celebration: "Mario wins and does a little dance",
height: 10,
weight:3,
speed:12,
attack_power: function() {
return this.weight * this.speed;
}
},
bowser: {
name:"Bowser",
description:"Big and green, Hates princesses.",
celebration: "Bowser wins and does a big roar",
height: 16,
weight: 6,
speed: 4,
boost: 0,
attack_power: function() {
return this.weight * (this.speed + this.boost);
}
},
boss_battle: function(contestant_1, contestant_2) {
alert(contestant_1.name + " vs " + contestant_2.name);
if (contestant_1.attack_power() > contestant_2.attack_power()) {
alert(contestant_1.celebration);
} else {
alert(contestant_2.celebration);
}
}
}
mario_world.boss_battle(mario_world.mario, mario_world.bowser);
As you can see, this entire program is encapsulated within a single object called mario_world. The mario_world object is the only object in the global namespace. the boss_battle function is now an attribute of mario_world, and each contestant has an attack_power function that works out his strength in a battle. The boss_battle function is parameterised, so you can battle any contestant against any other.
We have also written an attack_power function which is implemented by bowser and mario. This calculates the attack power from a series of other parameters.
Because functions are objects, we can assign them as attributes of objects. They're key value pairs, but if you've programmed before, you'll notice they work like methods. We can now call methods on our JSON objects.
What is this?
You might have noticed also that in the attack_power function we use the "this" keyword. We say this.speed and this.boost.
This is a troublesome keyword that trips up even quite advanced JavaScript developers all the time. "this" refers to the context in which the code is currently operating in. In this case, the context is mario (or bowser) and so this refers to these variables. That's because the attack_power function is an attribute of mario. This points to the object the current object is a member of. Your knowledge of JavaScript will be measured by your understanding of scope, and the "this" keyword, so we'll come back to this, but for now, let's make a real game…
But what about the jQuery?
Having defined our API, it's now time to hook it up to a user interface. This is where jQuery comes into it's own.
Extend your HTML page. Create a form. Add two dropdowns, containing the names of the available characters. Ideally populate these dropdowns by querying the API. You may need to adjust your JSON to do this.
Add a "Fight" button that will make those two characters battle.
Welcome to JSON
var mario = {
description:"Small and jumpy. Likes princesses.",
height: 10,
weight: 3,
speed: 12
}
var bowser = {
description: "Big and green, Hates princesses.",
height: 16,
weight: 6,
speed: 4
}
var luigi = {
description: "Best Friend of Mario, fond of green",
height: 18,
weight: 5,
speed: 4
}
alert(mario.description);
alert(bowser.description);
mario.can_fly = true;
alert(mario.can_fly);
Note that we can add the can_fly attribute without declaring it first. Our JSON object is simply extended.
A Rather Dull Mario Game
The first part is a simple extension to our previous JSON exercise. We add an invincible attribute and set it to false. We don't need to initialise this attribute, since undefined is falsey, but it feels neater to give it a starting value. Then we simply extend the check in the boss battle function to look for the invincible attribute.
var mario = {
description: "Small and jumpy. Likes princesses.",
height: 10,
weight: 3,
speed: 12,
invincible: false
}
var bowser = {
description: "Big and green, Hates princesses.",
height: 16,
weight: 6,
speed: 4,
boost: 0
}
var boss_battle = function() {
if ((mario.speed > bowser.speed + bowser.boost) || (mario.invincible)) {
alert("Mario has escaped")
} else {
alert("Bowser has stomped all over Mario")
}
}
boss_battle();
bowser.boost = 20
boss_battle();
mario.invincible = true;
boss_battle();
Lets clean this code up a little
A simple solution to this problem might look something like this:
var mario = {
name: "mario",
attack_power:8
}
var bowser = {
name: "bowser",
attack_power:10
}
var boss_battle = function(contestant_1, contestant_2) {
if (contestant_1.attack_power > contestant_2.attack_power ) {
alert(contestant_1.name + " has won")
} else {
alert(contestant_2.name + " has won")
}
}
boss_battle(mario,bowser);
We have used a simple conditional. Note the duplication of the alert.
An improved version might look something like this:
var mario = {
name: "mario",
attack_power:8
}
var bowser = {
name: "bowser",
attack_power:10
}
var boss_battle = function(contestant_1, contestant_2) {
winner = (contestant_1.attack_power > contestant_2.attack_power ) ? contestant_1 : contestant_2
alert(winner.name + " has won")
}
boss_battle(mario,bowser);
Here we have assigned the winner to a variable using the ternary operator. We can then just call winner.name.
Functions within JSON
Your solution to this task might look something like the following:
var mario_world = {
mario: {
name: "Mario",
description: "Small and jumpy. Likes princesses.",
celebration: "Mario wins and does a little dance",
height: 10,
weight: 3,
speed: 12,
attack_power: function() {
return this.weight * this.speed;
}
},
bowser: {
name: "Bowser",
description: "Big and green, Hates princesses.",
celebration: "Bowser wins and does a big roar",
height: 16,
weight: 6,
speed: 4,
boost: 0,
activate_boost: function() {
this.boost += 5;
},
attack_power: function() {
return this.weight * (this.speed + this.boost);
}
},
peach: {
name:"Peach",
description:"Beloved of Mario.",
celebration: "Peach wins and jumps in the air",
height: 8,
weight:2,
speed:15,
dash_mode: false,
toggle_dash: function() {
this.dash_mode = !this.dash_mode;
},
attack_power: function() {
p = this.weight * this.speed;
if (this.dash_mode) {
p *= 2;
}
return p;
}
},
boss_battle: function(contestant_1, contestant_2) {
return (contestant_1.attack_power() > contestant_2.attack_power() ) ? contestant_1 : contestant_2
}
}
var winner = mario_world.boss_battle(mario_world.mario, mario_world.bowser);
alert(winner.celebration);
mario_world.bowser.activate_boost();
winner = mario_world.boss_battle(mario_world.peach, mario_world.bowser);
alert(winner.celebration);
mario_world.peach.toggle_dash();
winner = mario_world.boss_battle(mario_world.bowser, mario_world.peach);
alert(winner.celebration);
But what about the JQuery
Here's an example of one way you could tackle this exercise. If you have taken a different approach, that's fine.
First we define some html. This is just a skeleton, it will be populated by the JavaScript:
<!DOCTYPE html>
<html>
<head>
<title>Super Mario World 9</title>
<script src="jquery.js"></script>
<script src="script.js"></script>
</head>
<body>
<form>
<select class="character_box" id="char_1"></select>
vs.
<select class="character_box" id="char_2"></select>
<input type="submit" value="Fight!" />
</form>
<p class="victor"></p>
</body>
</html>
Now the JavaScript, Note how the interface code is separated from the code that does the actual work. This is good practice. Notice how we append the characters to the dropdowns, and how we retrieve the characters by using the string values in the option field.
// User Interface
$(function() {
// populate the dropdowns
$.each(mario_world.characters, function(i,el) {
$(".character_box").append("<option value='" + i + "'>" + el.name + "</option>");
});
// add the submit handler
$('form').submit(function() {
char_1 = $('#char_1').val();
char_2 = $('#char_2').val();
winner = mario_world.boss_battle(mario_world.characters[char_1],mario_world.characters[char_2]);
$('.victor').html(winner.celebration)
return false;
})
})
var mario_world = {
characters: {
mario: {
name: "Mario",
description: "Small and jumpy. Likes princesses.",
celebration: "Mario wins and does a little dance",
height: 10,
weight: 3,
speed: 12,
attack_power: function() {
return this.weight * this.speed;
}
},
bowser: {
name: "Bowser",
description: "Big and green, Hates princesses.",
celebration: "Bowser wins and does a big roar",
height: 16,
weight: 6,
speed: 4,
boost: 0,
activate_boost: function() {
this.boost += 5;
},
attack_power: function() {
return this.weight * (this.speed + this.boost);
}
},
peach: {
name:"Peach",
description:"Beloved of Mario.",
celebration: "Peach wins and jumps in the air",
height: 8,
weight:2,
speed:15,
dash_mode: false,
toggle_dash: function() {
this.dash_mode = !this.dash_mode;
},
attack_power: function() {
p = this.weight * this.speed;
if (this.dash_mode) {
p *= 2;
}
return p;
}
}
},
boss_battle: function(contestant_1, contestant_2) {
return (contestant_1.attack_power() > contestant_2.attack_power() ) ? contestant_1 : contestant_2
}
}
Privacy with the Module Pattern
Closure
- Functions are objects and can be declared anywhere.
- If I declare a function within another function, the inner function has access to the local variables of the outer function.
- Normally when a function exits, all it's local variables are destroyed, but…
- If I hang on to the inner function in some way, the local variables of the outer function are still needed by the inner function.
- They are still in scope, so they are not garbage collected.
This is closure in a nutshell. Here's an example:
var outer = function() {
var a = "A Local variable"
var inner = function() {
alert(a)
}
window.fnc = inner
}
outer();
fnc();
When we call outer, we define inner and assign it as an attribute of window (in other words, a global variable) inner persists after outer has excited, so the local variable a is still in scope, and still accessible to inner.
Self Executing Functions
It seems a bit superfluous to have to call outer to create inner. Outer only exists here to define inner, there's no need for it once inner has been made.
If only there was a way to avoid referencing outer. Thankfully there is.
Here we have a self executing function. The function is in braces, and there are braces at the end. We are declaring an unnamed function, then running it straight away, dispensing with the need for outer.
*******************************************************************
What is the Self-Executing Function ?
A self-executing function is a function in JavaScript that doesn’t need to be called for its execution it executes itself as soon as it is created in the JavaScript file. This function does not have a name and is also called an anonymous function. This function is initialized inside a set of round brackets and the parameters can be passed through the round brackets at the end.
Syntax:
(function (parameters) {
// Code block to be executed
})(parameters);
*******************************************************************
(function() {
var a = "A Local variable"
var inner = function() {
alert(a)
}
window.fnc = inner
})()
fnc();
The Module Pattern
We can use the closure created by a self executing function to wrap our code, giving us the option to expose whichever parts of the API we want to, and to keep other parts private. Here we declare mario world within a self executing function.
(function() {}
var mario_world = {
mario: {
name:"Mario",
description:"Small and jumpy. Likes princesses.",
celebration: "Mario wins and does a little dance",
height: 10,
weight:3,
speed:12,
attack_power: function() {
return this.weight * this.speed;
}
},
bowser: {
name:"Bowser",
description:"Big and green, Hates princesses.",
celebration: "Bowser wins and does a big roar",
height: 16,
weight: 6,
speed: 4,
boost: 0,
attack_power: function() {
return this.weight * (this.speed + this.boost);
}
},
boss_battle: function(contestant_1, contestant_2) {
alert(contestant_1.name + " vs " + contestant_2.name);
if (contestant_1.attack_power() > contestant_2.attack_power()) {
alert(contestant_1.celebration);
} else {
alert(contestant_2.celebration);
}
}
}
window.mario_world = mario_world
})()
Writing Plugins
One of the huge strengths of jQuery is it's comfy support for plugins. You can write a plugin in moments to do pretty much anything you like. Plugins range from very complex image galleries, to tiny little scripts that do one thing.
Read more about plugins here:
A typical plugin framework looks like this:
(function( $ ){
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
This is a closure in which we can operate without worrying about the global scope. We add the plugin function to $.fn (pronounced effin'). $.fn is an alias for the jQuery prototype, so any functions we add become accessible to any jQuery object.
The plugin receives a jQuery object in the 'this' variable. You can iterate over this variable using this.each(), making any changes you like to the DOM nodes therein.
In most cases, the plugin should return a jQuery object, usually 'this'. This allows us to chain plugins together with other methods.
Given access to the jQuery element in the this variable, you can in theory do anything you like. Add event handlers to it, make changes, trigger animations, anything you can do in jQuery can be rolled up into a plugin.
Rudify Plugin Exercise
Create a plugin insult that replaces all the html content of an element, and replaces it with a rude comment.
Use it like this:
$('h1').insult();
Ensure your plugin is chainable. You should also be able to do this:
$('h1').insult().css({:color:red});
For bonus points, make your plugin insert a random insult. You can use Math.floor(Math.random() * i) to generate a random integer between 0 and i - 1.
Answers
A typical answer to this problem might look like this:
(function( $ ){
var insults = [
'you have large elbows',
'your ears smell of chips',
'your hat is too big'
]
$.fn.insult = function() {
this.each(function(i, el) {
$(el).html(insults[Math.floor(Math.random()*insults.length)])
})
return this;
};
})( jQuery );
Here we have defined the plugin. Note the insults array is defined as a local variable within the closure. It is defined once, when the plugin is declared, so we avoid computational overhead, and it is private, so no-one else can read it.
Now lets use our plugin:
$(function() {
$('h1').insult();
})
Asynchronous Programming
Human time, network time, and CPU time are very different. Most of the time, our scripts do nothing, but they're not sitting around scratching themselves, they are busy listening.
JavaScript is inherently asynchronous. It has to be because networks connections and human beings are so slow. If our scripts stopped and waited every time an ajax request was made, we would soon get fed up.
Instead, JavaScript allows us to fire, and listen out for events.
We have seen how easy it is to listen for events in jQuery. We can register a click handler for example, simply by calling
$('a').click(function() {
alert('clicked');
}
Here we have registered a hyperlink click handler. It listens to the hyperlinks, and if one fires a 'click' event, the function is called.
But jQuery goes much further than this…
Triggering Events
Events can be triggered in response to user actions, network events, and many other things. Here we hook an event to a timer, allowing us to submit a form at regular intervals. Let's autosave:
$(function() {
$('form.autosave').submit(function() {
// do cool ajax here
$('body').append('<p>saving</p>');
return false;
})
setInterval(function() {$('form').trigger('submit');}, 5000)
})
Here we add a submit listener to the form. This takes over the submission of the form, and instead submits an ajax request, alerting the user.
We can trigger the submit event any time we like using the trigger method:
$('form').trigger('submit');
In the example above we attach the trigger to a timeout, submitting the form every 5 seconds.
Custom Events
Events are identified by a string. Classic ones include "submit", "click", or "mousemove". These events are triggered by the browser.
There is nothing to stop us from using our own string to trigger custom events.
We trigger using .trigger, and we listen out using .bind
<!DOCTYPE html>
<html>
<head>
<script src="jquery.js"></script>
<script src="hello.js"></script>
</head>
<body>
<form>
<input id="number_1" type="text" disabled="true" />
<input id="number_2" type="text" disabled="true" />
<input type="submit" value="Roll!" />
</form>
</body>
</html>
$(function() {
$('form').submit(function() {
number_1 = Math.floor(Math.random() * 5);
number_2 = Math.floor(Math.random() * 5);
$("#number_1").val(number_1);
$("#number_2").val(number_2);
if (number_1 === number_2) {
$(this).trigger('equal', {val:number_1})
};
return false;
});
$('form').bind('equal', function(e, params) {
alert("score: " + params.val)
});
})