Как заново связать диалог после его перезаписи AJAX? - PullRequest
2 голосов
/ 02 апреля 2012

У меня есть таблица учеников, и в каждой строке указаны их имена, список выбора для выбора посещаемости для их урока, а затем при нажатии на ссылку «Сообщение» появится диалоговое окно для отправки сообщения ученику.

Таблица динамически управляется выбранным списком курсов. Например, учитель выбирает курс, а затем таблица заполняется всеми учащимися в этом курсе. Это делается через AJAX. Тело таблицы в основном пишется каждый раз, когда выбирается курс. Моя проблема в том, что при выборе нового курса div для диалога становится видимым внутри ячейки ссылки на сообщение. Я подозреваю, что проблема связана с 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 в прошлом месяце, так что терпите меня!

Ответы [ 10 ]

5 голосов
/ 12 апреля 2012

Вы не должны использовать click() с элементами, которые динамически добавляются на страницу, потому что этот метод jQuery не имеет возможности привязывать будущие события к этим элементам.Это хорошо для статических страниц и документов, но не для функциональности, которая вставляет, удаляет или изменяет объекты на странице.

Вместо этого вам нужно использовать on(), потому что это позволяет связыватьбудущие события.Вам нужно реализовать это так:

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

На данный момент, исходя из звука вещей, вы используете только live() в качестве потенциального заменителя.Не используйте это, потому что с jQuery 1.7 это устарело.Рефакторинг всего устаревшего кода, подобного этому, абсолютно необходим в любом веб-проекте - вы не можете просто отказаться от изменений из-за диапазона и глубины существующей реализации.На самом деле, это должно только мотивировать вас больше: потому что, если вы покинете сайт с устаревшим программным обеспечением, что-то пойдет не так.

Если вы не знаете, как можно перейти с live() на on(),см. документацию jQuery , которая предоставляет краткий и простой способ обновления существующей функциональности.

2 голосов
/ 18 апреля 2012

Как я понимаю, у каждой строки есть своя разметка для диалогов, и код, который создает эти диалоги, выполняется только один раз, во время загрузки страницы:

/** 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. Каждая строка будет иметь одинаковые идентификаторы, как этот <td id="studentName">. Повторение большого количества идентификаторов на странице не совсем нормально, это может привести к проблемам, которые трудно отладить.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: Только что заметил, это почти тот же подход, который предложил @Lazerblade.

2 голосов
/ 16 апреля 2012

Вот ваш javascript, переписанный с учетом измененного синтаксиса для вызова .each () для popUpLink после перезагрузки.Я также связал 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
1 голос
/ 13 апреля 2012

Вот более простой пример.Я надеюсь, что это демонстрирует то, что вы спрашиваете.Вы можете увидеть рабочую версию на http://jsfiddle.net/4wEPm/2/

Когда вы перезаписываете содержимое таблицы с помощью ajax, ссылки на диалоговое окно теряются.Я думаю, что проще просто заново инициализировать диалоговые окна.

Я использую делегат в таблице (на вашем примере элемент таблицы не перезаписывается, только строки).Таким образом, прослушиватель кликов будет сохраняться после вызова AJAX.Всякий раз, когда диалоговое окно div инициализируется с помощью jquery, оно перемещается в конец страницы.Итак, я добавил ссылку на объект диалога в привязке, просто для быстрого доступа к диалогу вызова («открыть»).Поскольку я занимаюсь инициализацией и открытием диалогового окна в той же функции щелчка, для начала необходимо скрыть диалоговое окно 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 голосов
/ 18 апреля 2012
$('#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.*/


});
0 голосов
/ 16 апреля 2012

У меня была похожая проблема при создании с помощью 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 голосов
/ 15 апреля 2012

У меня есть упрощенный пример здесь

По сути, вам нужна функция делегата, или большинство людей рекомендует жить. Делегат - это, в основном, похожая функция, но вместо привязки к верхнему документу делегат связывается только с указанным вами dom. Следовательно, не возможно использовать stopPropagation в прямом эфире. Кроме того, жить не рекомендуется в 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!');
});​​

Надеюсь, это поможет

0 голосов
/ 13 апреля 2012

Как правило, 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;
});
0 голосов
/ 12 апреля 2012

Вы перезаписываете таблицу, поэтому состояние диалога каждый раз теряется.

0 голосов
/ 02 апреля 2012

Если я правильно понял ваш вопрос, вы должны использовать

.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;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...