Nick
Nick

Reputation: 6025

jQuery class event handlers - how to disable for one element in class

I have an event handler attached to a class, as so:

$('#container').on('click', '.myClass', function (e) {...

Within this handler I want to attach a different click handler to the element that has been clicked. When the temporary handler has been clicked, I want to re-enable the original handler.

What I'm trying to do (as shown in this fiddle) is allow a section of text to be clicked, change that to an input text box, and then submit the change to recreate the text.

I've tried the following without success as found at the fiddle:

$('#container').on('click', '.submit', function (e) {
    var $this = $(this),
        new_text = $this.prev().val();
    e.stopPropagation();
    $this.parent().off('click.temp').html(new_text);                    
});

$('#container').on('click', '.test', function (e) {
    var $this = $(this);
    $this.html("<input type='text' value='" + $this.text() + "'/><input class='submit' value='Submit' type='submit'>");
    $this.on('click.temp', function (e) {
        e.stopPropagation();
    });
});

Using an .off() doesn't seem to cancel the original handler on the class because it is attached to the class not the element.

I think I've partly answered my question with e.stopPropagation(), but it's still not quite working and I'm not convinced I'm going about this the best way :)

Note: This post relates to the idea but does not use this.

Upvotes: 1

Views: 1262

Answers (3)

techfoobar
techfoobar

Reputation: 66693

I basically restructured your code so that the events are turned on and off in the same manner.

Updated Demo: http://jsfiddle.net/qZVzY/6/

Updated Code

onClickReadMode - is the event handler when the div is clicked while in read mode

onClickEditMode - is the event handler when the div is clicked while in edit mode

function onClickReadMode(_elem) {
    console.log('onClickReadMode');
    var $this = _elem, text = $this.text();
    $this.html("<input class='text' type='text' value='" + text + "'/><input class='.submit' value='Submit' type='submit'>");
    _elem.off('click.before');
    _elem.on('click.after', function() {
        onClickEditMode($(this));
    });
    _elem.find('.text').on('click.stopevent', function(e) {
        e.stopPropagation();
        return false;
    });
}

function onClickEditMode(_elem) {
    console.log('onClickEditMode');
    var $this = _elem;
    var new_text = $this.find('input').val();
    $this.html(new_text);
    _elem.off('click.after');
    _elem.on('click.before', function() {
        onClickReadMode($(this));
    });
}

$('.test').on('click.before', function (e) {
    onClickReadMode($(this));
});

Upvotes: 1

thecodeparadox
thecodeparadox

Reputation: 87073

You can do it simply like following:

function testClick() {

    var $this = $(this),
        text = $this.text();

    // you have to off the click like this
    $('#container').off('click', '.test');
    
    $this.html(
        "<input class='text' type='text' value='" + text + "'/><input class='submit' value='Submit' type='submit'>"
    );

    $this.find('.submit').on('click', function(e) {
        e.stopPropagation();
        var new_text = $this.find('input.text').val();
        $this.html(new_text);
        $('#container').on('click', '.test', testClick); // again on click
    });
}

$('#container').on('click', '.test', testClick);

Working sample

You can separate the submit event like following:

function testClick() {

    var $this = $(this),
        text = $this.text();

    // you have to off the click like this
    $('#container').off('click', '.test');

    $this.html("<input class='text' type='text' value='" + text + "'/><input class='submit' value='Submit' type='submit'>");
}

$('#container').on('click', '.submit', function(e) {
    e.stopPropagation();
    var new_text = $(this).prev('input.text').val();
    $(this).parent().html(new_text);
    $('#container').on('click', '.test', testClick); // again on click
});

$('#container').on('click', '.test', testClick);

Working sample

Upvotes: 2

nnnnnn
nnnnnn

Reputation: 150070

Rather than adding and removing handlers for the inputs on the fly, I'd stick with delegated event handlers like you're already doing in the click handler that creates the inputs:

$('#container').on('click', '.test', function (e) {
    var $this = $(this);
    $this.removeClass("test")
         .html("<input type='text' value='" + $this.text() + "'/><input id='me' value='Submit' type='button'>");
});

$('#container').on('click', 'input[type="button"]', function (e) {
    var $this = $(this),
        new_text = $this.prev().val();
    $this.parent().addClass("test")
                  .html(new_text);
});

On click of a '.test' div replace its contents with inputs like you were doing, but also remove the "test" class so that further clicks on the div won't do anything (for the moment).

On click of a submit button change the div back to just show the text, and add the class back again so that the previous click handler takes effect again.

Note: I've changed your buttons from type="submit" to type="button" because they're not actually used to submit a form.

Demo: http://jsfiddle.net/4vmQ4/5/

Upvotes: 1

Related Questions