JavaScript - Loading contents from one div to another

kbjradmin

New Member
Messages
512
Reaction score
2
Points
0
i'm trying to make a page that uses javascript to change the content in the main area of the page. i wrote this function:
Code:
function changeContent( value )
{
    var content = document.getElementById("content");
    var source = document.getElementById(value);
    content.innerHTML = ( source.defaultHTML || source.innerHTML );
    if ( ! source.defaultHTML )
    {
        source.defaultHTML = source.innerHTML;
    }
    source.innerHTML = "";
}
but it keeps returning the error 'source is null'. i can't figure out why the source would be null. the function changeContent is called on page load with the string "home" for value.

Here's the markup if it helps:
HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<?php include('config.php'); ?>
<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <!--Data Tags-->
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Language" content="en-us" />
    <title>PseudoFrame Template</title>
    
    <!--File Includes-->
        <!--Cascading StyleSheets-->
            <link rel="stylesheet" type="text/css" href="style.css" />
        <!--JavaScript-->
            <script type="text/javascript" src="pseudoframe.js"></script>    

</head>

<body>

    <div id="header">
    </div>
    
    <div id="menu">
        <ul>
            <li><a href="#home" rel="frame">Home</a></li>
            <li><a href="#about" rel="frame">About</a></li>
            <li><a href="#contact" rel="frame">Contact Us</a></li>
            <li><a href="#affiliates" rel="frame">Affiliates</a></li>
        </ul>
    </div>
    
    <div id="content">
        <!--
            Content is dynamically inserted here based on the current page.
        -->
    </div>
    
    <div id="footer">
    </div>
    
    <!--
        START PAGE CONTENT DIVS
    -->
    
    <div id="home" class="contents">
        <h1>Home</h1>
    </div>
    
    <div id="about" class="contents">
        <h1>About</h1>
    </div>
    
    <div id="contact" class="contents">
        <h1>Contact Us</h1>
    </div>
    
    <div id="affiliates" class="contents">
        <h1>Affiliates</h1>
    </div>
    
    <!--
        END PAGE CONTENT DIVS
    -->
    
</body>

</html>

please help.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
That's not quite enough information. We need to actually see how changeContent is called. Please include enough JS (make sure it generates the error) to make your example testable and post a link to a live page.
 

kbjradmin

New Member
Messages
512
Reaction score
2
Points
0
the function is called with:
Code:
function pageLoad()
{
    changeContent("home");
}
window.onload = pageLoad();

right now the page is on my computer, but i'll upload it and post back when it's up.



edit:
ok, it's up: http://www.kbjrweb.com/pseudoFrame/
just ignore the links, i've haven't gotten around to setting them up yet; still trying to get the function to work at all...
 
Last edited:

teamg1

New Member
Messages
2
Reaction score
0
Points
0
I looked at your example. Do you want a different web page to load when you click each item?

I have done this with frames, and it makes everything a lot easier once you create your "master frame", or are you committed to doing the frame content with javascript?
 

kbjradmin

New Member
Messages
512
Reaction score
2
Points
0
the entire point is that i'm trying to accomplish the same concept as frames without having to actually use frames.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
The first error in the live page is that the initialization script calls changeContents("home") (plural), but the function in pseudoframe.js is called changeContent (singular). Once you fix this, notice that #content is successfully changed to the contents of #home, suggesting the problem doesn't lie there. The culprit is contentLinks. That the problem might be someplace other than where you were looking is the reason I asked for a complete example and a live page.

There are two problems in contentLinks. The first is a design flaw: you don't want to call changeContent for each anchor, you want to define a handler that will call changeContent. The second error is that the href property of an HTMLAnchorElement is an absolute URI. You'll either need to extract the fragment identifier from the absolute URI using (e.g.) regular expressions, or use getAttribute.

Code:
function changeContent( value ) {
  ...
}

function contentChanger(id) {
	return function(evt) {
		changeContent(id);
	}
}

function contentLinks()
{
	if (!document.getElementsByTagName) return;
	var anchors = document.getElementsByTagName('a');
	for (var i = 0; i < anchors.length; i++)
	{
		var anchor = anchors[i];
		if (anchor.getAttribute('href') && anchor.getAttribute('rel') == 'frame')
		{
			anchor.onclick = contentChanger(anchor.getAttribute('href').substr(1));
		}
	}
}

There are still larger issues to consider: when is it acceptable to apply the technique you're developing, how it plays with browser history and bookmarking, how it uses network resources and how it degrades.
 
Last edited:

VPmase

New Member
Messages
914
Reaction score
0
Points
0
It would be a lot easier if you just used arrays. I'll make a script for ya real quick showing you what I mean.

