Frederik Heyninck
Frederik Heyninck

Reputation: 3543

jQuery plugin: options fail

I created this jquery plugin, but my option is the same for each instance. The backgrounds are both opacity: .9

Demo: http://jsfiddle.net/Yh2ET/2/

How can i fix this?

Upvotes: 1

Views: 99

Answers (2)

ShadowScripter
ShadowScripter

Reputation: 7369

Explanation

Your problem is that you're not instantiating each settings, instead they share the same settings across the board. In order to make each instance have their own settings, you need to:

Define the defaults within the plugin scope, meaning that each instance will have their own settings.
Or
You could learn how to use object constructors. Which does the same thing, but will allow you to keep most of your code as it is, with some minor tweaks.

To learn more about object constructors, click here.


How it's done

First, we change your defaults to a function, instead of an object. What we're doing here, is assigning object properties to the function itself.

$.fn.linkZoomIcon.defaults = function(){
    this.sSpanClass = "linkZoomSpan";
    this.background = {
        css:{
            'opacity': .5
        },
        class: 'linkZoomOverlayBackground'
    };
    this.icon = {
        css:{},
        class: 'linkZoomOverlayIcon'
    };
};

And then, inside the plugin scope, we do like this to create an instance of that object.

$.fn.linkZoomIcon = function(options){
    var oSettings = $.extend(true, new $.fn.linkZoomIcon.defaults, options);
    ......
}

Now we have separate options for each instance.


Changelog

  • Removed the container and container class.
  • Removed default options for container.
  • Removed the .each, it was unnecessary for current usage.
  • The overlay and icon should now be positioned relative to the anchor, the CSS for this was:

    a{
        position: relative;
        display: inline-block;
    } 
    
  • Instead of letting JQuery create the element for me, I directly give it one with document.createElement, it should increase the performance.

  • Instead of the hover event, which is a shorthand for mouseenter and mouseleave, I use them directly.
  • The Zoom icon and background elements are now created at initialization, instead of every time mouseenter is fired. The events only show and hide the elements instead.
  • EDIT Added oSettings.sSpanClass, so that other spans in the link won't be affected.
  • EDIT Corrected the CSS in the JSFiddle solution.

Solution

Here you go: Solution in JSFiddle,
and here's the code in its entirety.

Javascript

(function($) {
    $.fn.linkZoomIcon = function(options)
    {
        var oSettings = $.extend(true, new $.fn.linkZoomIcon.defaults, options);

        var jImage = $("img:first", this);
        var iWidth = jImage.width(),
            iHeight = jImage.height();

        //Background overlay
        var eBg = $(document.createElement("span"));
        eBg.addClass(oSettings.background.class)
           .addClass(oSettings.sSpanClass)
           .width(iWidth).height(iHeight)
           .css(oSettings.background.css)
           .hide();
        $(this).append(eBg);

        //Zoom icon
        var eIco = $(document.createElement("span"));
        eIco.addClass(oSettings.icon.class)
            .addClass(oSettings.sSpanClass)
            .css(oSettings.icon.css)
            .hide();
        $(this).append(eIco);

        $(this).mouseenter(function(){
            $("span."+oSettings.sSpanClass, this).show();
        }).mouseleave(function () {
            $("span."+oSettings.sSpanClass, this).hide();
        });
    };

    $.fn.linkZoomIcon.defaults = function(){
        this.sSpanClass = "linkZoomSpan";
        this.background = {
            css:{
                'opacity': .5,
            },
            class: 'linkZoomOverlayBackground'
        };
        this.icon = {
            css:{},
            class: 'linkZoomOverlayIcon'
        };
    };

})(jQuery);

$(document).ready(function ()
{
    $('a.linkZoomOverlay').linkZoomIcon({background: {css:{'opacity': .2}}});
    $('a.linkZoomOverlayB').linkZoomIcon({background: {css:{'opacity': .9}}});    

});

Happy coding!

Upvotes: 2

andyb
andyb

Reputation: 43823

I thought it would be as simple as moving var opts = $.extend(true, $.fn.linkZoomIcon.defaults, options);to inside the hover function but I am also having problems when the images are side by side if for example the browser window is narrow. Although it seems to work if the images are rendered vertically, albeit with the problem you describe with the shared options.

I have played around a bit with the code and created a demo fiddle that seems to work for me in Chrome. The <a> is given position:absolute and display:inline-block and the overlay background and icon are positioned relatively to the anchor. I also removed the container element as I believe it is unnecessary. It might not be exactly what you are after but I hope it helps nonetheless.

HTML

<a href="#" class="linkZoomOverlay">
    <img src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Liliumbulbiferumflowertop.jpg/220px-Liliumbulbiferumflowertop.jpg" />
</a>
<a href="#" class="linkZoomOverlayB">
    <img src="http://upload.wikimedia.org/wikipedia/commons/thumb/5/52/Liliumbulbiferumflowertop.jpg/220px-Liliumbulbiferumflowertop.jpg" />
</a>

CSS

.linkZoomOverlayBackground {
    background:black;
    position:absolute;
    top:0;
    left:0;
}

.linkZoomOverlayIcon {
    background:url('http://het-stro-buro.f8development.be/frontend/themes/het-stro-buro/core/layout/images/linkZoomIcon.png') no-repeat center center;
    width:100%;
    height:100%;
    position:absolute;
    top:0;
    left:0;
}

JavaScript

(function($) {
    $.fn.linkZoomIcon = function(options) {

        return this.each(function() 
        {
            var $this = $(this);
            $this.hover(function () {
                $this.css({position:'relative', display:'inline-block'});
                var opts = $.extend(true, $.fn.linkZoomIcon.defaults, options);
                var image = $this.find('img:first');
                var elBackground = $('<span>').addClass(opts.background.class);
                var elIcon = $('<span>').addClass(opts.icon.class);

                elBackground.width(image.width()).height(image.height())

                // Styling
                elBackground.css(opts.background.css);
                elIcon.css(opts.icon.css);

                $(this).prepend(elIcon);
                $(this).prepend(elBackground);
            }, function () {
                $this.removeAttr('style');
                $this.find('span').remove();
            }); 
        });
    };

    $.fn.linkZoomIcon.defaults = {
        background:{ 
            css:{
                'opacity': .5
            },
            class: 'linkZoomOverlayBackground'
        },
        icon:{ 
            css:{},
            class: 'linkZoomOverlayIcon'
        }
    };

})(jQuery);

$(document).ready(function () {
    $('a.linkZoomOverlay').linkZoomIcon({background: {css:{'opacity': .1}}});
    $('a.linkZoomOverlayB').linkZoomIcon({background: {css:{'opacity': .7}}});    
});

Upvotes: 0

Related Questions