I have this ul which is made by HTML and I want to create elements inside with JS
HTML code:
<ul id="navbar__list">
</ul>
and JS code:
var ul = document.getElementById("navbar__list");
var link1 = document.createElement("a");
var Li1 = document.createElement("li").appendChild(document.createElement("a"));
var sec1 = ul.appendChild(Li1)
link1.innerHTML = "Section 1"
link1.href ="#section1"
all I got was without text and as a beginner, I do not know what is wrong
CodePudding user response:
Use this:
var ul = document.getElementById("navbar__list");
var li = document.createElement("li");
ul.appendChild(li);
var link = document.createElement("a");
link.setAttribute('href', '#section1');
link.innerHTML = "Section 1";
li.appendChild(link);
CodePudding user response:
You need to pass link1
into your appendChild
call. Right now your code is calling createElement("a")
twice and passing the second uninitialized <a>
into appendChild
, which is not what you want.
You'll want this:
- Use
const
for locals that shouldn't be reassigned. - Be defensive: because JavaScript doesn't offer compile-time type-safety or other guarantees it's a good idea to always check your assumptions and to
throw new Error
when those assumptions are invalidated. This greatly aids debugging in JavaScript ("fail fast"). - When building-up DOM element trees in JS, I find it helpful to put each element in its own anonymous-scope (
{ }
) which mirrors the DOM's structure.- This also helps prevent bugs where elements aren't parented correctly.
const ul = document.getElementById("navbar__list");
if( !ul ) throw new Error( "Couldn't find navbar__list" );
{
const li = document.createElement("li");
ul.appendChild( li );
{
const aLink = document.createElement("a");
aLink.textContent = "Section 1";
aLink.href = "#section1";
li.appendChild( aLink );
}
}
Somewhat surprisingly, the DOM API is kinda verbose: there's no succinct way to create elements with their attributes and inner-content set, instead we need explicit calls to createElement
and appendChild
. Some alternatives have been proposed that use compile-time techniques, like JSX, as a more lightweight alternative you could use a helper-function like this:
/**
@param {string} tagName
@param {[string, string][]} attributes - Array of 2-tuples
@param {HTMLElement | HTMLElement[] | string} content - Either: one-or-many HTML elements, or string textContent
*/
function create( tagName, attributes, content ) {
const e = document.createElement( tagName );
for( let i = 0; i < attributes.length; i ) {
const pair = attributes[i];
e.setAttribute( pair[0], pair[1] );
}
if( typeof content === 'string' ) {
e.textContent = content;
}
else if( Array.isArray( content ) ) {
for( const child of content ) {
e.appendChild( child );
}
}
else if( typeof content === 'object' && content !== null ) {
e.appendChild( content );
}
return e;
}
Used like so:
const ul = document.getElementById("navbar__list");
if( !ul ) throw new Error( "Couldn't find navbar__list" );
{
ul.appendChild(
create( "li", [], create( "a", [ [ "href", "#section1" ] ], "Section 1" ) )
);
}