Edit- Done
Demo: http://saumpro.x10hosting.com/EsamTests/psuedoframes.html


Script:
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>
<div id="links"><a href="#links" onclick="changeContent(1);">Home</a><br /><a href="#links" onclick="changeContent(2);">About Us</a><br /><a href="#links" onclick="changeContent(3);">Contact</a><br /><a href="#links" onclick="changeContent(4);">Affiliates</a></div>
<div id="content">BLAH!</div>
<script type="text/javascript">
var contentlist = new Array();
contentlist[1] = "Home!";
contentlist[2] = "About Us!";
contentlist[3] = "Contact!";
contentlist[4] = "Affilates!";
var contentbox = document.getElementById("content");

function changeContent(x){
	contentbox.innerHTML = contentlist[x];
}

changeContent(1);
</script>
</body>
</html>
 
Last edited:

descalzo

Grim Squeaker
Community Support
Messages
9,373
Reaction score
326
Points
83
Code:
function contentLinks()
{
 if (!document.getElementsByTagName) return;
 var anchors = document.getElementsByTagName('a');
 for (var i = 0; i < anchors.length; i++)
 {
  var anchor = anchors[i];
  if (anchor.getAttribute('href') && anchor.getAttribute('rel') == 'frame')
  {
   anchor.onclick = changeContent(anchor.href.substr(1));
  }
 }
}

Why are you using this to try to set onclick handlers for the links instead of putting them in the HTML?

It will not work.

1. As been pointed out, anchor.href gives you [URL="http://www.kbjrweb.com/pseudoFrame/#home"]http://www.kbjrweb.com/pseudoFrame/#home[/URL] not just #home.
You would need something like

Code:
  index_after_symbol = anchor.href.indexOf( '#');
  text_after_hash_symbol = anchor.href.substr( index_after_symbol );


2. When you programically assign to anchor.onclick, you have to give it a function. You are giving it the result of running a function , changeContent(anchor.href.substr(1)) .


PS. When you hard code the onclick, remember to add "return false". ie

Code:
"<a href="#links" onclick="changeContent(1); [B]return false[/B];">Home</a>

That keep the address bar from adding '#links'
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
Why are you using this to try to set onclick handlers for the links instead of putting them in the HTML?
Generally speaking, there are three reasons: separation of behavior from structure, making the page degrade gracefully when JS isn't available (the HTML page is designed to work w/o JS, and scripts add functionality), and to reduce code repetition.

PS. When you hard code the onclick, remember to add "return false". ie
...
That keep the address bar from adding '#links'
I recommend letting the address change. It can be used to make the page work with browser history and bookmarks.

