简体   繁体   中英

Dynamically create a div with dynamic onclick function

Context: I'm lazy, and I'm trying to dynamically/automatically create menu buttons which are hyperlinked to the headers of a page with raw JavaScript.

My site loads the content of the body from an external file located at the same folder with document.onload, and I'm trying to set up a menu function, which then should load the default page's menu items. Loading the menu manually each time I change from one page to another works, as I've included loadMenues(thispage) on the end loadContents(), but it doesn't work as soon as the page is loaded, as loading the body content does. I don't understand this behaviour.

function setVisible(thisdiv){
    var alldivs = document.getElementsByClassName("container");
    [].forEach.call(alldivs, function(uniquediv){
        document.getElementById(uniquediv.id).style.display = "none";
        return;
    });
    document.getElementById(thisdiv).style.display = "block";
    window.scrollTo(0,0);
    loadMenues(thisdiv);
}
window.onload = function(){
    loadContent("personalinfo");
    loadContent("contactdetails");
    setVisible("personalinfo");
    loadMenues("personalinfo");
}

I'm explaining this, secondary question, in order to contextualize my main problem.

loadContents(file) is a function which extracts the contents from the requested file. The layout of each of these files is the same, pretty much, with each section of the file being separated by a custompadding div , where its first child is a h1 element as shown below:

<html>
    <div class="custompadding">
        <h1 id="headerpersonaldetails">Personal details</h1>
        <p>Lorem ipsum</p>
    </div>
    <div class="custompadding">
        <h1 id="headercontactdetails">Contact details</h1>
        <p>Lorem ipsum</p>
    </div>
</html>

I'm trying to set up a menu item for each of these headings, which scrolls to the clicked-on header. Setting up each menu-item manually works as expected, but I want to automatize it, so changing any file will automatically add the menu items to whichever page we change to. Following is my code which adds these elements to the divisor, but I'm having issues handling the onclick function.

function loadMenues(file) {
    var rightmenu = document.getElementById("right-menu");
    while(rightmenu.firstChild){
        rightmenu.removeChild(rightmenu.firstChild);
    }
    [].forEach.call(document.getElementById(file).children, function(custompaddingchild) {
    console.log(custompaddingchild);
    headerelement = custompaddingchild.getElementsByTagName("h1")[0]
    newbutton = document.createElement("div");
    newbutton.setAttribute("class", "menu-item");
    let movehere = function() { location.href="#"+headerelement.id; console.log(headerelement.id); }
    newbutton.onclick = movehere;
    /*rightmenu = document.getElementById("right-menu");*/
    buttonspanner = document.createElement("span");
    buttoncontent = document.createTextNode(headerelement.innerHTML);
    buttonspanner.appendChild(buttoncontent);
    newbutton.appendChild(buttonspanner);
    rightmenu.appendChild(newbutton);
    });
}

The first part of the function deletes all the nodes which already are in the menu, in order to add the new ones when changing pages.

Trying to define newbutton.setAttribute() with onclick results in a SyntaxError (fields are not currently supported) in Firefox. It doesn't work if I set a static string as newbutton.setAttribute("onclick", "location.href=#headerpersonalinfo"); either.

Trying to set a static anchor link with newbutton.onclick set to a function, instead, works, such that

newbutton.onclick = function() {
    location.href = "#headerpersonalinfo";
}

and this is pretty much how my current code is set up, except that I have given this function a unique variable, which I then call.

The problem I have is this, as I see it: The variable is redefined each time it finds a new header, so calling the function sends the user to the last header, and not the expected one. How can I set the function to be parsed at the moment I define onclick with it, and not call the function when the user presses the button?

PS: I'm using my own internal naming convention of files, headers, and items, in order to modularize my site as much as I can. Since this is a website only intended for my Curriculum Vitae, I'm its only developer.

The issue occurs because the you are hoisting "variables" to the global scope (newbutton and headerelement).

Set them to block scoped variables ( const or let ) and you will see that it works: https://codesandbox.io/s/rm4ko35vnm

function loadMenues(file) {
  var rightmenu = document.getElementById("right-menu");
  while (rightmenu.firstChild) {
    rightmenu.removeChild(rightmenu.firstChild);
  }
  [].forEach.call(document.getElementById(file).children, function(
    custompaddingchild
  ) {
    console.log(custompaddingchild);
    const headerelement = custompaddingchild.getElementsByTagName("h1")[0];
    console.log(headerelement.innerHTML);
    const newbutton = document.createElement("div");
    newbutton.setAttribute("class", "menu-item");
    console.log(headerelement.id);
    let movehere = function() {
      location.href = "#" + headerelement.id;
      console.log(headerelement.id);
    };
    newbutton.addEventListener('click', movehere);
    const rightmenu = document.getElementById("right-menu");
    const buttonspanner = document.createElement("span");
    buttoncontent = document.createTextNode(headerelement.innerHTML);
    buttonspanner.appendChild(buttoncontent);
    newbutton.appendChild(buttonspanner);
    rightmenu.appendChild(newbutton);
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM