News

Learning JavaScript: Arrays and functions

Learn web programming basics with this practical look at making function calls and passing in essential variable data

javascriptlogo

In this article we’re going to introduce you to functions and arrays. We’re also going to see a bit more of the browser’s document object model (DOM) and how it can be leveraged using JavaScript. And, not to disappoint you, we’re going to build something cool with everything that you learn: a revolving photo slideshow page.

Let’s first take a look at the slideshow page so you understand what we’re going to build. You might have seen a few of these on hipper sites across the web. They usually consist of a full-screen image used in the background, with text placed over the image. Often these automatically, or by user input, switch between a set of images. These types of pages are being used for homepages, on photo sites and even as album cover viewers, complete with background audio (we’ll look at audio later in the series when we cover HTML5 APIs).

Download the accompanying tutorial files and  open the file ‘slideshow.html’ to see the completed example. Does it look like this would be complicated to build? Not at all! We’ll supply all the code and instruction you need.

tools | tech | trends: Text editor (eg Dreamweaver, TextMate, NotePad or equivalent) plus web browser
experts: Elisabeth Robson, Eric Freeman
tutorial files: download here

01. The HTML markup

We’ll start with a simple HTML page. The body contains two <div>s, the first of which will be used for the page background (lines 8-9), and a second <div> that is used to hold the descriptive text that will be placed on top of the background (lines 10-11).

001 <!doctype html>
002 <html>
003 <head>
004 <title>Beautiful Food Photo Slideshow</title>
005 <meta charset="utf-8">
006 <link rel="stylesheet" href="slideshow. css">
007 <script src="slideshow.js"></script>
008 </head>
009 <body>
010 <div>
011     <img id="one">
012     <img id="two">
013 </div>
014 <div id="description">
015 </div>
016 </body>
017 </html>

02. Add the images

Now add two images to the divs; we’ll need both of these to smoothly fade one image out as we fade another in (we’ll get to the fading effect in a bit). If you’re used to HTML you might have noticed there are no src attributes in the <img> tags (lines 2, 3), and that’s because we’re going to specify the image sources, dynamically, with JavaScript.

001 <div>
002     <img id="one">
003     <img id="two">
004     </div>

03. Add the JavaScript

Rather than placing JavaScript code directly into this page, we’ll use the <script> element’s src attribute to point to the file slideshow.js (line 4), where we’ll write the code. This lets us keep our HTML and JavaScript separate, which is often more maintainable and readable. It’s important that you specify a closing </script> tag or you’ll get unwanted behaviour from some browsers.

001 <head>
002 <title>Beautiful Food Photo Slideshow</title>
003 <meta charset="utf-8">
004 <script src="slideshow.js"></script>
005 </head>

04. Add the CSS

Add a link to a CSS file named slideshow.css (line 4), which uses some newer features of CSS3 to handle the visual transition from image to image; we’ll take a closer look at the CSS next.

001 <head>
002 <title>Beautiful Food Photo Slideshow</title>                    
003 <meta charset="utf-8">
004 <link rel="stylesheet" href="slideshow.css">                    
005 <script src="slideshow.js"></script>
006 </head>

05. Make the photos full screen

In slideshow.css first make sure the photo <div> fills the entire screen (lines 1-6), and position it (lines 7-9). Then set the images to fill the entire screen, and make sure they are sized appropriately for any browser window size, by setting the min-width and min-height properties of the image to 100% (lines 9-10), setting the width and height to auto (lines 12-13), and positioning them (lines 15-17).

001 html, body, div.photo {
002     width: 100%;                         
003     padding: 0px;
004         margin: 0px;
005 }
006         position: relative;
007 }
008 img {
009         min-width: 100%;
010         min-width: 100%;
011
012         width: auto;
013         height: auto;
014
015         position: fixed;
016         top: 0px;
017         left: 0px;
018 }

06. Handle the transitions

To handle the fade in/out between the images, we’re using a CSS3 property, transition (lines 9-14) to affect the opacity of the photo. We’re specifying the opacity in the img.transparent rule, so the transition will happen when an element has the class ‘transparent’. In the img.transparent rule, we specify an opacity of 0 (in other words, completely transparent). That means whenever we add the class transparent to an image, the transition will be applied and the image will transition from fully opaque to fully transparent over one second. The easing method – ease-in-out – specifies that the transition should happen in a gentle, slow start and finishing manner. We’ll be setting the class of the image using JavaScript so we can control when this fading transition occurs.

