How to use JavaScript objects to spawn HTML elements

Script, version 1.3

Why would you want to add stuff to a Web page after it's loaded?

Js Objects Spawn Element ExampleMost Web sites load all their images, text, and other elements when the page first loads and leave it at that. This is fine if you want your users to see a static page, or one whose pre-existing content moves around or hides and shows.

But what if you want user actions to add new instances of content you've prepared for them? Users could add books to a shopping cart, or spawn new monsters in a role-playing game, or open panels to show larger versions of images that they can drag around. In those cases, you need JavaScript objects.

Learning how to use JavaScript objects is also a great introduction to object-oriented code, which is easier to re-use and share than procedural code.

This tutorial walks you through a simple demonstration of the power of JavaScript objects by letting the user spawn new rectangles by clicking on the page.

Screencast script

Prerequisites

You should know enough CSS to style a div with absolute positioning, and know enough JavaScript to create a function and assign CSS styles with JavaScript.

You should have a code editor (like Sublime Text or TextWrangler) and standards-compliant browser (like Firefox, Safari, or Chrome).

Note that adding HTML elements on the fly is an advanced feature that doesn't work in every code editor's Web preview. If you run into trouble, it's best to load your object-enabled Web page in an actual browser.

Demo

This demo shows one way to use the kind of interaction you'll learn in this tutorial. Here are demos with ../related_files/leopold_ruth_div_mania.html ../related_files/rodrigo_randima_div_mania.html ../related_files/senese_don_div_mania.html circles, borders, and dots. The animated logo on this page shows a more subtle use of spawning random JavaScript objects.

Tutorial script

HTML elements, JavaScript objects, and constructor functions

Technically, every element of HTML--a div, image, or form--is an "HTML object." In this demo, however, you'll create a "JavaScript object"; for now, think of it as a scaffolding that can hold data or HTML elements that you can add to the page later.

I'll also show you how to write a constructor function that uses this scaffolding to build new div elements when the user needs them.

In the JavaScript we're writing, the constructor function will be called DivObject. If you've worked with JavaScript before, this name should look odd, because JavaScript names usually start with a lower case. Constructor functions, however, are usually capitalized to show that they are more powerful than regular functions.

We'll use the special keyword this to represent the JavaScript object built by that constructor. We'll call the actual HTML element spawned by this process this.div.

Writing the constructor function

Start with some HTML boilerplate, and add a script tag to the head. Inside create this function called DivObject:

  <script>
	DivObject = function() {
	    this.div = document.createElement( "div" ) ;
	    document.body.appendChild( this.div ) ;
	}
  </script>

The constructor function does two basic tasks. First, it creates a new, free-floating div using the special method createElement. Second, it attaches that div somewhere in the Web page, using the special method appendChild.

In this case our script attaches the div to the body, but you could append it anywhere you want by writing something like:

	    document.getElementById( "headlineContainer" ).appendChild( this.div ) ;	

Letting the user spawn divs

The constructor function won't work unless the user can trigger it, so we'll add a link to the body:

  <body>
	<a href="#" onclick="new DivObject()">Click</a> to spawn a rectangle.	
  </body>

You'll notice another difference between constructors and ordinary JavaScript functions: to call DivObject, you add the JavaScript keyword new before the function name.

Styling the divs with a class

You now have enough machinery in place to spawn new divs everytime you click on the link. Unfortunately, they won't show up on the page yet--why?

The divs you're making have no style attached, so there's nothing to see. But they are being added to the HTML, which you can confirm if your browser has an HTML inspector like Firebug.

Let's add a CSS class for our new divs called panel, and add that class via JavaScript in the constructor function.

  <style>
	.panel {
		position: relative ;
		width: 200px ;
		height: 100px ;
		background-color: palegoldenrod ;
	}
  </style>
  <script>
	DivObject = function() {
	    this.div = document.createElement( "div" ) ;
	    document.body.appendChild( this.div ) ;
	    this.div.className = "panel" ;
	}
  </script>

Absolute positioning works best for precise top and left positions. The color and sizes are arbitrary and can be overridden in the constructor function. You could also add background images and other characteristics to the panel style if you wish.

Note also that the correct way to add a CSS class to an element in JavaScript is via .className, not .class as you might expect.

When tested in a browser, the results are better in that you can see the divs being added as they march down the page--but still pretty boring. Let's make this page a lot more interesting by giving each div a different color and other attributes.

Giving each div special characteristics

There are several ways to give each new div you spawn its own identity. One of the more common ways is to pass special characteristics as arguments to the constructor function, like this:

  <script>
	DivObject = function( messageHTML ) {
	    this.div = document.createElement( "div" ) ;
	    document.body.appendChild( this.div ) ;
	    this.div.className = "panel" ;
	    this.div.innerHTML = messageHTML ;
	}
  </script>
	...
	
  <body>
	<a href="#" onclick="new DivObject( 'You have mail!' )">Click</a> to see a message.	
  </body>
	

Styling the divs randomly

Another way to give each div a unique identity is to set its characteristics randomly, this time entirely inside the constructor function. Let's use this technique to make a colorful design by giving each div a random position and color. We'll start by going back to our original constructor function.

In the stylesheet, we'll replace the CSS position relative with absolute, because that works better for random placement on the page.

We'll also need a bunch of random numbers, mostly percentages. In our new constructor function, the JavaScript method Math.random will give us a decimal number between 0 and 1 (like .3759214). We'll multiply by a number like 100 to make it into a percentage (like 37.59214). Then we'll pull the whole number (like 37) using the parseInt method, and tack % on the end. This will yield a valid CSS value (like 37%) the browser can understand.

  <style>
	.panel {
		position: relative ;
		width: 200px ;
		height: 100px ;
		background-color: palegoldenrod ;
	}
  </style>
  <script>
	DivObject = function() {
	    this.div = document.createElement( "div" ) ;
	    document.body.appendChild( this.div ) ;
	    this.div.className = "panel" ;
	    this.div.style.top = parseInt( 100 * Math.random() ) + "%" ;
	    this.div.style.left = parseInt( 100 * Math.random() ) + "%" ;
		this.div.style.backgroundColor = "hsla("  +  parseInt( 360 * Math.random() )  +  ", "  +  parseInt( 100 * Math.random() )  +  "%, "  +  parseInt( 100 * Math.random() )  +  "%, "  +  Math.random()  +  ")" ;
	}
  </script>

Note that we randomized the background color, which usually takes the form hsla(180, 20%, 70%, .5), by putting random numbers in for each of the Hue, Saturation, Luminosity, and Alpha slots:

  1. Math.random will give a decimal number between 0 and 1 (like .270451).
  2. For the first value, multiply that by 360 to make it into an angle (like 270.451).
  3. For the second and third, multiply by 100 to make it into a percentage (like 27.0451).
  4. For the fourth, leave it alone to make a decimal (like .270451).
  5. Then parse out the integer for the first three to get a value like 270 or 27%.

You'll also note we didn't have to parseInt the opacity--that's because it is already a decimal that runs from 0 to 1.

Try more randomness!

You could also randomize the width and height of each div. Or you could create a for loop that creates 100 rectangles automatically.