Button onclick disables draggable ??

Hello & Thanks :slight_smile:
In the code below:
Draggable works great until I click the Button .
Then ’ elmnt.cloneNode ’ doesn’t work
and then draggable stops working .
I tried to run code in DeveloperTools , but the Button doesn’t seem to click and there are no console errors .
Plz , can someone spot my error ?
Thanks

<!DOCTYPE html>
<html>
<style>
#mydiv {
  position: absolute;
  z-index: 9;
  background-color: #f1f1f1;
  text-align: center;
  border: 1px solid #d3d3d3;
}

#mydivheader {
  padding: 10px;
  cursor: move;
  z-index: 10;
  background-color: #2196F3;
  color: #fff;
}
</style>
<body>

<h1>Draggable DIV Element</h1>

<p>Click and hold the mouse button down while moving the DIV element</p>

<button onclick="cloneByTagName()">cloneByTagName</button>

<br><br>
<div id="mydiv">
  <div id="mydivheader">Click here to move</div>
  <div contenteditable="true">Type here: </div>
</div>

<script>
function cloneByTagName() {
  var elmnt = document.getElementsByTagName("div")[0];
  var cln = elmnt.cloneNode(true);
  document.body.appendChild(cln);
}
</script>

<script>
//Make the DIV element draggagle:
dragElement(document.getElementById("mydiv"));

function dragElement(elmnt) {
  var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  if (document.getElementById(elmnt.id + "header")) {
    /* if present, the header is where you move the DIV from:*/
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
  } else {
    /* otherwise, move the DIV from anywhere inside the DIV:*/
    elmnt.onmousedown = dragMouseDown;
  }

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    /* stop moving when mouse button is released:*/
    document.onmouseup = null;
    document.onmousemove = null;
  }
}
</script>
</body>
</html>

One big issue is that you are using ID values to identify elements on the page. The ID is designed to be unique on the page. When you have multiple elements that you want to assign the same ID to, you won’t get any warning, but your code will start to misbehave. The right solution is to use class values to identify elements that you will have plenty of, like the draggable div element for example :slight_smile:

I tweaked your code to better handle this:

<!DOCTYPE html>
<html>
<style>
  .mydiv {
    position: absolute;
    z-index: 9;
    background-color: #f1f1f1;
    text-align: center;
    border: 1px solid #d3d3d3;
  }

  .mydivheader {
    padding: 10px;
    cursor: move;
    z-index: 10;
    background-color: #2196F3;
    color: #fff;
  }
</style>

<body>

  <h1>Draggable DIV Element</h1>

  <p>Click and hold the mouse button down while moving the DIV element</p>

  <button onclick="cloneByTagName()">cloneByTagName</button>

  <br><br>
  <div class="mydiv">
    <div class="mydivheader">Click here to move</div>
    <div contenteditable="true">Type here: </div>
  </div>

  <script>
    function cloneByTagName() {
      var elmnt = document.getElementsByClassName("mydiv")[0];
      var cln = elmnt.cloneNode(true);

      dragElement(cln);

      document.body.appendChild(cln);
    }

    //Make the DIV element draggagle:
    dragElement(document.getElementsByClassName("mydiv")[0]);

    function dragElement(elmnt) {
      var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
      //if (document.getElementById(elmnt.id + "header")) {
      /* if present, the header is where you move the DIV from:*/
      elmnt.childNodes[1].onmousedown = dragMouseDown;
      //} else {
      /* otherwise, move the DIV from anywhere inside the DIV:*/
      //elmnt.onmousedown = dragMouseDown;
      //}

      function dragMouseDown(e) {
        e = e || window.event;
        e.preventDefault();
        // get the mouse cursor position at startup:
        pos3 = e.clientX;
        pos4 = e.clientY;
        document.onmouseup = closeDragElement;
        // call a function whenever the cursor moves:
        document.onmousemove = elementDrag;
      }

      function elementDrag(e) {
        e = e || window.event;
        e.preventDefault();
        // calculate the new cursor position:
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        pos3 = e.clientX;
        pos4 = e.clientY;
        // set the element's new position:
        elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
        elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
      }

      function closeDragElement() {
        /* stop moving when mouse button is released:*/
        document.onmouseup = null;
        document.onmousemove = null;
      }
    }
  </script>
</body>

</html>

One other change I made is in cloneByTagName. I add the code to make the newly cloned div be draggable at this time itself. The reason is that we have a reference to the newly created element. It would be a shame to waste that opportunity haha.

:slight_smile:

Aha , that’s great Thanks .

Something I don’t yet understand :
What connects cloned-Node to ‘onmousedown’ ?
this guy: cln ?
’ var cln = elmnt.cloneNode(true); ’ ?
So far I think so , and what does cln look like ?
Is it an index ? Or what ?

Now let me tell you why I am using contenteditble , instead of textarea .
I want to save the *.html file . So that when I open *.html again ,
all the text I entered will still be there . And I can continue to
add text to it . Over and over .

However herein is a new problem .
When I open *.html again , the cloned-Nodes have lost their connection to ‘onmousedown’ .
And I can’t Drag them .
The last created mydiv/mydivheader
is still Draggable , and any new cloned-Nodes are Draggable (until the next save/open) .

So what I need help with now is :
How to reconnect these un-Draggable Nodes to ‘onmousedown’ again ?

Thanks

The cloneNode method returns a reference to the newly cloned element itself. It isn’t an index. The Creating DOM Elements tutorial goes into more detail on this, and I do encourage you to read that, for it covers a lot of what you are trying to do :bookmark:

How are you persisting the newly cloned nodes and the page state? You can use both textarea and contenteditable for storing the entered values.

Cheers,
Kirupa

Thanks:

<button onclick="saveAs(filename, allHtml)">Save This Page</button>

      <script>
         function saveAs(filename, allHtml) {
           allHtml =  document.documentElement.outerHTML; 
          var blob = new Blob([allHtml], {type: 'text/csv'});
          if(window.navigator.msSaveOrOpenBlob) {
              window.navigator.msSaveBlob(blob, filename);
          }
          else{
              var elem = window.document.createElement('a');
              elem.href = window.URL.createObjectURL(blob);
              elem.download = filename;        
              document.body.appendChild(elem);
              elem.click();        
              document.body.removeChild(elem);
          }
         }    
      </script> 

Yahoo! That’s great news . Are there any special keywords or attributes that I need to apply to make textarea persistent . Because I tried it once , and there was no text in the left in the there when I opened saved page .
I am re-reading:
https://www.kirupa.com/html5/creating_dom_elements_and_other_stuff.htm
Thanks

One approach (which I tend to prefer) is to only persist the data in your app and re-create the HTML and such as needed. You can use any of the Web Storage approaches for doing that: https://www.kirupa.com/things_to_do_with_data/web_storage.htm

You can see an example of me storing the data from a textfield (similar in properties to a textarea) here: https://www.kirupa.com/tricks/metadata_generator.htm The data for the first four text fields are persisted, and I use local storage to only persist the values in the text field.

:slight_smile: