cure
cure

Reputation: 2688

making a new div draggable, tried everything

Hello stackoverflow comunity.

I am working on some code that makes draggable resizeable divs. I have it working with the divs that are created originally, but the newly added divs arent becomming draggable.

Here is ALL my code:

<html>
   <head>
      <script>
     var id = 4;
     function drag(ev)
     {
        ev.dataTransfer.setData("Text",ev.target.id);
     }

     function drop(ev)
     {
        ev.preventDefault();
        ev.target.appendChild(document.getElementById(ev.dataTransfer.getData("Text")));
    }
function change(div)
    {
    var divw=parseInt(div.style.width);
    var divh=parseInt(div.style.height);
    var imgw=divw-10;
    var imgh=divh-10;
    div.children[0].style.width=imgw;
    div.children[0].style.height=imgh;
    div.style.border="dotted 3px grey";
    }
function addimg()
    {
    var main = document.getElementById('main');
    var div  = document.createElement('div');
    div.onmouseout = function() {this.style.border=0};
    div.ondragstart = function() {drag(event)};
    div.onmousemove = function() {change(this)};
    div.setAttribute('draggable', true);
    div.id = 'div'+id;
        id+=1;
        div.style.styleFloat = 'left';
        div.style.cssFloat = 'left';
        div.style.resize = 'both';
        div.style.overflow = 'hidden';
        div.style.height = '110px';
        div.style.width = '110px';
        div.innerHTML = '<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />';
        main.appendChild(div);
     }
      </script>
   </head>   
   <body>
      <center>
     <div ID="main" ondragover="event.preventDefault()" ondrop="drop(event)" style="width:900px; height:900px; border: dashed 1px lightgrey;" overflow="auto">
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
           <textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML" style="resize:none; width: 100px; height: 100px"></textarea>
           <p style="background-color: blue"></p>
        </div>
        <div style="clear:both"></div>
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
          <img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
        </div>   
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
          <img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
        </div>   
     </div>
      </center>
      <button onclick="addimg()">add an image</button>
   </body>
</html>

the issue is that the new divs aren't draggable.

P.S. if you use jquery, please explain it very detailed, i have no experience with it.

Upvotes: 0

Views: 1518

Answers (2)

Mr Br
Mr Br

Reputation: 3901

I m not sure what draggable function in this case is. Is it just dragging this newly added image to this element in top left ? After what that image disappear ?

If this is case, solution is very simple. In function addimage you have wrong line.Your line is:

div.ondragstart = function() {drag(event)};

And it should be

div.ondragstart = function(event) {drag(event)};

In this line you call function without setting event as argument, and you use it in function. Hope it helps.

Upvotes: 2

Henry Florence
Henry Florence

Reputation: 2866

One solution is to use the same method used to create the <img> element, to create the <div>:

<html>
   <head>
      <script>
      var id = 4;
      function drag(ev) {
        ev.dataTransfer.setData("Text",ev.target.id);
      }

      function drop(ev) {
        ev.preventDefault();         
        document.getElementById('main')
                .appendChild(document.getElementById(ev.dataTransfer.getData("Text")));
      }

      function change(div) {
        var divw = parseInt(div.style.width);
        var divh = parseInt(div.style.height);
        var imgw = divw - 10;
        var imgh = divh - 10;
        div.children[0].style.width = imgw;
        div.children[0].style.height = imgh;
        div.style.border = "dotted 3px grey";
      }
      function addimg() {
        var main = document.getElementById('main');
        main.innerHTML += '<div id="div'+id+'" onmouseout="this.style.border=0" draggable="true" ' +
                          'ondragstart="drag(event)" onmousemove="change(this)" style="float:left; ' +
                          'resize:both; overflow:hidden; height: 110px; width:110px"></div>';
        div = document.getElementById('div'+id);
        div.innerHTML = '<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />';
        id+=1;
      }
      </script>
   </head>   
   <body>
      <center>
     <div ID="main" ondragover="event.preventDefault()" ondrop="drop(event)" style="width:900px; height:900px; border: dashed 1px lightgrey;" overflow="auto">
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
           <textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML" style="resize:none; width: 100px; height: 100px"></textarea>
           <p style="background-color: blue"></p>
        </div>
        <div style="clear:both"></div>
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
          <img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
        </div>   
        <div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
          <img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
        </div>   
     </div>
      </center>
      <button onclick="addimg()">add an image</button>
   </body>
</html>

This should ensure the browser renders the new <div> element in the same way as the existing ones. In addition ensuring that elements are appended back to the main <div> element when they are dropped, will prevent them from disappearing when dropped onto of other elements, as previously.

Using Jquery

On the tip of using jquery, if we include the jquery.min.js library at the top of the file:

<script src="http://code.jquery.com/jquery-1.9.1.js"></script>

The change() function can be rewritten as:

function change(div) {
    var $div = $(div);
    $div.css('border','dotted 3px grey')
        .children( ':first' )
        .width( $div.width() - 10 )
        .height( $div.height() - 10 );
}

This is somewhat shorter than the original. The first line converts the div parameter into a jquery object and stores it in the $div variable. The $ at the beginning of the variable name is just a convention, as the variable contains a jquery object. Caching the jquery object in this variable is more efficient than using $(div) 3 times in the change() function.

Calls to$div.width() and $div.height() perform the same action as the parseInt() calls in the original function. Jquery allows function calls to be 'chained', thus the first call on $div sets the border style and returns the same $div object. The .children() call returns the first child of $div (the <img> element) which then has it's width and height set using the corresponding methods.

It should be noted that jquery is generally thought to be easier to use, and offer good cross browser compatibility (which can be a real headache) rather than more efficient.

Moving style out of elements

We can move the common style attribute out of the individual elements into a separate section in the <head> of the html:

<style>
    #main {
      width:900px; 
      height:900px; 
      border: dashed 1px lightgrey;
      overflow: auto;
    }
    .dragDiv {
      float: left; 
      resize: both; 
      overflow: hidden; 
      height: 110px; 
      width: 110px;
    }
   .dragDiv img {
      width: 100px; 
      height: 100px
   }
   .dragDiv textarea {
      resize: none; 
      width: 100px; 
      height: 100px;
   }
</style>

By giving the drag-able <div> elements the class dragDiv we reduce the amount of style duplication:

<div id="main" ondragover="event.preventDefault()" ondrop="drop(event)">
    <div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1">
       <textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML"></textarea>
       <p style="background-color: blue"></p>
    </div>
    <div style="clear:both"></div>
    <div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2">
      <img draggable="false" src="https://www.google.com/images/srpr/logo11w.png" />
    </div>   
    <div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3">
      <img draggable="false" src="https://www.google.com/images/srpr/logo11w.png" />
    </div>   
</div>

Is this something like what you are looking for? I'm happy to suggest more alterations, if required.

Jquery offers draggables - which use absolute positioning; resizables; and sortables - which offer similar 'snap on drop' behaviour as the code above. Although I don't suggest you use these instead, they might be good guides as to how you wish your code to behave.

Upvotes: 1

Related Questions