2012-04-02 5 views
2

Ich habe eine Tabelle von Studenten und in jeder Zeile sind ihre Namen, eine Auswahlliste, um ihre Anwesenheit für ihre Lektion auszuwählen und dann ein "Nachricht" -Link, wenn geklickt wird, erscheint ein Dialog, um eine Nachricht an den Schüler zu senden.Wie verbinde ich den Dialog neu, nachdem er von AJAX neu geschrieben wurde?

Die Tabelle wird dynamisch von einer Auswahlliste von Kursen gesteuert. Zum Beispiel wählt ein Lehrer einen Kurs aus und dann wird der Tisch mit allen Schülern innerhalb dieses Kurses neu besetzt. Dies geschieht über AJAX. Der Tabellenkörper wird grundsätzlich jedes Mal geschrieben, wenn ein Kurs ausgewählt wird. Mein Problem ist das, wenn ein neuer Kurs ausgewählt wird, wird das div für den Dialog in der Zelle der Nachrichtenverbindung sichtbar. Ich vermute, dass das Problem mit AJAX zu tun hat und nicht in der Lage ist, das Link- und Klick-Event erneut zu binden. Wie überwinde ich das also?

Dies ist meine Tabelle in PHP erstellt (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:[email protected]" id="parentEmail">Message</a>    
      </td>  
     </tr>'; 
    } 

    $table2 .= '</tbody></table>'; 

    return $table2;  
} 

Dies ist die jQuery den Dialog und die Tabelle zu handhaben:

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

Alles funktioniert gut, bis ein neuer Kurs ausgewählt und das Textfeld innerhalb der Zelle sichtbar wird. Ich habe erst letzten Monat mit jQuery angefangen, also ertrage mich!

+0

Der Grund, warum die Dialog-divs nach dem Ajax-Aufruf sichtbar sind, liegt daran, dass Sie sie nicht explizit ausgeblendet haben. Der Dialoginitialisierungscode lief nur einmal, wenn die Seite zum ersten Mal geladen wurde, und das machte die ursprünglichen divs verborgen. dieser Code läuft nach jedem Ajax-Aufruf nicht wieder – gary

Antwort

2

Wie ich verstehe, jede Zeile hat seine eigene Markup für Dialoge und der Code, der diese Dialoge erstellt nur einmal ausgeführt wird, während die Seitenlast:

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

Aber dieser Code sollte beim Start UND jedes Mal aufgerufen werden, wenn Sie Ihre Tabelle neu füllen, da Markup für Dialoge innerhalb von Zeilenzellen liegt. Ich schlage vor, Sie in einer Funktion diesen Code zu setzen:

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

Nennen Sie es, direkt nach dem Laden der Seite, und jedes Mal, wenn Sie wieder zu bevölkern Tabelle:

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

Auch ich bemerkte, wie Sie Ihre Tabellenzeilen innerhalb erstellen foreach Schleife. Jede Zeile hat dieselbe ID, wie diese <td id="studentName">. Wenn viele IDs auf der Seite wiederholt werden, ist das nicht in Ordnung, dies kann zu Problemen führen, die schwer zu debuggen sind.

Ich hoffe es hilft.

EDIT: Gerade bemerkt, es ist fast der gleiche Ansatz, der @ Lazerblade vorgeschlagen.

0

Wenn ich Ihre Frage richtig verstanden habe, sollten Sie

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

oder

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

anstelle von

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

