jQuery Event triggert sehr eigenart



  • Hallo,

    folgendes: ich hab einen Button, der die Notizen eines Benutzers anzeigen soll. Klickt man drauf, werden die Notizen dynamisch über AJAX in eine Tabelle geladen:

    class NotesList
        loadNotes: ->
            self = @
    
            $.ajax 'url',
                type: 'GET',
                dataType: 'json',
                success: (data) ->
                    for key, note of data
                        console.log 'added one note'
                        $('.notes-table').append(new Note(note).render())
    
                error: (xhr, textStatus, errorThrown) ->
                    console.log textStatus, errorThrown
    
        constructor: ->
            # Initial load
            if( ! notesLoaded)
                notesLoaded = true
                @loadNotes()
    

    Die Note-Klasse:

    class Note
            render: () ->
                return '<tr class="note-item" data-id="' + @note.id + '">
                    <td>
                        <a href="#" class="delete-note pull-right"><i class="fa fa-trash-o"></i></a>
                        <a href="#" class="show-note-details">' + @note.title + '</a><br>
                        <span class="text-muted">' + @note.date + '</span>
                    </td>
                </tr>'
    
            constructor: (@note) ->
                $('.delete-note').click ->
                    id = $(this).closest('tr').data('id')
                    console.log id
    

    Nachdem der Popover dynamisch mit Inhalt versehen wird, verwende ich livequery.
    Alles zusammen sieht wie folgt aus:

    notesLoaded = false
    
        class Note
            render: () ->
                return '<tr class="note-item" data-id="' + @note.id + '">
                    <td>
                        <a href="#" class="delete-note pull-right"><i class="fa fa-trash-o"></i></a>
                        <a href="#" class="show-note-details">' + @note.title + '</a><br>
                        <span class="text-muted">' + @note.date + '</span>
                    </td>
                </tr>'
    
            constructor: (@note) ->
                $('.delete-note').click ->
                    id = $(this).closest('tr').data('id')
                    console.log id
    
    $('.popover').livequery ->
            class NotesList
                loadNotes: ->
                    self = @
    
                    $.ajax 'url',
                        type: 'GET',
                        dataType: 'json',
                        success: (data) ->
                            for key, note of data
                                console.log 'added one note'
                                $('.notes-table').append(new Note(note).render())
    
                        error: (xhr, textStatus, errorThrown) ->
                            console.log textStatus, errorThrown
    
                constructor: ->
                    # Initial load
                    if( ! notesLoaded)
                        notesLoaded = true
                        @loadNotes()
    
            new NotesList()
    

    Das resultierende Verhalten aber verstehe ich nicht, weil:

    Klickt man auf das Icon zum Löschen eines Eintrags, sollte die ID des zu löschenden Elements auf der Konsole ausgegeben werden (zum Testen halt). Momentan bekomme ich vom Server 4 Notizen. Und hier das seltsame:

    Klicke ich beim ersten Element auf löschen schreibt er mir wie gewünscht die ID auf die Konsole - aber 3 mal. Klicke ich auf das zweite Element, schreibt er 2 mal die ID aus - und so weiter. Beim letzten Element der Liste gibt es scheinbar keinen Klick-Handler; wenn ich drauf klicke, passiert gar nichts und laut Debugger komme ich auch nie zu dem Click-Event.

    Ich habe die Notes-Klasse ausgelagert - wenn ich das nicht mache, sondern die ganze "Note-Logik" selbst wieder in die NotesList packe, funktioniert alles.

    Eine Lösung laut google war, die Klick-Events zu "unbinden":

    $('.delete-note').unbind('click').click ->
    

    Funktioniert toll - nur hat das letzte Element der Liste immer noch keinen Clickhandler, auch wenn es gleich wie alle anderen erzeugt wird.

    Jemand eine Ahnung?

    Schöne Grüße



  • Wenn Du eine Frage stellst, solltest Du dazu schreiben, welche Programmiersprache Du verwendest. Lediglich der letzte einzeilige Codeausschnitt ist jQuery bzw. JavaScript.


  • Mod

    Wieso verwendest du livequery? Das ist ein jQuery plugin dass ich noch nie gesehen habe.

    Verwende einfach .on() oder übersehe ich irgendwas?



  • Sorry, vergessen zu erwähnen: das ist CoffeeScript. Falls das wer nicht kennt; das übersetzt lediglich nach JS.

    Wieso verwendest du livequery? Das ist ein jQuery plugin dass ich noch nie gesehen habe.

    Ich hab einen Contaier namens "notes". In dem befinden sich widerrum drei Container: notes-overview, notes-loading und notes-details.

    Für die Popover verwende ich Bootstrap. Bootstrap erzeugt beim Klick auf einen Button einen Container, und lädt dynamisch den Content aus dem anderen Div:

    $.each $('*[data-toggle="popover"]'), (element) ->
            $(this).popover({
                placement: 'bottom',
                html: true,
                title: $(this).data('popover-title'),
                content: -> 
                    $('#' + $(this).data('div-container')).html()
            })
    

    Das $('#' + $(this).data('div-container')).html() respektive der popover-title sind nur zwei Attribute, die mein Popover-Button hat, damit ich weiß was dazu gehört:

    <a class="btn navbar-btn btn-default show-notes" href="#" data-toggle="popover" data-div-container="notes" data-popover-title="Notes">Sohow Notes</a>
    

    Warum ich livequery jetzt genau verwende:
    Dadurch, dass der Popover den Content dynamisch lädt, manipuliere ich das DOM dahingehend, dass der Popover-Container den Content vom Notes-Container bekommt. Ohne Livequery kann ich auf die Elemente nicht zugreifen, da sie beim erstmaligen DOM basteln ja gar nicht existieren. Erst wenn ich auf den Button klicke, wird der Content geladen und die Elemente existieren - dafür brauche ich livequery.


  • Mod

    Dafür verwendet man .on()

    Du hängst ein .on an den body und wirfst dort die selektoren rein die du haben willst. jQuery kann sowas logischerweise von haus aus.

    http://api.jquery.com/on/#direct-and-delegated-events



  • Stimmt... naja, ich habs inzwischen ohnehin anders gelöst: über AngularJS. Da spare ich mir einiges 🙂

    Danke aber


Log in to reply