我有一个学生表,每行都有他们的名字,一个选择列表来选择他们的课程出勤,然后单击“消息”链接会弹出一个对话框向学生发送消息。
该表由选择的课程列表动态驱动。例如,教师选择一门课程,然后该课程将重新填充该课程中的所有学生。这是通过AJAX完成的。每次选择课程时,表体基本上都会被写入。我的问题是,当选择新课程时,对话框的div在Message链接的单元格内变得可见。我怀疑问题与AJAX有关,无法重新绑定链接和点击事件。因此,我如何克服这个问题?
这是我在PHP中生成的表格(http://pastebin.com/CTD3WfL6):
public function createTable($cid)
{
$userModel = new Users();
$attendanceModel = new Attendance();
$students = $userModel->getStudents($cid);
$table2 = '<table id="tutorTable">';
$tableHeaders =
'<thead>
<th>Student Name</th>
<th>Attendance</th>
<th>Message</th>
<th>Mobile</th>
<th>Parent Name</th>
<th>Message</th>
</thead>
<tbody>';
$table2 .= $tableHeaders;
foreach($students as $student)
{
$table2 .=
'<tr><td id="studentName">'.$student['firstname'].' '.$student['lastname'].'</td>
<td>
<select class="attendSelect" id="studentSelect"'.$student['id'].'>
<option value="Attended">Attended</option>
<option value="Absent">Did not Attend</option>
<option value="Excused Absent">Excused</option>
<option value="Late">Excused</option>
<option value="Excused Late">Did not Attend</option>
</select>
</td>
<td>
<a href="#MessageStudent" class="popUpLink">Message</a>
<div class="popUpDialog" id="'.$student['id'].'" title="Message '.$student['firstname'].' '.$student['lastname'].'">
<form id="studentForm" action="" method="POST">
<fieldset>
<input type="hidden" value="message_send" name="action"/>
<input type="hidden" value="'.$student['id'].'" name="studentId"/>
<textarea rows="3" cols=35" name="message"></textarea>
<input type="submit" value="Send Message"/>
</fieldset>
</form>
</div>
</td>
<td>'.$student['phone1'].'</td>
<td>Parent name goes here</td>
<td>
<a href="mailto:ParentsEmail@email.com" id="parentEmail">Message</a>
</td>
</tr>';
}
$table2 .= '</tbody></table>';
return $table2;
}
这是处理对话框和表格的jQuery:
/** Dialog Handler **/
$('.popUpLink').each(function()
{
$divDialog = $(this).next('.popUpDialog');
$.data(this, 'dialog', $divDialog.dialog(
{
autoOpen: false,
modal: true,
title: $divDialog.attr('title')
}));
}).on('click',function()
{
$.data(this, 'dialog').dialog('open');
return false;
});
/**AJAX to handle table **/
$('#courseSelect').on('change', function()
{
var cid = $('#courseSelect').val();
$.getJSON('?ajax=true&cid=' + cid, function(data)
{
var lessonSelect = "";
var count = 1;
/** populate select list of lessons **/
for(var i in data.lessons)
{
lessonSelect += '<option id="' + count + '" value="' + data.lessons[i].id+ '">' + data.lessons[i].name + '</option>'
count++;
};
var lessonDialog = '<p>' + data.lessons[0].name + '</p>';
var launchLessonDiv = '<a href=" ' + data.launchLesson.reference + ' ">Launch Lesson</a>';
var courseDialog = '<p>' + data.course.fullname + '</p>';
$('#lessonSelect').html(lessonSelect);
$('#lessonDialog').html(lessonDialog);//insert lesson information into lesson dialog
$('#launchLessonDiv').html(launchLessonDiv);//insert link to launch lesson
$('#courseDialog').html(courseDialog);
/**Repopulate table **/
//var lessonCount = 1;
//var table = createTutorTable(data, cid, lessonCount);
//$('table#tutorTable>tbody').html(table);
$('form#tutorTableForm').html(data.table);
});//getJSON
});//Course select
一切正常,直到选择新课程并且文本区域在单元格内变得可见。我上个月刚刚开始使用jQuery,所以请耐心等待!
答案 0 :(得分:5)
您不应该将click()
与动态添加到页面的元素一起使用,因为此jQuery方法无法将未来事件绑定到这些元素。它适用于静态页面和文档,但不适用于在页面上插入,删除或修改对象的功能。
相反,您需要使用on()
,因为它允许您绑定未来事件。你需要像这样实现它:
$(document).on('change', '#courseSelect', function()
{
// Your existing code here
}
目前,从事物的声音来看,你只是使用live()
作为潜在的替代品。不要使用它,因为从jQuery 1.7开始,它已被弃用。在任何Web项目中重构所有过时的代码都是绝对必要的 - 由于现有实现的范围和深度,您不能仅仅拒绝改变。事实上,这应该只会激励你更多:因为如果你使用已弃用的软件离开网站会出现问题。
如果您不确定如何从live()
更改为on()
,请参阅jQuery's documentation,它提供了一种简洁易用的方式来更新现有功能。
答案 1 :(得分:2)
这是你的javascript,重写为包含修改后的语法,用于在重新加载后调用popUpLink的.each()。我还将popUpLink绑定到外部表单包装器。另外,验证您的jQuery已更新到最新版本1.7.2,以便使用.on()函数:
/** Dialog Handler **/
function reSetPop() {
$('.popUpLink').each(function() {
$divDialog = $(this).next('.popUpDialog');
$.data(this, 'dialog', $divDialog.dialog({
autoOpen: false,
modal: true,
title: $divDialog.attr('title')
}));
});
}
reSetPop();
$('#tutorTableForm').on('click', '.popUpLink', function() {
$.data(this, 'dialog').dialog('open');
return false;
});
/**AJAX to handle table **/
// let's assume your select, below, is part of the form and replaced as well
$('#tutorTableForm').on('change', '#courseSelect', function() {
var cid = $('#courseSelect').val();
$.getJSON('?ajax=true&cid=' + cid, function(data) {
var lessonSelect = '';
var count = 1;
/** populate select list of lessons **/
for(var i in data.lessons) {
lessonSelect += '<option id="' + count + '" value="' + data.lessons[i].id+ '">' + data.lessons[i].name + '</option>';
count++;
};
var lessonDialog = '<p>' + data.lessons[0].name + '</p>';
var launchLessonDiv = '<a href=" ' + data.launchLesson.reference + ' ">Launch Lesson</a>';
var courseDialog = '<p>' + data.course.fullname + '</p>';
$('#lessonSelect').html(lessonSelect);
$('#lessonDialog').html(lessonDialog);//insert lesson information into lesson dialog
$('#launchLessonDiv').html(launchLessonDiv);//insert link to launch lesson
$('#courseDialog').html(courseDialog);
/**Repopulate table **/
$('form#tutorTableForm').html(data.table);
reSetPop();
});//getJSON
});//Course select
答案 2 :(得分:2)
据我所知,每一行都有自己的对话标记,创建这些对话框的代码只在页面加载期间执行一次:
/** Dialog Handler **/
$('.popUpLink').each(function()
{ ... }
但是每次重新填充表时都应该在启动时调用此代码,因为对话框的标记位于行单元格内。我建议你把这段代码放在一个函数中:
var initDialogs = function() {
$('.popUpLink').each(function()
{
...
}).on('click', function(){
...
});
}
在页面加载后立即调用它,每次重新填充表时都会调用它:
initDialogs();
$('#courseSelect').on('change', function()
{
var cid = $('#courseSelect').val();
$.getJSON('?ajax=true&cid=' + cid, function(data)
{
// .. lots of code here
// then you populate your table
// (can't find #formTableForm in your example though)
//$('table#tutorTable>tbody').html(table);
$('form#tutorTableForm').html(data.table);
// now your table filled, old dialogs gone.
// init dialogs again.
initDialogs();
});//getJSON
});
另外,我注意到你如何在foreach循环中创建表行。每一行都有相同的ID,就像这一行<td id="studentName">
一样。在页面上重复了很多id是不行的,它可能导致难以调试的问题。
我希望它有所帮助。
编辑:刚刚注意到,这几乎和@Lazerblade提出的方法相同。
答案 3 :(得分:1)
这是一个更简单的例子。我希望它能够证明你的要求。您可以在http://jsfiddle.net/4wEPm/2/
查看工作版本使用ajax覆盖表的内容时,对对话框的引用将丢失。我认为再次重新初始化对话框会更容易。
我在表上使用委托(根据您的示例,表元素不会被覆盖,只有行)。这样点击监听器将在ajax调用后保持不变。每当通过jquery初始化对话框div时,div就会移动到页面的末尾。因此,我在锚点中添加了对象对象的引用,只是为了方便访问调用对话框(&#39;打开&#39;)。由于我在同一个单击函数中处理初始化和打开对话框,因此需要隐藏对话框div。
此外,在ajax调用中,最好清理旧的对话框,因为新的对话框将被创建。
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" />
<div>
<table id="t1" border="1">
<tr>
<td><a href="" class="popup">message 1</a>
<div class="dlog" style="display: none">dialog 1</div>
<p>stuff</p>
<p>
<button class="btn"> faking ajax </button>
</p>
</td>
</tr>
<tr>
<td><a href="" class="popup">message 2</a>
<div class="dlog" style="display: none">dialog 2</div>
<p>stuff</p>
<p>
<button class="btn"> faking ajax </button>
</p>
</td>
</tr>
</table>
<br/><br/>
<script>
$("#t1").on('click', '.popup', function(e){
/*
initialize the dialog box on the first click of the message link
and insert a reference to the newly created dialog box, the next
time the link is clicked, don't need to initialize, just invoke open
*/
if (typeof $(this).data("dialog-ref") == "undefined"){
$(this).data("dialog-ref", $(this).next('.dlog').dialog({ modal: true }));
}else {
$(this).data("dialog-ref").dialog('open');
}
return false; // don't follow the link.
});
// this is just to fake the ajax calls and overwrites the table content.
$("#t1").on('click', '.btn', function(){
// clean up of the old dialog boxes, because the new content will have new dialog boxes.
$('#t1 .popup').each(function() {
try {
$(this).data('dialog-ref').dialog('destroy');
}catch(err) {
}
});
var x = Math.floor(Math.random() * 100);
var table = $("<tr><td><a href='' class='popup'>message "+x+"</a><div class='dlog' style='display: none'>dialog "+x+"</div><p>stuff</p><button class='btn'> faking ajax </button></td></tr><tr><td><a href='' class='popup'>message "+(x+1)+"</a><div class='dlog' style='display: none'>dialog "+(x+1)+"</div><p>stuff</p><p><button class='btn'> faking ajax </button></p></td></tr>");
$("#t1").html(table);
});
</script>
答案 4 :(得分:0)
如果我的问题得到了解决,你应该使用
.live('click',function()
{
$.data(this, 'dialog').dialog('open');
return false;
});
或
.on('click',function()
{
$.data(this, 'dialog').dialog('open');
return false;
});
而不是
.click(function()
{
$.data(this, 'dialog').dialog('open');
return false;
});
答案 5 :(得分:0)
您正在覆盖表格,因此每次都会丢失对话框的状态。
答案 6 :(得分:0)
一般来说,jQuery会在加载时将所有元素与事件绑定在一起但是它不能通过.click()方法绑定到动态函数上。这样使用.live方法在动态事件绑定中更有效。
您也可以尝试使用实时功能。 http://docs.jquery.com/Events/live并以示例的方式阅读
http://api.jquery.com/live/
将是
$('.popUpLink').live('click',function()
{
$.data(this, 'dialog').dialog('open');
return false;
});
答案 7 :(得分:0)
我有一个简化示例here
基本上,您需要委托功能或大多数人推荐直播。 委托基本上是类似于生存的功能,但是委托只绑定到您指定的特定dom,而不是绑定到顶层文档。因此,不可能在现场进行stopPropagation。 另外,live在jquery 1.7中被弃用
如果你懒得看小提琴,这里是代码
<input id="madButton" type="button" value="add dynamic link" />
<div id="container"></div>
$('#madButton').on('click',function() {
var linkDom = '<a class="dynamicLink" href="#">click me</a><br/>';
$('#container').append(linkDom);
});
$('#container').delegate('.dynamicLink', 'click', function() {
alert('say aye!');
});
我希望它有所帮助
答案 8 :(得分:0)
在使用AJAX构建“上传完成”对话框时遇到了类似问题,只需在创建对话框之前销毁对话框,如:
on('click',function(e) {
$.data(this, 'dialog').dialog('destroy').dialog('open');
/**
* You could also use e.preventDefault() instead of
* "return false" as and alternative
*/
return false;
});
答案 9 :(得分:0)
$('#tutorTable').delegate('.clickElement', 'click' function(){
var elem = $(this); //which will be your div/dialog if you supply the right selector
/*No need to rebind events since this handler will be attached to the #tutorTable
It will listen for the desired event and delegate it back
to the element that matches the supplied selector.*/
});