rstaib / jquery-bootgrid

Nice, sleek and intuitive. A grid control especially designed for bootstrap.
http://www.jquery-bootgrid.com
MIT License
974 stars 361 forks source link

Problem with event delegation on dymamic grid elements #138

Open jhargis opened 9 years ago

jhargis commented 9 years ago

I'm struggling to understand why I can't get event delegation working with a dynamic bootgrid element.


/* --- AJAX based grid with this formatter ---- */
formatters: {
    "search_on_id": function(column, row) {
        return "<span class=\"btn btn-default btn-xs\" role=\"button\"><span class=\"glyphicon glyphicon-plus report-search-add-btn\" data-p-id=\"" + row.p_id + "\" data-p-no=\"" + row.p_no + "\"></span></span>";
    },
<!--  Grid HTML -->
<table id="grid-data" class="table table-condensed table-hover table-striped">
    <thead>
        <tr>
            <th data-column-id="p_id">p_id</th>
            <th data-column-id="p_no">p_no</th>
            <th data-column-id="id" data-formatter="search_on_id" data-header-align="right" data-sortable="false" data-align="center" data-header-css-class="commandColumn bootgrid-xs"></th>
        </tr>
    </thead>
</table>
/* --- js event ---- */
$(function() {
    $("#grid-data").on('click', 'span.report-search-add-btn', function(){ 
        console.log( 'p_id: ' + $(this).data('p-id') ); 
    });
});

if i set a breakpoint just prior to the jquery.on, the selector is found. The child target does not exist yet, and at this point, the delegation fails to find the child target(span.report-search-add-btn) after the child is dynamically populated, post grid load.

It does not work after grid initialize/initialized.

$("#grid-data").on("initialized.rs.jquery.bootgrid", function (e) {
    alert("initialized");
    $("#grid-data").on('click', 'span.report-search-add-btn', function(){ console.log( 'p_id: ' + $(this).data('p-id') ); });
}).bootgrid(bg_conf);

It DOES work if I place the event binding inside loaded.rs.jquery.bootgrid

$(function() {
    $("#grid-data").bootgrid().on("loaded.rs.jquery.bootgrid", function (e){
        $("#grid-data").on('click', 'span.report-search-add-btn', function(){ console.log( 'p_id: ' + $(this).data('p-id') ); });
    });
});

But this creates new bindings every time data loads into the grid, so potentially tons of unnecessary binding.

Any idea what is going on here?

qzminski commented 9 years ago

I think the "formatters" paramter should be changed or adjusted in general so that you can affect the cell element directy and e.g. inject DOM elements with already bound events. For example:

formatters: {
    'foobar': function(column, row, cell) {
        var link = $('<a>').on('click', function() { alert('foobar') });
        link.appendTo(cell);
    }
}

I see no reason why you would like to return only the plain HTML and bind the events in a separate method.

sergiofg commented 9 years ago

Delegation doesn't work because bootgrid stop click propagation with event.stopPropagation() (so the click event never reach beyond tbody).

From the docs: "Use the loaded.rs.jquery.bootgrid event to bind custom events to your controls rendered by a formatter."

So, your last example (the one that works) it's the intended way.

You can use jquery.off() to remove old bindings.