0

I'm having an issue with adding an on click event inside a jQuery plugin.

The following is firing on all elements (should only fire on a single element), event is not applied to dynamic elements (it should) - DEMO :

$.fn.myPlugin = function () {
    var element = $(this);
    var settings = { ... }
    var methods = {
        init : function() {
            $(document).on('click', element, function () {
                element.css('background', 'red');
            });
        }
    };
    return methods.init();
};

I need the onclick event inside the plugin settings.event (hover, click, ...).

How can I bind a dynamic on click event inside a jquery plugin with out it firing on every element ?

4
  • I can see event is applied to both dynamic and static li's Commented Nov 13, 2014 at 13:21
  • When you click on an <li> the background for that element should change, not all of them. The dynamic <li>'s background never changes. Commented Nov 13, 2014 at 13:24
  • You mean on click of dynamic <li> right? Commented Nov 13, 2014 at 13:25
  • Yep, dynamic or not the background should change only for the element clicked. Commented Nov 13, 2014 at 13:26

2 Answers 2

1

You should stay more close to the common jQuery plugin pattern.

// method is an (optional) string to call a special method on each element
// options is an (optional) object to add or overwrite properties of the defaults
$.fn.myPlugin = function(method, options) {
    if (typeof method == 'object') options = method, method = null;
    var settings,
        defaults = {
            events: {click: function() {$(this).css({backgroundColor: settings.backgroundColor});}},
            backgroundColor: 'red',
            border: '2px solid black',
            /* all your defaults here */
        },
        methods: {
            giveBorder: function() {$(this).css({border: settings.border});}
            /* all your named methods here, you can use values from settings inside*/
        }
    settings = $.extend(true, {}, defaults, options); // merge defaults and options together
    // now apply a function to each element and return the whole collection
    // if there's a valid method do this
    if (method && methods[method]) return this.each(methods[method]);
    // otherwise do the initializing function
    else return this.each(function(i, elem) { // this 'is' the initializing function
        // put in here all you want to do with each element on init
        $.each(settings.events, function(evt, func) { // apply the event handler to each element
            if (typeof func == 'function')elem.on(evt, func);
        })
    })
};

When you now do on the li-elements $('li').myPlugin() all single elems get a click-handler attached. But $('li') is not live, it holds only the elems beeing in the DOM when it's called (old versions of jQuery had a .live()-function but that was deprecated and removed).

So when you want to initialize a newly created elem with your plugin do it this way:

var alllis = $('li').myPlugin();
var newli = $('<li>Dynamic</li>').myPlugin(); // now it has also a click-handler
$('ul').append(newli); // now it's added to the DOM
alllis.add(newli); // this way you can add it to the jQuery collection of all li

Here' is a working DEMO, and you should play around with following to evaluate the possibilities of this pattern:

var newli2 = $('<li>DynamicGreen</li>').myPlugin({backgroundColor: 'green'});
var newli3 = $('<li>DynamicMouseover</li>').myPlugin(
    {events: {click: 'none', mouseover: function() {$(this).css({backgroundColor: 'yellow'})} }}
);
newli3.myPlugin('giveBorder');
$('ul').append(newli2, newli3);
Sign up to request clarification or add additional context in comments.

Comments

0

I think the reason why the event is firing on all static elements is because when you call $('li').myPlugin();, the object that is getting passed to the plugin is a nodelist, not a single node. Something like this works better for the elements that the plugin is applied to.

init : function() {
            element.each(
                function(i, el) { 
                    $(el).on('click', function () {
                        $(el).toggleClass('bg_red');
                    });
                });
        }

Also, note that when you pass in the element here $(document).on('click', element, function (e) {, it is not scoping the handler to this element the way I think you are trying to do. .on() only uses selectors (i.e. strings) for that. In this case, element is getting passed in in event.data, and is going unused.

As far as why it doesn't work on the dynamically added one, I am not sure, but I suspect it may be a scoping issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.