使用ajax加载后无法在DOM中找到元素(想要绑定jquery插件)

15
所以我有两个HTML页面。一个作为容器,一个作为内容。 当我加载带有表格的内容页面时,我可以使用拖放。
但是当我进入我的容器页面并将内容页面通过ajax加载到一个div中时,拖放功能停止工作。内容页面内的所有其他JavaScript功能仍然有效。如何将jquery dnd插件绑定到通过ajax加载的表格上?
我正在使用这个教程进行拖放:http://isocra.com/2008/02/table-drag-and-drop-jquery-plugin/ 我的代码看起来像这样:
$(window).load(function()
{   if(temp == 0)
    { 
        DP("eerste keer")
        load_table(); 
        temp = 1;
    }
} );

function load_table()
{    
    DP('load_table');
    $.ajax({
            //async: false,
            type: "POST",
            url: "/diagnose_hoofdpagina/table_diagnose/" + DosierID, // <== loads requested page
            success: function (data) {
                    $("#diagnoses_zelf").html(''); //<== clears current content of div
                    $("#diagnoses_zelf").append(data).trigger('create'); // <== appends requested page
                },
            error: function(){
                alert('error');
              } 
        }).done(function() {
        update_table(); 
        initialize_table();    // <== calls jquery plug in
        });

    return false;   
}


function initialize_table() 
{
    var tableid = $('#diagnoses_zelf table').attr('id'); //< this finds the correct table thanks to Fábio Batista => this option worked, rest didn't
    alert(tableid);
    $(tableid).tableDnD({    
        onDrop: function(table, row) {
        alert(table + "     "  +  row);

        },
        onDragStart: function(table,row){
        var tette = $(row).index;
        alert(tette);
        },
        dragHandle: ".dragHandle"
    });     
}

图片描述

这怎么可能?我该怎么办呢? 请有人帮帮我。

简短地说:

我想要访问通过ajax加载到我的容器页面中的表格的ID,并在其上使用jquery拖放插件。

编辑

发现:

一些奇怪的事情发生了,我的容器页面中的表格被重命名为pSqlaTable而不是我在控制器页面中给它指定的ID。

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

这就是代码无法再找到表的原因。感谢 Fábio Batista 写的这段代码,问题已经得到解决:

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

但是我现在该如何使用dnd插件呢?

它现在可以找到表格了,但我仍然无法将dnd插件绑定到它上面,我能否将jquery插件绑定到ajax加载的表格上?

编辑

//drag & drop http://isocra.com/2008/02/table-drag-and-drop-jquery-plugin/
function initialize_table() 
{
    var tableid = $('#diagnoses_zelf table').attr('id');
    alert(tableid);
    $('#' + tableid).tableDnD({    
        onDrop: function(table, row) {
        alert(table + "     "  +  row);

        },
        onDragStart: function(table,row){
        alert('issemer?');
        },
        dragHandle: ".dragHandle"
    });    
} 

这是我仍然困扰的代码。tableid是正确的,但jquery的初始化不正确。我无法拖动表格中的行。我的语法错了吗?
编辑
可能是因为我使用ZPT(或JavaScript)在其他页面上动态生成表格,所以无法将jquery绑定到表格上?

1
“gets stuck here” 在 .tableDnD 行的意思是什么?JS 控制台是否打印任何错误?如果有,请包含在内。如果没有,您可能是正确的,它无法找到 #tableDiagnose 元素,并且我会检查确保 HTML 正确地创建了该 ID。 - Don McCurdy
没有报错信息,我会检查表格是否获得正确的ID,但那应该不是问题所在。以防万一,直接把有效的控制器包含到容器页里面不行吗?或者我真的需要把拖放的逻辑放到容器页里面吗? - GertV
可以将HTML(例如您的控制器)嵌入容器中而不会破坏JS事件,但这需要在前端初始化HTML之后使用特殊的JS方法(如.detach和.append),或者确保您的ID不会更改,根据您下面的解决方案。我认为,这将是您看到的单独的后端错误。至于将“dnd逻辑放在容器页面上”,我会考虑将该JS模块化为共享的.js文件,以便根据需要重复使用,如果您需要在多个地方使用它。 - Don McCurdy
你能否执行 console.log(data) 并展示给我们看呢? - Kevin Schmid
6个回答

18

插件的问题。

您混合使用了许多外部库和代码。这会导致可能存在版本不匹配的情况,并且在您的代码中存在大量黑盒子。

作为开发人员,这应该让您感到非常不安。在代码库中有您完全不理解的代码会让你非常沮丧。

替代方案。