001 img {
002    min-width: 100%;
003    min-height: 100%;
004    width: auto;
005    height: auto;
006    position: fixed;
007    top: 0px;
008    left: 0px;
009    // We still need browser-specific versions of the transition, be careful to use this ordering
010    -webkit-transition: opacity 1s ease-in-out;
011    -moz-transition: opacity 1s ease-in-out;
012    -o-transition: opacity 1s ease-in-out;
013    -ms-transition: opacity 1s ease-in-out;
014    transition: opacity 1s ease-in-out;
015 }
016 img.transparent {
017    opacity: 0;
018 }

07. Style the description

Now position the description <div> so it sits on top of the photo near the bottom-left of the screen.

001 div#description {
002    position: absolute;
003    font-family: Helvetica, sans-serif;
004    font-size: 600%;
005    font-weight: bold;
006    color: white;
007    text-shadow: 1px 1px 3px #373737;
008    left: 30px;
009    bottom: 30px;
010 }

08. Create arrays to hold image names and text

Now that you’ve created the HTML and CSS, you need to add the behaviour using JavaScript. First you’re going to define a set of images with corresponding descriptions, and to do that we’ll use a data type called an array. You’ll create two arrays: one to hold the image names for the photos, and the second to hold the string description we’ll display on top of each photo.

001 var photos = [
002    "images/Pears.jpg",
003    "images/Salad.jpg",
004    "images/Cauliflower.jpg"
005 ];
006 var descriptions = [
007    "Asian Pears",
008    "Spinach Salad",
009    "Romanesque Cauliflower"
010 ];

09. Set the Image src attribute with JS

Now you’re ready to use the arrays to set the src images of the <img> elements in the HTML. To do that you’ll use document.getElementById() to get an <img> element and then set its src. Here we’ve initially set the src of the first image to the value of item 0 in the photos array, which is the string images/Pears.jpg.

001 var img = document.getElementById("one");
002 img.src = photos[0];

10. Loading the code

In the previous tutorial we wrote the code in a <script> element in the body of the page, and that code ran as the browser loaded the HTML page. This time around, we’re going to include a JavaScript file from the <head> of the page. When doing this, a potential problem can occur when the browser begins evaluating JavaScript in the <head> element before it has read the rest of the page; this is because the DOM hasn’t fully been constructed.

11. Write a function

To fix this we need to ensure that the code isn’t executed until the rest of the page has been fully loaded. To do that you can place the code in a function, as detailed below:

001 function init() {
002    var img = document.getElementById("one");
003    img.src = photos[0];
004 }

Note that by defining a function, what you’re actually doing is packaging up this code so that you can reference it by the name init (see the boxout to the left for more on functions). Any time that you call init(), the code defined in its body (the code between the curly braces) is evaluated.

12. The window.onload property

So, how do you get your JavaScript to wait until the page is fully loaded before the init function is called? You use the window.onload property, which is available in every browser. If you assign the property to a function, then that function will be called once (and only once) the page has been fully loaded (and the DOM created), which is exactly what we want. Here’s how to set the window.onload property:

001 function init() {
002    var img = document.getElementById("one");
003    img.src = photos[0];
004 }
005 window.onload = init;

Make sure you type ‘init’, not ‘init()’, on line 5. Why? Because you aren’t calling this function, you’re leaving it up to the browser to call it once the page is loaded.
Try loading the page now, and you should see a photo appear in the browser window.

13. Add the descriptive text

At this point, you’ve got an image displayed, but what about the description? To display the description, we need to get the <div> element with the id ‘description’ from the DOM (line 4), and then set its content, using the innerHTML property, to the descriptive text in the descriptions array (line 5). Once you’ve added this code, reload the page and you should see the first photo with its descriptive text.

001 vfunction init() {
002    var img = document.getElementById("one");
003    img.src = photos[0];
004    var div = document.getElementById("description");
005    div.innerHTML = descriptions[0];
006 }
007 window.onload = init;

14. Keep track of your images

Add a new variable – photoIndex (line 1) – which will hold the next image/description we’re going to transition to. A good place to add this variable is underneath the two arrays we created earlier.

001 var photoIndex = 0;

15. Create a function for the transition

Now write a new function – transition – that will increase the value of photoIndex by 1 (line 4), to indicate the next image item in the array to display. You need to check to see if we’ve reached the end of the array; if we have, set photoIndex back to 0 so we start again at the beginning of the array the next time the function is called. Use a property of the array – the length property – to test to see if photoIndex is too big.

001 var photoIndex = 0;
002
003 function transition() {
004    photoIndex = photoIndex + 1;
005    if (photoIndex >= photos.length) {
006        photoIndex = 0;
007    }
008 }

