0

I have a method, which is meant to create divs within another div... However it won't work...

Here is the method:

populateSquares(){
    let relatedTagToPopulation = document.getElementById("questionp");
    let whatTextIs = relatedTagToPopulation.textContent;
    for (let u=0;u<this.stemQuestions.length;u++){
        if (this.stemQuestions[u]==whatTextIs){
            var populateSquaresPertinentInt = u;
        }
    }
    for  (let i=0;i<this.stemAnswers.length;i++){
        if (i==populateSquaresPertinentInt){
            let numberOfSquaresToAdd = this.stemAnswers[i].length;
            for (let j=0;j<numberOfSquaresToAdd;j++){
                let elToAdd = document.createElement("<div id='ans"+j+"' class='lans'></div>"); 
                let elToAddInto = document.getElementById("answeri"); 
                elToAddInto.appendChild(elToAdd); 
            }
        }
    }
}

It gives out this error...

Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('<div id='ans0' class='lans'></div>') is not a valid name.
1
  • 1
    createElement takes a tag name, like "div", not HTML. You would assign attributes separately. Commented Feb 10, 2019 at 6:00

2 Answers 2

1

If you are using JavaScript, you should follow the document: https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement, and here: CreateElement with id?

let elToAdd = document.createElement('div')
// then call `elToAdd.xxxx` to add attributes or do other operation on the element
elToAdd.setAttribute("id", "ans" + i);
// ... more

If you are using jQuery, you can use:

let elToAdd = jQuery("<div id='ans"+j+"' class='lans'></div>")
Sign up to request clarification or add additional context in comments.

1 Comment

Note that the id attribute is also reflected by a property, so you can do: elToAdd.id = "ans" + j
1

Three Ways to Create Tags

The following examples all do the same thing:
Create an <article> tag with the class: .post and add it to the <main id="main"> tag.
There's an exception see #2 .innerHTML


document.createElement(tagName)

The only parameter is a tagName (ex. "DIV", "SPAN", "IFRAME", etc.). Once created it needs to be added to the DOM:

const post = document.createElement("ARTICLE");
post.className = "post";
document.getElementById('main').appendChild(post);

This is an old yet stable method but it takes two lines to create one barebones tag. More code is necessary to assign attributes and content.


.innerHTML += htmlString

This property will parse a tag(s) out of a given String within the targeted tag. If an = operator is used all content of the targeted tag is overwritten with the htmlString. If += operator is used the htmlString will be appended to the content within the targeted tag.

document.querySelector('main').innerHTML += `<article class='post'></article>`;

This pattern is simple and versatile. In one line multiple tags can be created with attributes and content. It's limited to either overwriting content: = or appending to content: +=.

Edit: Kaiido has informed me that .innerHTML will replace everything so if you are concerned about event bindings or references don't use it. See comments below.


.insertAdjacentHTML(position, htmlString)

This is .innerHTML on steroids. It will insert before/after/inside/outside a given htmlString of a targeted tag. The first parameter is one of four strings that determine the position of insertion relative to the targeted tag:

"beforebegin" <div id="target"> "afterbegin" text content "beforeend" </div> "afterend"

The second parameter is the htmlSting to be inserted.

document.getElementsByTagName('MAIN')[0].insertAdjacentHTML('afterbegin', `
  <article class='post'></article>
`);                    

I couldn't follow your code but it's supposed to be a method? So the demo has an object called populate and there's a factory function called documentSection() that creates objects and inherits the method .createSection() from populate.

Demo

let text = ['post 1', 'post 2', 'post 3'];
let archives = ['document 1', 'document 2', 'document 3'];

const populate = content => ({
  createSections: () => {
    let idx = 0;
    const target = document.querySelector("main");
    /* 
    Pattern 1 - document.createElement(tagName)
    */
    const section = document.createElement('SECTION');
    section.id = content.title;
    target.appendChild(section);
    /*
    Pattern 2 - .innerHTML += htmlString
    */
    section.innerHTML += `<h2>${content.title}</h2>`;
    for (let text of content.text) {
      idx++;
      /*
      Pattern 3 - .insertAdjacentHTML(position, htmlString)
      */
      section.insertAdjacentHTML('beforeend', `<article id="${content.title}-${idx}" class="t">${text}</article>`);
    }
  }
});

const documentSection = (title, text) => {
  let content = {
    title: title,
    text: text
  };
  return Object.assign(content, populate(content));
};

const post = documentSection('Post', text);
const archive = documentSection('Archive', archives);

post.createSections();
archive.createSections();
main {
  display: table;
  border: 3px ridge grey;
  padding: 2px 10px 10px;
}

h1 {
  font: 900 small-caps 1.5rem/1 Tahoma;
  margin-bottom: 8px
}

h2 {
  font: 700 small-caps 1.2rem/1 Tahoma;
  margin-bottom: 8px
}

section {
  border: 2px solid #000;
  padding: 2px 8px 8px;
}

article {
  font: 400 1rem/1.25 Arial;
}

.t::before {
  content: attr(id)': ';
  font-weight: 700;
}
<main>
  <h1>Documents</h1>
</main>

2 Comments

Nope, #2 doesn't do the same thing at all. From the DOM point of view, it does remove the <main> element and all its children, and then append a new one, with the same markup, along with new elements that do share the same markup as the children of the previous <main> and a new <article> element. If you had any variable pointing to one of these children, the element they point to is now off-doc. If you had any event listeners, they're gone.
Duly noted, sir, thank you. @Kaiido does .innerText and .textContent wipeout anything with += ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.