通常,这些插件提供的功能,作为 JavaScript 开发人员我们可以很容易地完成,而不需要它们。在简单的场景下,这种开发过程可以让我们创建理解的代码并更容易维护。我们不仅从这个过程中学习,而且还创造了更小的具体代码块。由社区驱动的解决方案总体上非常好,但重要的是要记住它们不是万能药。通常,您将被困在一个不太活跃的项目中,该项目对您特定情况存在错误,您必须搜索一个庞大而陌生的代码库。

您的代码

那么,这个拖放插件是做什么的呢?

嗯,我将其分解如下:

  • 监听表格行上的 mousedown 事件
  • 当此事件触发时,开始移动表格行以匹配鼠标位置
  • mouseup 发生时,检测到并确定位置。

让我们看看如何做类似的事情。 假设表格的HTML如下:

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

这里有一个带有一些基本样式的表格的fiddle

接下来,我们将监听选择事件。我们将为表格行添加一个选择事件,并为文档添加一个鼠标松开事件。jQuery有这些事件的监听器。由于我们希望这些事件即使在AJAX之后也能保持,所以我们将使用.on,它让我们使用委托事件。 .on的意思是即使我们稍后添加内容到表格中,也不会影响。

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;
});

这里有一个可用的Fiddle,展示了这段代码。

现在,我们需要实际改变拖放行为,使其更新当前位置以反映鼠标位置。我们可以监听mousemove事件,并检测我们当前所在的元素。大致如下:

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

您可以在此处查看工作的示例

这很好,但我们想要实际改变元素位置。因此,我们需要更改表结构以允许这样做。我们可以移除该元素,并将其附加到正确的位置。我们将检查是否有选定的元素,如果有,我们可以在mousemove事件中跟踪它与当前元素的比较。首先,我们可以使用以下代码检测是否应进行拖动:

$(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");
    }
});

(小提琴)

现在,我们将添加实际选择,当目标不是我们的元素且我们在表格中时,我们将替换元素。我们的完整代码应该类似于:

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)

到目前为止,我们只有几行代码,这很好,因为我们知道正在发生什么,并且不需要使用许多我们不完全理解的外部代码来完成。

但它能进行AJAX吗?

让我们使用AJAX将数据加载到表格中并查看!我们将使用setTimeout模拟AJAX响应,这将允许我们模拟异步请求。我们将使用

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);

这意味着在一秒钟后更新#MySpecialTable的HTML。让我们看看它是否有效呢?

那么为什么它有效呢?嗯,我们使用了委托事件,这意味着我们不关心正在加载的元素是否已经在屏幕上显示。我们之所以能够这样做,是因为我们自己构建了代码并知道我们的最终目标是什么。现在只需要稍微清理一下代码。

我们将把代码包装在以下内容中,以防止$在非冲突模式下成为问题(也就是说,$已经在页面中被占用):

(function($){

})(jQuery);

接下来,我们将为表格事件添加一个绑定。
$.GertVDragTable = function(elementSelector){ // rest of code.

最终,我们的代码可能会看起来像这样。 使用它将是一个简单的$.GertVDragTable("#MySpecialTable");,或者我们可以将其放在$.fn上并允许每个函数调用它。这只是一种品味问题。
请不要复制粘贴 :) 如果您在每个阶段停下来思考下一步的原因,我会很感激。

3
这句话的意思是:“这不是如何实现jQuery的答案,但是它帮助我完成了开始我的自己的拖放操作。感谢您的帮助和好文章。” - GertV

2

您不需要使用ID作为选择器,您可以使用任何能够找到您的表格的表达式。

如果在结果的$.ajax调用中只有一个表格,您可以搜索“容器内的表格”,并使用容器ID来查找,这个ID不会改变:

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

如果有多个表格,使用不同类型的选择器,而不是ID。CSS类可以很好地工作:

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

同样,data-属性也是如此:

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

3
请记住,data 属性是 HTML5 属性,不是所有浏览器都支持。 - Ghazanfar Mir

1
尝试为您的表格添加一个标题,像这样:


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

然后使用jQuery 属性选择器 来查找这个表格,而不是通过id查找。

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

这是一段不错的代码,但Fábio Batista的建议对我很有效。$('#diagnoses_zelf table').tableDnD( ... ); - GertV
它对我有所帮助,但并没有解决问题,所以我不会接受它作为答案。抱歉。 - GertV

1
如果您的ID正在更改,则不应再使用ID:
<table class="tableDiagnose table table-hover">

插件。
function initialize_table() 
{
    $('.tableDiagnose.table').tableDnD({    
        onDrop: function(table, row) {
        alert(table + "     "  +  row);
        },
        dragHandle: ".dragHandle"
    });   
    DP('nee');  
}

编辑:ajax 是异步的:

