Can't find element in DOM after loading it with ajax (want to bind jquery plug in to it) Can't find element in DOM after loading it with ajax (want to bind jquery plug in to it) ajax ajax

Can't find element in DOM after loading it with ajax (want to bind jquery plug in to it)


The issue with plugins.

You're mixing lots of external libraries and code. This results in possible mis-matches between versions, and a lot of black boxes in your code.

As a developer, this should make you feel very uneasy. Having code you do not fully understand in your code base can get really frustrating really fast.

The alternative.

Often, these sort of plugins provide functionality we, as JavaScript developers can accomplish just as easily without them. This development process, in simple enough scenarios, lets us create code we understand and have an easier time maintaining. Not only do we learn from this process, but we also create smaller bits of specific code. Community driven solutions are very good in general, but it's important to remember they're not a silver bullet. Often you're stuck using a not-so-active project which has a bug for your specific case and you have to dig through a large, unfamiliar code base.

Your code

So what does this drag and drop plugin do?

Well, I'd break it down as the following:

  • Listens to the mousedown event on table rows
  • When such an event fires, start moving the table row to match the mouse position
  • When mouseup occurs, detect that, and finalize the position.

Let us see how we can do something similar. Let's assume the table's HTML is something like:

<table>    <tbody>    <tr>        <td> Hello 1</td>    </tr><tr>        <td> Hello 2</td>    </tr>    </tbody></table>

Here is a fiddle with the table with some basic styling applied

Next, we'll listen to the selection events. We'll add an event to the table rows for selection and to the document to when the mouse is up. jQuery has event listeners for such events. Since we want these events to stick even after AJAX, we'll use .on which lets us use delegated events. .on means that even if we add content to the table later, it won't matter.

var selected; // currently selected row$(document).on("mousedown","#MySpecialTable tr",function(){   $("#textDiv").text(this.textContent);     selected = this;});$(document).on("mouseup",function(){    $("#textDiv").text("Left "+selected.textContent);     selected = null;});

Here is a working fiddle of such code.

Now, we'll want to actually change the drag&drop to work when, that is, update the current position to the one reflecting the mouse position. We can listen to mousemove events, and detect the element we're currently on. Something like

$(document).on("mousemove",function(e){    $("#textDiv").text($(e.target).html());});

You can see a working fiddle here

That's nice, but we want to actually change the element position. So we'll need to change the table structure to allow that. We can remove the element, and append it at the correct position. We'll check if we have a selected element, and if we do, we can track it compared to the current element in the mousemove event. We can for starters detect if we should drag with something like:

$(document).on("mousemove",function(e){    if(selected !=null){// got an element selected        if($("#MySpecialTable").has(e.target).length > 0){ //in the table            $("#mousePos").text("DRAGGING");            }    }else{        $("#mousePos").text("NOT SELECTED");    }});

(Fiddle)

Now, we'll add actual selection, we'll replace the elements when the target is not our element and we're in the table. Our full code should be something like:

var selected;$(document).on("mousedown","#MySpecialTable tr",function(e){    e.preventDefault();//stop the text selection;   $("#textDiv").text(this.textContent);     selected = $(this);    selected.find("td").css("background-color","#999");});$(document).on("mouseup",function(){    $("#textDiv").text("Left "+selected.text());     selected.find("td").css("background-color","");    selected = null;});$(document).on("mousemove",function(e){    if(selected !=null){// got an element selected        if($("#MySpecialTable").has(e.target).length > 0){ //in the table            var el = $(e.target).closest("tr");//the tr element we're on            el.before(selected);// replace the elements        }    }else{        $("#mousePos").text("NOT SELECTED");    }});$("#MySpecialTable").on('selectstart', false);//Don't let the user select the table

(Fiddle)

Now, so far we only have a few lines of code, which is nice since we know exactly what's going on and didn't need to use lots of lines of external code we don't fully understand.

But will it AJAX?

Let's load the data into the table with AJAX and see! We'll simulate an AJAX response using a setTimeout which would allow us to simulate an asynchronous request. We'll use

setTimeout(function(){    $("#MySpecialTable").html("<tr><td> Hello 1</td></tr><tr><td> Hello 2</td></tr><tr><td> Hello 3</td></tr><tr><td> Hello 4</td></tr><tr><td> Hello 5</td></tr><tr><td> Hello 6</td></tr>");},1000);

This means, update the HTML of #MySpecialTable after one second. Let's see if it works shall we?

So why does it work? well, we used delegated events which means we don't care if the elements we're loading are in the screen right now or not. We had the insight to do this since we built our code ourselves and knew what our final goal was. The only thing left to do is clean the code a little.

We'll wrap our code in the following, to prevent $ from being an issue in non-conflict mode (that is, $ is already taken in the page:

(function($){})(jQuery);

Next we'll add a binding for our table event:

$.GertVDragTable = function(elementSelector){ // rest of code.

Eventually, our code might look something like this.

Using it, would be a simple $.GertVDragTable("#MySpecialTable"); alternatively, we can put it on $.fn and allow every function to call it. Which is a matter of taste.

No copy-pasta please :) I'd appreciate it if you stop on every stage and think why the next step was taken.


You don't need to use the ID as a selector, you can use any expression that can find your table.

If there's only one table on the resulting $.ajax call, you can search for "a table inside the container", using the container ID, which won't change:

$('#diagnoses_zelf table').tableDnD( ... );

If there's more than one table, use a different kind of selector, instead of the ID. A CSS class works fine:

$('table.table-diagnose').tableDnD( ... );

So does a data- attribute:

$("table[data-diagnose]").tableDnD( ... );


Try adding a title to your table, like so:

<table id = "tableDiagnose" class = "table table-hover" title = "table-content">

Then use the jQuery attribute selector to find this table instead of finding it by id.

$('table[title="table-content"]').tableDnD({ // the rest of your code