开发者

How to undelegate after event has fired only once

I have an event wired up on a set of select lists (a.k.a. drop-down lists) that - upon firing their bound event - I need to remove the event from.

Each select list has the 'change' event bound like so:

$('#batting-delivery-table tbody').delegate('select[id^="shot-"]', 'change', function () {
    $(this).find('option:first').remove();
});

As soon as that first option in the list has been removed, I want to make sure no further options are deleted. I've tried the following,开发者_运维问答 but without any success:

$('#batting-delivery-table tbody').delegate('select[id^="shot-"]', 'change', function () {
    $(this).find('option:first').remove().undelegate($(this), 'change');
});

I've also tried variations on "live"/"die" and would consider using $.one() if I could visualise how to arrange my code.

Suggestions appreciated.


The jQuery .one() function is meant for this specific purpose.

.one()

Description: Attach a handler to an event for the elements. The handler is executed at most once per element.


Have you tried this?

$("#batting-delivery-table tbody").delegate('select[id^="shot-"]', "change", function () {
    $(this).undelegate("change").find("option:first").remove();

});

These selects are probably not dynamically generated on the client during (longer) page life but are rather loaded in the content so there's no need to use delegate/undelegate functionality. You're probably just trying to remove the Select an item from the list option from them when user selects something and you don't want the to select the dummy options again (Which is rather clever and nice). I'd just go with bind/unbind:

$("select[id^='shot-']").bind("change", function(evt){
    $(this).unbind("change").find("option:first").remove();
});

You can check this JSFiddle that works as expected (and even has few style improvements that you may like as well).

Having dynamic selects

Solution 1

live/delegate functionality will not work as you want it to, because when you try to undelegate an event on a particular element, the delegated event still matches its selector. So it won't work, because event is not related to a single element. Details of why it's working that way can be read in jQuery documention and is out of scope of this answer.

The best way to make it is to give the dummy option special class so you will be able to distinguish it from others and delete it when it's present and do nothing when it's not. But change event will run regardless.

$("select[id^='shot-']").live("change", function(evt){
    $("option.dummy-option", this).remove();
});

JSFiddle that uses live handler registration.

Solution 2

You can still use one handler registration, but your functionality that ads new selects to the form will have to register the event along with the new select element that gets appended (hence no global event registration). An example of this functionality:

$("a.action-add-new").click(function(evt) {
    evt.prevetnDefault();
    $("<select><option>...</option></select>").appendTo("someContainer").one("change", function(){
        $("option:first", this).remove();
    });
});

Solution 3

Oh I came up with solution 3, that uses live (or could as well use delegate) event registration. You should set event handler to a particular selector which you change after change has run.

When you create your select, give it a particular class like unselected. Then register change event against that selector. In the change event just remove the class and it won't run again for this select element.

<select id="shot-first" class="unselected">
...
</select>

$("select[id^='shot-'].unselected").live("change", function(evt) {
    $(this).removeClass("unselected").find("option:first").remove();
});

Check the working proof of concept in this JSFiddle. Works. I don't know why I didn't come up with this one before. :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