How do I rebind the dialog after it is being rewri

2019-07-17 05:47发布

I have a table of students and in each row are their names, a select list to select their attendance for their lesson and then a "Message" link when clicked will popup a a dialog to send a message to the student.

The table is dynamically driven by a select list of courses. For example, a teacher selects a course and then the table is repopulated with all the students within that course. This is done through AJAX. The table body is basically getting written every time a course is selected. My problem is this, when a new course is selected, the div for the dialog becomes visible inside the cell of the Message link. I suspect the problem is to do with AJAX and not being able to rebind the link and click event. How do I therefore overcome this?

This is my table generated in 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;     
}

This is the jQuery to handle the dialog and the table:

/** 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

Everything works fine until a new course is selected and the textarea becomes visible inside the cell. I've only just started jQuery last month so bear with me!

10条回答
贼婆χ
2楼-- · 2019-07-17 06:00

I have a simplify example here

Basically, you need a delegate function or most people recommend live. Delegate is basically, similar function to live but instead of bind to the top document, delegate only bind to specific dom that you specified. Therefore, it is not possible to have stopPropagation in live. Also, live is deprecated in jquery 1.7

if you lazy to see the fiddle, here is the code

<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!');
});​​

I hope it helps

查看更多
劫难
3楼-- · 2019-07-17 06:06

As I understands, each row has its own markup for dialogs and the code that creates those dialogs is executed only once, during page load:

/** Dialog Handler **/
$('.popUpLink').each(function()
{ ... }

But this code should be called on startup AND every time you repopulate your table, because markup for dialogs is located inside row cells. I suggest you to put this code in a function:

var initDialogs = function() {
    $('.popUpLink').each(function()
    {
      ... 
    }).on('click', function(){
      ...
    });
}

Call it right after page load, and each time you repopulate table:

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

Also, I noticed how you create your table rows inside foreach loop. Every row will have the same id's, like this one <td id="studentName">. Having many id's repeated on the page is not OK, it can leads to problems that hard to debug.

I hope it helps.

EDIT: Just noticed, it is almost the same approach that @Lazerblade proposed.

查看更多
放我归山
4楼-- · 2019-07-17 06:06

You should not be using click() with elements which are dynamically added to a page because this jQuery method has no way of binding future events to these elements. It's fine for static pages and documents, but not for functionality which inserts, deletes or modifies objects on the page.

Instead, you need to use on() because it allows you to bind future events. You need to implement it like this:

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

At the moment, from the sound of things, you're only using live() as a potential substitute. Don't use this because as of jQuery 1.7 it is deprecated. Refactoring all out-of-date code like this is an absolute must in any web project -- you can't just refuse to change things because of the range and depth of existing implementation. In fact, that should only motivate you more: because if you leave the site with deprecated software something's going to go wrong.

If you're unsure about how you can change from live() to on(), see jQuery's documentation which provides a succinct and easy way to update existing functionality.

查看更多
叛逆
5楼-- · 2019-07-17 06:08

If I got your question right you should use

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

or

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

instead of

.click(function()
{
    $.data(this, 'dialog').dialog('open');
    return false;
});
查看更多
来,给爷笑一个
6楼-- · 2019-07-17 06:10

I had a similar issue when building with AJAX a dialog for "Upload complete" and such, just destroy the dialog before you create it like:

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; 
}); 
查看更多
姐就是有狂的资本
7楼-- · 2019-07-17 06:12

Here's your javascript, rewritten to include modified syntax for recalling the .each() for the popUpLink after reloading. I've also bound the popUpLink to the outer form wrapper. Also, verify that your jQuery has been updated to the latest version, 1.7.2, in order to use the .on() function:

/** 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
查看更多
登录 后发表回答