SitePoint Sponsor

User Tag List

Results 1 to 11 of 11
  1. #1
    SitePoint Wizard
    Join Date
    Apr 2002
    Posts
    2,307
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)

    simple adding html element without style q.

    just getting to know my way round javascript and am wondering what's the best way to add in some html without using css? so for example, this html doc:

    Code:
    <html>
    <head>
    <script type="text/javascript">
    function addDiv() {
         // ?
    }
    </script>
    </head>
    <body>
    <!-- div to be added here -->
    <p onmouseover="addDiv();">Rollover</p>
    </body>
    </html>
    and this is the html to be added by javascript:
    Code:
    <div><ul><li>one</li><li>two</li></ul></div>
    so what should go in the addDiv function? what's the standard/best way to add that div html into the html doc where the comment indicates?

    thanks.

  2. #2
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The easiest method would be to have a placeholder in the markup that you can get hold of with the javascript.
    Code:
    <body>
    <div id="addHere"><!-- markup to be added here --></div>
    <p onmouseover="addDiv();">Rollover</p>
    </body>
    That way, your script can get the placeholder via its id and alter its html directly.
    Code:
    function addDiv() {
         var el = document.getElementById("addHere");
         el.innerHTML = "<ul><li>one</li><li>two</li></ul>";
    }

  3. #3
    SitePoint Wizard
    Join Date
    Apr 2002
    Posts
    2,307
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    right thanks. i did this:

    Code:
    function addDiv() {
    	var div = document.createElement("div");
    	div.innerHTML = "<ul><li>one</li><li>two</li></ul>";
    	document.body.insertBefore(div, null);
    }
    which is good because it doesn't require an empty div, but it places the div after the paragraph. i'm not sure what this line should be:
    document.body.insertBefore(div, null);
    ?

    also once that works, what would the removeDiv() function be assuming this line is added into the addDiv function:
    div.setAttribute("id", "newdiv");
    ?

    and a more general question: html which has been added by javascript like above, does that become part of the document tree much like the html which is part of the doc? that is, the js added html, is that then manipulatable in much the same way as normal non js added html is manipulatable?

    thanks

  4. #4
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you give the paragraph an id, you can grab a reference to that and then use that reference in insertBefore, rather than null. It all depends on how general you want your script to be.

    To remove the div, you could use a function that removes any element by its id.
    Code:
    function addDiv() {
    	var div = document.createElement("div");
            div.id = "notStayingLong";
    	div.innerHTML = "<ul><li>one</li><li>two</li></ul>";
            var p = document.getElementById("pId");
    	document.body.insertBefore(div, p);
    }
    
    function removeDiv(id) {
      var el = document.getElementById(id);
      el.parentNode.removeChild(el);
    }
    Or you could maintain a reference to the original div.
    Code:
    var div;
    
    function addDiv() {
    	div = document.createElement("div");
    	div.innerHTML = "<ul><li>one</li><li>two</li></ul>";
            var p = document.getElementById("pId");
    	document.body.insertBefore(div, p);
    }
    
    function removeDiv() {
      div.parentNode.removeChild(div);
    }
    The first method is more general. The second is specific to your page.

    Yes, adding html via JavaScript adds it to the document tree.

  5. #5
    SitePoint Wizard
    Join Date
    Apr 2002
    Posts
    2,307
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    i see, excellent, thanks.

  6. #6
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,702
    Mentioned
    101 Post(s)
    Tagged
    4 Thread(s)
    I would like to take a stab at answering this one too, and clearing up a couple of misconceptions.

    Quote Originally Posted by johnyboy View Post
    right thanks. i did this:

    Code:
    function addDiv() {
    	var div = document.createElement("div");
    	div.innerHTML = "<ul><li>one</li><li>two</li></ul>";
    	document.body.insertBefore(div, null);
    }
    which is good because it doesn't require an empty div, but it places the div after the paragraph.
    The innerHTML property is one that is only supported by Microsoft. There have been numerous discussions about whether it should be used or not, which only serves to demonstrate that it is a contentious technique.

    The accepted manner to add elements is to explicitly create them and append them on to each other.

    Code javascript:
    function addDiv() {
    	var div, ul, li, text;
    	div = document.createElement("div"),
    	ul = document.createElement('ul'),
    	li = document.createElement('li'),
    	text = document.createTextNode('one');
    	li.appendChild(text);
    	ul.appendChild(li);
    	div.appendChild(ul);
    	ul = document.createElement('ul'),
    	li = document.createElement('li'),
    	text = document.createTextNode('two');
    	li.appendChild(text);
    	ul.appendChild(li);
    	div.appendChild(ul);
    	document.body.appendChild(div);
    }

    You can make your life easier by encapsulating some of the work into a separate function.

    Code javascript:
    function addDiv(id) {
    	var div = newEl('div', [
    		newEl('ul',
    			newEl('li', 'one')
    		),
    		newEl('ul',
    			newEl('li', 'two')
    		)
    	], {'id': id});
    	document.body.appendChild(div);
    }

    Then you can keep the newEl() function separate as a helper function.

    Code javascript:
    function newEl(tag, content, attrs) {
    	var el = document.createElement(tag);
    	var i;
    	if (content instanceof Array) {
    		for (i = 0; i < content.length; i += 1) {
    			addContent(el, content[i]);
    		}
    	} else {
    		addContent(el, content);
    	}
    	addAttrs(el, attrs);
    	return el;
    }
    function addContent(el, content) {
    	if (content) {
    		if (typeof content === 'string') {
    			content = document.createTextNode(content);
    		}
    		el.appendChild(content);
    	}
    	return el;
    }
    function addAttrs(el, attrs) {
    	var attr, value;
    	if (attrs) {
    		for (attr in attrs) {
    			value = attrs[attr];
    			if (value) {
    				attr = attr.toLowerCase();
    				if (attr === 'class') {
    					el.className = value;
    				} else {
    					el.setAttribute(attr, value);
    				}
    			}
    		}
    	}
    }

    Quote Originally Posted by johnyboy View Post
    i'm not sure what this line should be:
    document.body.insertBefore(div, null);
    When the reference child is null, the new child is placed at the end of the children. This is also exactly what happens with appendChild

    Code javascript:
    document.body.appendChild(div);

    Quote Originally Posted by johnyboy View Post
    also once that works, what would the removeDiv() function be assuming this line is added into the addDiv function:
    div.setAttribute("id", "newdiv");
    While you can use an identifier to reference the element, it's a better practice to use a reference to the element itself where possible.

    Then you can pass that reference to functions, or work on them directly.

    Code javascript:
    function removeEl(el) {
        el.parentNode.removeChild(el);
    }
     
    newEl = document.body.appendChild(div);
    ...
    removeEl(newEl);

    Quote Originally Posted by johnyboy View Post
    and a more general question: html which has been added by javascript like above, does that become part of the document tree much like the html which is part of the doc? that is, the js added html, is that then manipulatable in much the same way as normal non js added html is manipulatable?
    There are some subtle differences when using innerhtml vs other methods.
    Check out http://www.quirksmode.org/dom/events/ for details on them.
    Last edited by paul_wilkins; Jul 31, 2008 at 19:16.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  7. #7
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think the common phrase when referring to innerHTML is "it's not a W3C standard but it is widely supported by modern browsers." It's unlikely to disappear anytime soon.

    Having said that, Paul is absolutely write to champion the 'long way round' DOM manipulation techniques, methods that are standard and are more widely applicable to XML in general.

  8. #8
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,702
    Mentioned
    101 Post(s)
    Tagged
    4 Thread(s)
    Thank you, I was going to make newEl() rather short and sweet, but decided that coming up with something more flexible that can be used by others would be a better decision.

    Here's a refactored version which keeps the array handling encapsulated in the content section.

    Code javascript:
    function newEl(tag, content, attrs) {
    	// tag:     The tag name of the new element
    	// content: Text or an element to be added, can also be an array of them
    	// attrs:   An object notation list of attributes to be set {name: 'value', ...}
    	var el = document.createElement(tag);
    	if (content) {
    		addContent(el, content);
    	}
    	if (attrs) {
    		addAttrs(el, attrs);
    	}
    	return el;
    }
    function addContent(el, content) {
    	// content can array, text or element
    	var i;
    	if (content instanceof Array) {
    		for (i = 0; i < content.length; i += 1) {
    			addContent(el, content[i]);
    		}
    	} else {
    		if (typeof content === 'string') {
    			content = document.createTextNode(content);
    		}
    		el.appendChild(content);
    	}
    	return el;
    }
    function addAttrs(el, attrs) {
    	// attrs is an object notation list
    	// eg. {'id': 'myId', 'name': 'myName', ...}
    	var attr, value;
    	for (attr in attrs) {
    		value = attrs[attr];
    		if (value) {
    			attr = attr.toLowerCase();
    			if (attr === 'class') {
    				el.className = value;
    			if (attr === 'style') {
    				setStyle(el, value);
    			} else {
    				el.setAttribute(attr, value);
    			}
    		}
    	}
    }
    	function setStyle(el, declarations) {
    		var i, pair, property, value, pos;
    		declarations = declarations.split(';');
    		for (i = 0; i < declarations.length; i += 1) {
    			pair = declarations[i].split(':');
    			property = dashToCamelCase(trim(pair[0]));
    			value = trim(pair[1]);
    			el.style[property] = value;
    		}
    	}
    	function trim(text) {
    		return text.replace(/^\s+|\s+$/g, "");
    	}
    	function dashToCamelCase(text) {
    		var pos;
    		pos = text.indexOf('-');
    		while (pos > -1) {
    			text = text.substring(0, pos) + text.charAt(pos+1).toUpperCase() + text.substring(pos+2);
    			pos = text.indexOf('-');
    		}
    		return text;
    	}
    }

    edit: mixed-case attributes all become lowercase
    edit: Setting a style is now handled nicely where a dash-separated properly is changed to camelCase instead.
    Last edited by paul_wilkins; Aug 3, 2008 at 13:48.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  9. #9
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Do you need to be careful changing the case of property names before accessing them?
    Code:
     attr = attr.toLowerCase();
     value = attrs[attr];

  10. #10
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,702
    Mentioned
    101 Post(s)
    Tagged
    4 Thread(s)
    Ahh yes, thanks for that. I've updated the previous post to fix that.

    This I presume is where test cases would have helps to iron out silly things like that.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  11. #11
    SitePoint Wizard
    Join Date
    Apr 2002
    Posts
    2,307
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    excellent, thanks very much for this you two. very helpful.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •