Frage

I want to add an unobtrusive event handler to a button using javascript with prototype. I'm written a very simple HTML example below where there are two buttons. The first button has the onclick added to it within the HTML. The second button has the id "googleButton" that should have an event handler attached to it in my javascript. I have tried many different forms of attaching the event handler and all of them are throwing errors. I can get this kind of thing to work very easily in jQuery, maybe I'm missing something about the prototype syntax?

Here's the HTML:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Assignment 10 - Part 1</title>
        <script src="./js/prototype.js" type="text/javascript"></script>
        <script src="./js/scriptaculous/scriptaculous.js?load=effects,controls" type="text/javascript"></script>
        <script src="./js/assignment10p1.js" type="text/javascript"></script>
        <link rel="stylesheet" type="text/css" href="css/style.css" />
    </head>
    <body>
        <fieldset>
            <legend>City Search</legend>
            <label for="cityName1">Enter a city name: </label>
            <input type="text" id="cityName1">
            <input type="button" value="Google City" onclick='googleSearch("cityName1")'>
            <input id="googleButton" type="button" value="Google City">
            <div id="cityAutoComplete" class="autocomplete"></div>
        </fieldset>   
    </body>
</html>

Here's the javascript:

var cities = ["Aachen", "Aalborg", "Aarhus", "Abbeville", "Abbot", "Abbotsford",
              "Aberdeen", "Abernathy", "Acadia", "Acampo", "Acra", "Adams", "Addison",
              "Addy", "Adrian", "Agate", "Agua Caliente", "Aiken", "Ainsworth",
              "Akron", "Alamo", "Alba", "Albany", "Alberta", "Alden", "Alta", "Amboy",
              "Amherst", "Anchorage", "Anderson", "Andover", "Appleton", "Arcadia", 
              "Ardmore", "Argyle", "Arlington", "Arthur", "Ashburn", "Ashland", 
              "Ashton", "Athens", "Atlanta", "Auburn", "Aurora", "Austin", "Aztec",
              "Bagwell", "Bailey", "Bainbridge Island", "Baker", "Bakersfield", 
              "Baldwin", "Ballard", "Baltic", "Bangkok", "Banner", "Barcelona",
              "Barlow", "Barnesville", "Barnum", "Barrington", "Bartlett", "Barton",
              "Batesville", "Bath", "Battle Creek", "Baxter", "Bay City", "Beach", 
              "Bear Creek", "Beaumont", "Beaver", "Bedford", "Belcourt", "Belfast",
              "Belgium", "Bellingham", "Bellevue", "Belmont", "Belvidere", "Benson",
              "Berkley", "Berlin", "Bethany", "Beverly", "Big Bear", "Biggs", 
              "Billings", "Bingham", "Birmingham", "Bishop", "Blackfoot", "Blain",
              "Bloomfield", "Bloomington", "Blue Springs", "Boggs", 
              "Boiling Springs", "Boise", "Bolton", "Boston", "Bradford", "Bremerton",
              "Brooklyn", "Brooks", "Brunswick", "Brussels", "Buffalo", "Burbank",
              "Burlington", "Butte", "Byron"];

function googleSearch(id) {
    var city = $(id).value;
    window.location.href="http://www.google.com/search?q=" + city;
}

document.observe("dom:loaded", function() {
    new Autocompleter.Local("cityName1", "cityAutoComplete", cities);
});

// This should add the event handler
$('googleButton').observe('click', googleSearch('cityName1'));

Here's the error firebug gives:

TypeError: $(...) is null
$('googleButton').observe('click', googleSearch('cityName1'));

Sorry this is a repost, I deleted the previous question thinking I'd found the problem, but it persists. Others had commented that I needed to do it like this:

$('#googleButton').observe('click', googleSearch('cityName1'));

But that's jQuery syntax, not prototype. Another person said it should be working and that's all I heard. Other than the libraries loaded above this is literally the full example.

War es hilfreich?

Lösung

There are two issues:

First, you're hooking up the handler wrong. This code:

$('googleButton').observe('click', googleSearch('cityName1'));

calls googleSearch immediately, passing in 'cityName1', and passes the return value into observe, exactly the way foo(bar()) calls bar and passes its return value into foo. That should be:

$('googleButton').observe('click', function() {
    googleSearch('cityName1');
});

...or

$('googleButton').observe('click', googleSearch.curry('cityName1'));

...which basically does the above, but using Prototype's Function#curry.

With either of those, we pass a function into observe that, when called, will call googleSearch passing in 'cityName1'.

Second, scripts run immediately when they're encountered in the HTML (unless you use the defer or async attributes, which modify the behavior). Since the script is above the markup for the element in the HTML, the element doesn't exist yet when you're trying to get access to it.

If you move that code into your dom:loaded callback above it, it should work.

Alternately, you can just move your scripts to the end of the HTML, just before the closing </body> tag, as is usually the recommendation. Then you can do away with dom:loaded; all of the elements defined by the markup above the script exist by the time it runs.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top