@kbjradmin: rather than using document.getElementsByTagName(), you might want to use document.links. It has wider support on older browsers (if you're worried about getElementsByTagName not being defined) and probably won't involve a function call or DOM traversal (depending on implementation). It's also slightly more readable.
 

descalzo

Grim Squeaker
Community Support
Messages
9,373
Reaction score
326
Points
83
Ok, here is my version....

Code:
<html >
<head>

        <title>PseudoFrame Template</title>
        <link rel="stylesheet" type="text/css" href="style.css" />

<script>

function changeContent( value )
{
                //  SAME AS YOUR CURRENT CODE
	var content = document.getElementById("content");
	var source = document.getElementById(value);
	content.innerHTML = ( source.defaultHTML || source.innerHTML );
	if ( ! source.defaultHTML )
	{
		source.defaultHTML = source.innerHTML;
	}
	source.innerHTML = "";
}

// A FUNCTION TO MAKE A FUNCTION TO PASS TO  anchor.onclick

function make_onclick( word ){
        
        function call_changeContent(){
             changeContent( word );
             return false;  // THIS KEEPS THE LINK FROM BEING FOLLOWED
         }
        return call_changeContent ;  // RETURN THE FUNCTION -- NAME WITHOUT ()
}

function contentLinks()
{
    if (!document.getElementsByTagName) return;
        var anchors = document.getElementsByTagName('a');
        for (var i = 0; i < anchors.length; i++)
        {
            var anchor = anchors[i];
            if (anchor.getAttribute('href') && anchor.getAttribute('rel') == 'frame')
            {  
                        //  anchor.href returns the entire URL not just #yadda
                indx = anchor.href.indexOf( '#' ) ;
                tail = anchor.href.substr( indx + 1 ) ;
                anchor.onclick = make_onclick( tail ) ; 
             }
         }
}

    function init(){
        changeContent("home");
        contentLinks();
    }
      // NOTE: YOU PASS A FUNCTION -- THE NAME WITHOUT THE ()
    window.onload = init ;

</script>

</head>

<body>

	<div id="header">
	</div>
	
	<div id="menu">
		<ul>
			<li><a href="#home" rel="frame">Home</a></li>
			<li><a href="#about" rel="frame">About</a></li>
			<li><a href="#contact" rel="frame">Contact Us</a></li>
			<li><a href="#affiliates" rel="frame">Affiliates</a></li>
		</ul>
	</div>
	
	<div id="content">
		<!--
			Content is dynamically inserted here based on the current page.
		-->
	</div>
	
	<div id="footer">
	</div>
	
	<!--
		START PAGE CONTENT DIVS
	-->
	
	<div id="home" class="contents">
		<h1>Home</h1>
	</div>
	
	<div id="about" class="contents">
		<h1>About</h1>
	</div>
	
	<div id="contact" class="contents">
		<h1>Contact Us</h1>
	</div>
	
	<div id="affiliates" class="contents">
		<h1>Affiliates</h1>
	</div>
	
	<!--
		END PAGE CONTENT DIVS
	-->

</body>

</html>
Edit:
Generally speaking, there are three reasons: separation of behavior from structure, making the page degrade gracefully when JS isn't available (the HTML page is designed to work w/o JS, and scripts add functionality), and to reduce code repetition.

But do any of those apply in this situation?

Degrade with out JS? As it is, nothing works on his page without JS. The links should not be #home, etc, they should be to a page that displays that content if there is no JS.

Reduce code repetition? He has to code the onLoad function to adjust the links. He has to code the fuction to make the fuction for onclick. He could avoid all that by just putting onClick="changeContent( 'div-name' )" in each link in the page.
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
But do any of those apply in this situation?
All of them could apply. Arguable, the first (separation of behavior & structure) might apply the least as it's mostly a matter of design philosophy, but it's a very clean design philosophy.

Degrade with out JS? As it is, nothing works on his page without JS.
Which is a problem with the technique and needs to be fixed in his implementation.

Reduce code repetition? He has to code the onLoad function to adjust the links. He has to code the fuction to make the fuction for onclick. He could avoid all that by just putting onClick="changeContent( 'div-name' )" in each link in the page.
He defines three functions once (no code repetition) rather than adding an inline onclick handler for each pseudoframe anchor in each and every page that uses the technique. The most code repetition the first approach has is a tag in each page to include the pseudoframe script.

Reducing code repetition isn't just about reducing how much you type. In the age of cut & paste, reducing how much you type is easy. It's about reducing mistakes and making maintenance easier. What if there are other behavioral alterations that later need to be added? For example, the source could link to other pages (so it works without JS) and contentLinks could alter the href attribute.

HTML:
...
			<li><a href="home" rel="frame">Home</a></li>
			<li><a href="about" rel="frame">About</a></li>
			<li><a href="contact" rel="frame">Contact Us</a></li>
			<li><a href="affiliates" rel="frame">Affiliates</a></li>
...
Code:
...
function extractFragment(url) {
    var matches = anchor.href.match(/^[^#?]+\/([^?#]+?)(?:\..{2,4})?(?:[?#].*|$)/);
    return matches && matches[1];
}

function contentLinks() {
    var anchors = document.links;
    for (var i = 0; i < anchors.length; ++i) {
        var anchor = anchors[i];
        if (anchor.getAttribute('href') && anchor.getAttribute('rel') == 'frame') {
            var fragment = extractFragment(anchor.href);
            if (fragment) {
                anchor.href = '#' + fragment;
            } else {
                fragment = anchor.getAttribute('href');
            }
            anchor.onclick = contentChanger(fragment) ; 
        }
    }
}

While you could still work out this particular behavior using inline click handlers (by returning false), it would still require defining behavior in multiple locations, which is the main problem with inline handlers.
 
Last edited:

descalzo

Grim Squeaker
Community Support
Messages
9,373
Reaction score
326
Points
83
My question to him was why he was doing it in a manner where he was clearly beyond his knowledge.
From his code, I felt that hardcoding onclick='changeContent("home" )' into the link HTML was more at his level at the moment.
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
My question to him was why he was doing it in a manner where he was clearly beyond his knowledge.
Fair enough.

@kbjradmin: if you want or need to study closures more, read Richard Cornford's "Javascript Closures" on Jibbering.com. And in case you haven't seen array literals, they are a faster-to-type alternative to using the Array constructor:
Code:
var contents = [
			document.getElementById("home").innerHTML,
			document.getElementById("about").innerHTML,
			document.getElementById("contact").innerHTML,
			document.getElementById("affiliates").innerHTML
		];
They can also be a little more readable than "Array(...)" when used in a function call, as you don't end up with Lisper's disease and wonder if you've forgotten a parenthesis. Compare:
Code:
foo(0, [{}, bar()]);
foo(0, Array({}, bar()));
 
Top