John B.
John B.

Reputation: 2359

jQuery click event fires twice

I have a problem with a content overlay script I am developing. It seems that my closing event fires twice, but returns 'undefined' the first time (or second time, depending on which opening link you click).

You can find a stripped-down working example on JSFiddle: http://jsfiddle.net/UhSLy/2/

If you click on 1. Click and then on 2. Click it alerts undefined first, then Dummy.

When I delete one opening-link, everything works fine. But I have to have multiple links since they open different overlays.

What causes the problem and how can I avoid it?

Edit: Code from JSFiddle follows:

;(function ($, window, document, undefined) {

"use strict";

var pluginName = 'contentOverlay',
    defaults = {
        property:   'value'
    };

function Plugin(element, options) {
    this.element = element;
    this.$element = $(element);

    this.options = $.extend({}, defaults, options);

    this.init();
}

Plugin.prototype = {

    /**
     * Init
     */
    init: function () {
        var self = this;

        // Bind opening method
        this.$element.click(function() {
            self.open();
        });

        // Bind closing method
        $('#close').click(function() {
            self.close();
        });
    },

    /**
     * Open
     */
    open: function () {
        this.overlay = 'Dummy';
    },

    /**
     * Close
     */
    close: function () {
        alert(this.overlay); // <==== PROBLEM: fires twice. returns 'undefined' once
    },

};

$.fn[pluginName] = function (options) {
    return this.each(function () {
        if (!$.data(this, 'plugin_' + pluginName)) {
            $.data(this, 'plugin_' + pluginName,
                new Plugin(this, options));
        }
    });
}

$(function () {
    $('.open').contentOverlay();
});

})(jQuery, window, document);

Upvotes: 4

Views: 4554

Answers (3)

The Alpha
The Alpha

Reputation: 146191

I've came up with this (only the changes here)

open: function () {
        this.overlay = 'Dummy';
        this.opened=true;
},

$('#close').click(function() {
    if(self.opened) 
    {
        self.opened=false;
        self.close();
    }    
});

I think code explains everything. The close event will never fire if an instance doesn't exist.

DEMO.

Upvotes: 0

Tats_innit
Tats_innit

Reputation: 34107

If I may suggest look in here: http://jsfiddle.net/PgbfN/25/

I reckon your this if condition which is to check if plugin is initialised is undefined hence runs through twice.

To resolve I added isApplied flag, once applied set the flag to true. Rest hope demo will help :)

Hope it helps

$.fn[pluginName] = function(options) {
        return this.each(function() {
            alert('me ==> ' + (!$.data(this, 'plugin_' + pluginName)) + " ==== " + $.data(this, 'plugin_' + pluginName));
            if (!isApplied) {
                $.data(this, 'plugin_' + pluginName, new Plugin(this, options));

            }
        });
    }

full code

var isApplied = false;

(function($, window, document, undefined) {

    "use strict";

    var pluginName = 'contentOverlay',
        defaults = {
            property: 'value'
        };

    function Plugin(element, options) {
        this.element = element;
        this.$element = $(element);

        this.options = $.extend({}, defaults, options);
        isApplied = true;
        this.init();
    }

    Plugin.prototype = {

        /**
         * Init
         */
        init: function() {
            var self = this;

            // Bind opening method
            this.$element.click(function() {
                self.open();
            });

            // Bind closing method
            $(document).on('click', '#close', function() {
                alert('Close is clicked');
                //self.close(); //<<== Is called
            });
        },

        /**
         * Open
         */
        open: function() {
            this.overlay = 'Dummy';
        },

        /**
         * Close
         */
        close: function() {
            alert(this.overlay); // <==== PROBLEM: fires twice. returns 'undefined' once
        },

    };

   $.fn[pluginName] = function(options) {
        return this.each(function() {
            alert('me ==> ' + (!$.data(this, 'plugin_' + pluginName)) + " ==== " + $.data(this, 'plugin_' + pluginName));
            if (!isApplied) {
                $.data(this, 'plugin_' + pluginName, new Plugin(this, options));

            }
        });
    }

    $(function() {
        $('.open').contentOverlay();
    });

})(jQuery, window, document);

Upvotes: 0

ahren
ahren

Reputation: 16961

$('#close').click(function() {
    self.close();
});

You're binding both objects close() methods to the close handler. Basically, when you click on the close button, it's running two functions, one for each of the overlay objects. Because one overlay object doesn't exist, it's returning undefined.

You could get around this problem by:

close: function () {
    if(this.overlay != undefined){ // Skips over the undefined overlays
        alert(this.overlay);
    }
}

DEMO: http://jsfiddle.net/UhSLy/9/

Upvotes: 3

Related Questions