16. Change the image sources

Now get the <img> elements from the DOM (lines 6-7). Remember that the <img> element with the id ‘one’ has the current image that is displayed. The next image is the image in the photos array at the index with the current value of photoIndex. Put this image in the <img> element with the id ‘two’ (line 8). The corresponding text for that image is the string at array index photoIndex in the descriptions array; put that text into the description <div> (lines 9-10).

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById("one");
007    var newImg = document.getElementById("two");
008    newImg.src = photos[photoIndex];
009    var div = document.getElementById("description");
010    div.innerHTML =descriptions[photoIndex];
011 }

17. Add the fade effect

When you add the class ‘transparent’ to an <img> element, it fires off a CSS transition that fades the image. We are transitioning from image one to image two, so you need to add the transparent class to image one and remove the class from image two. Use the setAttribute() function to add the transparent class to image one (line 11); this causes it to fade.

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById("one");
007    var newImg = document.getElementById("two");
008    newImg.src = photos[photoIndex];
009    var div = document.getElementById("description");
010    div.innerHTML =descriptions[photoIndex];
011    currentImg.setAttribute("class","transparent");
012 }

18. Remove the transparent class from the previous photo

Note that the setAttribute function takes two arguments: first the attribute to set, and second, the value of the attribute. We’ll use it now to remove the transparent class from image two by using an empty string for the value (line 12).

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById("one");
007    var newImg = document.getElementById("two");
008    newImg.src = photos[photoIndex];
009    var div = document.getElementById("description");
010    div.innerHTML =descriptions[photoIndex];
011    currentImg.setAttribute("class","transparent");
012    newImg.setAttribute("class", "");
013 }

19. Create arrays to hold image names and text

Now let’s transition between images when you click anywhere in the browser window. To do this, set the onclick property of the window to the transition function (line 14). This is similar to how you set the onload property of the window to init earlier. Once you’ve done this, if you click in the browser window, the transition() function will be called and the first image will fade and the next image from the array will appear.

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById("one");
007    var newImg = document.getElementById("two");
008    newImg.src = photos[photoIndex];
009    var div = document.getElementById("description");
010    div.innerHTML =descriptions[photoIndex];
011    currentImg.setAttribute("class","transparent");
012    newImg.setAttribute("class", "");
013 }
014 window.onclick = transition;

20. More than one transition

Right now the code only supports a transition from one image to a second. To keep transitioning images whenever you click on the browser window, you have to do a bit more work. To do this, we’ll use a new variable – current – to keep track of which image is currently visible. Add the new current variable to your JavaScript, under where you added photoIndex earlier, and initialise current to the value ‘one’, the id of the image that is visible when your app starts up (line 2).

001 var photoIndex = 0;
002 var current = "one";

21. Update the transition function

In the transition() function, when you get the currently visible image from the DOM and store it in the variable currentImg, instead of using the value one for the id, you’ll use the value in the variable current (line 6). The first time you call transition() this will be one, but the next time, it will be two, because after getting the currentImg, you’ll then switch current to two. But we can’t always just set it to two because if currentImg is currently two, we want to set it back to one. So, to overcome this, we’ll use an if test; if current equals one, we set it to two, otherwise (that is, current equals two) we set it to one (lines 7-11).

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById(current);
007    if (current == "one") {
008        current = "two";
009    } else {
010        current = "one";
011    }
012    var newImg = document.getElementById("two");
013    newImg.src = photos[photoIndex];
014    var div = document.getElementById("description");
015    div.innerHTML =descriptions[photoIndex];
016    currentImg.setAttribute("class","transparent");
017    newImg.setAttribute("class", "");
018 }

22. Finishing up the app

You also need to update where you set the value of newImage to use the new value of current (line 12). If currentImg is set to image one, and we switch current to two, then newImage should be set to image two (and likewise, if currentImg is set to image two, then newImage should be set to image one). Once you have made this change and you reload the page, you should now be able to transition between images every time that you click on the browser window.

001 function transition() {
002    photoIndex = photoIndex + 1;
003    if (photoIndex >= photos.length) {
004        photoIndex = 0;
005    }
006    var currentImg = document.getElementById(current);
007    if (current == "one") {
008        current = "two";
009    } else {
010        current = "one";
011    }
012    var newImg = document.
013getElementById(current);
014    newImg.src = photos[photoIndex];
015    var div = document.getElementById("description");
016    div.innerHTML =descriptions[photoIndex];
017    currentImg.setAttribute("class","transparent");
018    newImg.setAttribute("class", "");
019 }
×