function load_table()
{    
    DP('load_table');
    $.ajax({
            //async: false,
            type: "POST",
            url: "/diagnose_hoofdpagina/table_diagnose/" + DosierID, // <== loads requested page
            success: function (data) {
                    $("#diagnoses_zelf").html(''); //<== clears current content of div
                    $("#diagnoses_zelf").append(data).trigger('create'); // <== appends requested page
                    update_table(); 
                    initialize_table();    // <== calls jquery plug in
                },
            error: function(){
                alert('error');
              } 
        });
        //removed .done as you already have a success option in ajax


    return false;   
}

编辑:发现了你的错误......你检索了表格ID,然后在$(tableid)中选择它,但你错过了#

function initialize_table() 
{
    /*
    var tableid = $('#diagnoses_zelf table').attr('id'); //< this finds the correct table thanks to Fábio Batista => this option worked, rest didn't
    alert(tableid);
    // but you really should limit the use of variables when you don't need them*/
    //$('#'+tableid).tableDnD({            
    //like this directly
    $('#diagnoses_zelf table').tableDnD({    
        onDrop: function(table, row) {
        alert(table + "     "  +  row);

        },
        onDragStart: function(table,row){
        var tette = $(row).index;
        //alert(tette);
        },
        dragHandle: ".dragHandle"
    });     
}

在这里查看演示

编辑


感谢您的输入,我使用了 $('#diagnoses_zelf table').tableDnD( ... ); 来解决(无法找到我的表格ID问题)。 - GertV
我应该把这个放在哪里呢?因为我看不出来这怎么能帮助我将插件绑定到表格。 - GertV
@GertV 哦,抱歉我搞错了。这是因为您在ajax完成工作之前初始化了表格。将ajax设置为同步选项async:false或将初始化代码移至“success”内(首选解决方案)。请参见我的编辑后答案。 - TecHunter
1
@GertV 请看我的编辑部分。您在表ID选择器中忘记了符号。 - TecHunter
1
我会让你知道我的发现,因为它在你的例子中可以工作,所以我将再次完全检查我的代码。 - GertV
显示剩余11条评论

0

@BenjaminGruenbaum 你好,非常感谢你的教程。我稍微修改了一下代码,以阻止表头的拖放,并通过跟踪鼠标方向来改善拖动流畅性。

var old_y = 0;
(function ($) {
    $.GertVDragTable = function (tableName) {
        var selected;
        $(document).on("mousedown", tableName+" tr",function (e) {
            e.preventDefault(); //stop the text selection;
            if (($(this).find('th').length)== 0){   //prevent dragging on tr containing th
            selected = $(this);
            selected.find("td").css("background-color", "black");
            selected.find("td").css("color", "white");
            }
        });

        $(document).on("mouseup", function () {
            selected.find("td").css("background-color", "");
            selected.find("td").css("color", "");
            selected = null;
        });
        $(document).on("mousemove", function (e) {
            if (selected != null ) { // got an element selected
                if ($(tableName).has(e.target).length > 0) { //in the table
                    var el = $(e.target).closest("tr"); //the tr element we're on
                    if (el.find('th').length==0){ //prevent dropping on headers row

                    if (e.pageY > old_y){       //**
                    el.after(selected);}else{   //**-->more fluid dragging based on mouse direction
                        el.before(selected);    //**
                    }

                }
                }
                old_y = e.pageY;
            }
        });

        $(tableName).on('selectstart', false); //Don't let the user select the table
    }
})(jQuery);

这里是 JSFiddle http://jsfiddle.net/59rdq/

希望对某些人有所帮助。


0
你是把脚本文件包含在容器页面还是内容页面中?我猜你可能想在调用拖放插件时使用getScript来加载它。
...
$.getScript('pathTotableDnDlib').done(function(){
    $(tableid).tableDnD({    
    onDrop: function(table, row) {
    alert(table + "     "  +  row);

    },
    onDragStart: function(table,row){
    var tette = $(row).index;
    alert(tette);
    },
    dragHandle: ".dragHandle"
});});
...

更多关于getscript的信息:这里


首先,我将它添加到我的内容页面中。在那里一切都正常,直到我将其加载到容器页面中。现在我将代码转移到了容器页面。脚本本身是可调用的,所以我不明白为什么我不能将其绑定到表格上。我能否将jQuery插件绑定到已加载的内容上? - GertV
@GertV 当然可以。如果ID正确,内容加载正常,并且插件本身是可“插拔”的。您可以尝试从开发者控制台加载内容并尝试绑定插件。要检查插件是否已加载,请尝试调用$().tableDnD,它应该输入函数字符串,如果是这样,请尝试调用initialize_table(),如果插件(在调用后)被绑定,则可能是同步问题。 - Igarioshka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接