Funktioniert immer noch nicht :( –

5

Sie sollten nicht click() mit Elementen, die dynamisch sind hinzugefügt zu einer Seite becau Diese jQuery-Methode hat keine Möglichkeit, zukünftige Ereignisse an diese Elemente zu binden. Es ist in Ordnung für statische Seiten und Dokumente, aber nicht für Funktionen, die Objekte auf der Seite einfügen, löschen oder ändern.

Stattdessen müssen Sie on() verwenden, da Sie damit zukünftige Ereignisse binden können. Sie müssen es wie folgt umzusetzen:

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

Im Moment aus dem Klang der Dinge, du bist nur live() als potentieller Ersatz verwenden. Verwenden Sie das nicht, da es ab jQuery 1.7 veraltet ist. Das Refactoring von veraltetem Code wie diesem ist ein absolutes Muss in jedem Webprojekt - Sie können es nicht einfach ablehnen, Dinge zu ändern, aufgrund der Reichweite und Tiefe der bestehenden Implementierung. Das sollte Sie nur noch mehr motivieren: Denn wenn Sie die Website mit veralteter Software verlassen, wird etwas schief gehen.

Wenn Sie sich nicht sicher sind, wie Sie von live() zu on() wechseln können, finden Sie unter jQuery's documentation eine knappe und einfache Möglichkeit zum Aktualisieren vorhandener Funktionen.

+0

Hey, yeah. Siehe meine Bearbeitung. Ich habe alles auf .on aktualisiert, aber es funktioniert immer noch nicht:/Ich denke es ist, weil meine Die Tabelle wird jedes Mal neu generiert, wenn ein neuer Kurs ausgewählt wird. Das bedeutet, dass alle Popup-Dialoge vollständig überschrieben werden, aber jQuery sollte das Problem lösen können. –

+0

Ihre Frage enthält nur 'live()', was nicht funktioniert Sie müssen 'on()' verwenden. – hohner

+0

Ich habe ein wenig zu meiner Antwort hinzugefügt, nur um darauf hinzuweisen, dass Sie keine Angst davor haben sollten, existierende Software zu überarbeiten, oder das Code-Refactoring mit Beklemmung angehen. es sollte etwas sein, das _key_ zu jedem und jedem Projekt ist :) – hohner

0

Sie überschreiben die Tabelle, sodass der Status des Dialogfelds jedes Mal verloren geht.

+0

Ja, ich weiß, das ist das Problem und ich muss es neu binden, aber nichts funktioniert, auch wenn ich aktualisiert habe Alle meine jQuery-Handler auf die neueste Version –

1

Hier ist ein einfacheres Beispiel. Ich hoffe es zeigt, was du verlangst.Sie können eine funktionierende Version unter http://jsfiddle.net/4wEPm/2/

anzeigen

Wenn Sie den Inhalt der Tabelle mit AJAX überschreiben, gehen die Verweise auf das Dialogfeld verloren. Ich denke, es ist einfacher, die Dialoge neu zu initialisieren.

Ich verwende einen Delegaten auf der Tabelle (basierend auf Ihrem Beispiel wird das Tabellenelement nicht überschrieben, nur die Zeilen). Auf diese Weise bleibt der Klick-Listener nach dem Ajax-Aufruf bestehen. Immer wenn das Dialogfeld div durch jquery initialisiert wird, wird das div an das Ende der Seite verschoben. Also habe ich einen Verweis auf das Dialogobjekt im Anker hinzugefügt, nur um den Aufrufdialog zu öffnen ('öffnen'). Da ich die Initialisierung und das Öffnen des Dialogfelds in der gleichen Click-Funktion behandle, muss das Dialogfeld div zunächst ausgeblendet werden.

Auch im Ajax-Aufruf ist es am besten, die alten Dialogfelder zu bereinigen, da neue erstellt werden.

<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

Allgemeinen jQuery bindet alle das Element mit Ereignis auf die Ladezeit aber es kann nicht auf die dynamischen Funktionen von .click gebondet werden() Methoden hierfür Verwenden Sie die .live-Methode, die bei der dynamischen Ereignisbindung viel effektiver ist.
Sie können auch versuchen, Live-Funktion zu verwenden. http://docs.jquery.com/Events/live und las mit Beispiel bei http://api.jquery.com/live/

nach der Anwendung es so etwas wie

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

Ich habe ein simplify Beispiel here

Grundsätzlich wird, müssen Sie eine Delegatfunktion oder die meisten Leute empfehlen zu Hause ist. Delegat ist im Grunde, ähnliche Funktion zu leben, aber anstelle der Bindung an das oberste Dokument, delegieren nur binden an bestimmte dom, die Sie angegeben. Daher ist es nicht möglich, stopPropagation in Live zu haben. Auch lebt in jquery veraltet 1.7

wenn Sie faul, um die Geige zu sehen, hier ist der 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!'); 
});​​ 

Ich hoffe, es

2

hilft hier Ihr Javascript, neu geschrieben, um modifizierte Syntax ist für Abrufen der .each() für den PopUpLink nach dem Neuladen. Ich habe auch den PopUpLink an den äußeren Formular-Wrapper gebunden. Stellen Sie außerdem sicher, dass Ihre jQuery auf die neueste Version 1.7.2 aktualisiert wurde, um die.on() Funktion:

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

Ich hatte ein ähnliches Problem, wenn mit AJAX einen Dialog für "Laden abgeschlossen" und so den Aufbau, nur den Dialog zerstören, bevor Sie es erstellen möchten:

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


}); 
Verwandte Themen