2012-04-02 90 views
2

我有一張學生表,每行都是他們的名字,一個選擇列表來選擇他們的出席課程,然後點擊一個「消息」鏈接將彈出一個對話框發送消息給學生。如何在AJAX重寫對話框後重新綁定對話框?

該表由選定的課程列表動態驅動。例如,一位老師選擇一門課程,然後將該表格與該課程中的所有學生一起填寫。這是通過AJAX完成的。每次選擇課程時,表格體基本上都會寫入。我的問題是,當選擇新課程時,對話框的div在消息鏈接的單元格內變得可見。我懷疑問題是與AJAX有關,無法重新綁定鏈接和點擊事件。我如何克服這個問題?

這是(http://pastebin.com/CTD3WfL6)在PHP中生成我的表:

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:[email protected]" 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 

一切工作得很好,直到選擇了新課程並且textarea在單元格內變得可見。我上個月剛剛開始使用jQuery,所以請耐心等待!

+0

對話框div在ajax調用後可見的原因是因爲您沒有明確隱藏它。對話框初始化代碼只在第一次加載頁面時運行一次,這就是隱藏原始div的原因。每個Ajax調用後代碼都不會再運行 – gary 2012-04-12 20:14:25

回答

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提出的方法幾乎是一樣的。

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

仍然不能工作:( – 2012-04-02 14:23:36

5

不應使用click()與作爲動態元素添加到頁面becau如果這個jQuery方法沒有辦法將未來的事件綁定到這些元素上。靜態頁面和文檔很好,但不適用於在頁面上插入,刪除或修改對象的功能。您需要使用on(),因爲它允許您綁定將來的事件。您需要實現這樣的:

$(document).on('change', '#courseSelect', function() 
{ 
    // Your existing code here 
} 

目前,從事物的聲音,你只使用live()作爲一個潛在的替代品。不要使用它,因爲從jQuery 1.7開始,它已被棄用。像這樣重構所有過時的代碼在任何Web項目中都是絕對必須的 - 您不能因爲現有實現的範圍和深度而拒絕改變內容。事實上,這應該只會激勵你更多:因爲如果你使用棄用的軟件離開網站會出現問題。

如果您不確定如何從live()更改爲on(),請參閱jQuery's documentation,它提供了一種簡潔而簡單的方法來更新現有功能。

+0

嘿,是的,看到我的編輯,我已經更新了一切,但它仍然無效:/我認爲這是因爲我的每次選擇新課程時都會重新生成表格,這意味着所有彈出對話框都將被完全覆蓋,但jQuery應該能夠處理該問題 – 2012-04-11 21:00:24

+0

您的問題只有'live()',它不起作用。你需要使用'on()'。 – hohner 2012-04-11 21:02:16

+0

我在回答中加入了一點點,指出你不應該擔心修改現有的軟件,或者懷着誠惶誠恐的方式重構代碼,它應該是相反的 - 它應該是對每個項目都是關鍵的東西:) – hohner 2012-04-11 21:07:00

0

您正在覆蓋表,因此每次都會丟失對話框的狀態。

+0

是的,我知道,這是問題,我需要重新綁定它,但即使更新也沒有任何工作我所有的jQuery處理程序到最新版本 – 2012-04-12 09:39:09

1

這是一個更簡單的例子。我希望它能證明你在問什麼。您可以看到一個工作版本http://jsfiddle.net/4wEPm/2/

當您用ajax覆蓋表的內容時,對該對話框的引用丟失。我認爲只需再次重新初始化對話框就更簡單了。

我在表上使用委託(根據您的示例,表元素不會被覆蓋,只是行)。通過這種方式,點擊監聽器將在ajax調用之後保持。每當對話框div由jquery初始化時,div就移動到頁面的末尾。所以,我在錨點中添加了對話框對象的引用,只是爲了方便訪問調用對話框('打開')。由於我正在處理初始化,並在同一個點擊函數中打開對話框,因此對話框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> 

0

通常,jQuery的結合的所有元件與負載時間但是它不能由。點擊被結合到動態事件功能()方法在動態事件綁定中使用更有效的.live方法。
您也可以嘗試使用實時功能。 http://docs.jquery.com/Events/live,並在例如 http://api.jquery.com/live/

應用將是後讀一些類似

$('.popUpLink').live('click',function() 
{ 
    $.data(this, 'dialog').dialog('open'); 
    return false; 
}); 
0

我有一個簡化例子here

基本上,你需要一個委託功能或多數人推薦住。 委託基本上是類似於生存的函數,但不是綁定到頂層文檔,委託只綁定到您指定的特定dom。因此,不可能實時停止傳播。 此外,住在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!'); 
});​​ 

我希望它能幫助

2

這是你的javascript,改寫,包括修改語法在重新加載之後回顧popUpLink的.each()。我還將popUpLink綁定到外部表單包裝。此外,請驗證您的jQuery已更新到最新版本1.7.2,以便使用。在()函數:

/** 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 
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; 
}); 
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.*/ 


});