简体   繁体   中英

Why does jQueryUI accordion not work with divs drawn after ajax call?

I've got a simple jQueryUI Accordion working, which I populate afther the page has loaded. The following code works fine:

<html>
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.11.2/jquery-ui.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){
    $(function(){
        $("#ticket-event-list").accordion({
            header: '.event',
            collapsible: true,
            active: false,
            animate: {duration: 150}
        });
    });

    document.tickets = {
        "event1": {"title": "First Event", "content": "The first content"},
        "event2": {"title": "Second Event", "content": "The second content"}
    }

    $.each(document.tickets, function(eventId, eventObj){
        var eventHtml = '<div class="event" id="'+eventId+'">'+eventObj.title+'</div><div class="content">'+eventObj.content+'</div>';
        $("#ticket-event-list").append(eventHtml);
    });
});
</script>

</head>
<body>
    <div id="ticket-event-list"></div>
</body>
</html>

The html that gets inserted if the page is loaded is this:

<div id="ticket-event-list" class="ui-accordion ui-widget ui-helper-reset" role="tablist">
    <div class="event ui-accordion-header ui-state-default ui-corner-all ui-accordion-icons" id="event1" role="tab" aria-controls="ui-id-1" aria-selected="false" aria-expanded="false" tabindex="0"><span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-e"></span>First Event</div>
    <div class="content ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" id="ui-id-1" aria-labelledby="event1" role="tabpanel" aria-hidden="true" style="display: none; height: 18px;">The first content</div>
    <div class="event ui-accordion-header ui-state-default ui-corner-all ui-accordion-icons" id="event2" role="tab" aria-controls="ui-id-2" aria-selected="false" aria-expanded="false" tabindex="-1"><span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-e"></span>Second Event</div>
    <div class="content ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" id="ui-id-2" aria-labelledby="event2" role="tabpanel" aria-hidden="true" style="display: none; height: 18px;">The second content</div>
</div>

The json with which I populate the accordion should however first be taken from an api. So I rewrote the js as can be seen below. Please note that I don't even use the results of the API call. I still use the json which I write in the js.:

$(document).ready(function(){
    $(function(){
        $("#ticket-event-list").accordion({
            header: '.event',
            collapsible: true,
            active: false,
            animate: {duration: 150}
        });
    });

    document.tickets = {
        "event1": {"title": "First Event", "content": "The first content"},
        "event2": {"title": "Second Event", "content": "The second content"}
    }

    function requestTicketsByEvent(){
        var requestUrl = "{{ url_for('ajax_ticketsByEvent') }}";
        var request = $.ajax({
            dataType: "json",
            url: requestUrl,
            type: "GET"
        });
        return request;
    }

    function ticketsByEventCallback(request){
        request.done(function(data){
            // Note I don't even use the data returned by the call
            $.each(document.tickets, function(eventId, eventObj){
                var eventHtml = '<div class="event" id="'+eventId+'">'+eventObj.title+'</div><div class="content">'+eventObj.content+'</div>';
                $("#ticket-event-list").append(eventHtml);
            });
        });
    }

    var request = requestTicketsByEvent();
    ticketsByEventCallback(request);
});

But the resulting html is only as follows:

<div id="ticket-event-list" class="ui-accordion ui-widget ui-helper-reset" role="tablist">
    <div class="event" id="event1">First Event</div><div class="content">The first content</div>
    <div class="event" id="event2">Second Event</div><div class="content">The second content</div>
</div>

I also tried using the .accordion() method after I draw the html to the DOM, but that doesn't help either. Moreover, in the first piece of code (which worked fine) the .accordion() method is also used before the html gets drawn to the DOM.

Does anybody know why an API call prevents the accordion to work? All tips are welcome!

The accordion can't handle dynamically added content. Try wrapping your appends in a destroy and reinitialise calls:

var accordionOptions = {
        header: '.event',
        collapsible: true,
        active: false,
        animate: {duration: 150}
    };
$(function(){
    $("#ticket-event-list").accordion(accordionOptions);
});

// ...

    request.done(function(data){

        $("#ticket-event-list").accordion("destroy");
        // Note I don't even use the data returned by the call
        $.each(document.tickets, function(eventId, eventObj){
            var eventHtml = '<div class="event" id="'+eventId+'">'+eventObj.title+'</div><div class="content">'+eventObj.content+'</div>';
            $("#ticket-event-list").append(eventHtml);
        });
        $("#ticket-event-list").accordion(accordionOptions);
    });

Eg. notice how your example won't work if you delay the appends: http://jsfiddle.net/7b2eegdh/ and then it does works if you reinitialise the widget: http://jsfiddle.net/7b2eegdh/1/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM