user1032531
user1032531

Reputation: 26281

Accessing original targeted element within jQuery plugin

I put together a jQuery plugin to query the server and display a tooltip popup. Yea, I know there are probably better ones available, but half of my motivation is to learn how to do so myself. A live demo is located at http://jsfiddle.net/sVZah/, and the script is shown below. Upon hovering over an element, I wish to allow the developer to add additional data to be sent to the server. My thought was to add the getData() method to my plugin (note that the jsfiddle example doesn't do this because it needs to pass the demoJSON object to simulate ajax). The problem is that this within the method refers to the tooltip and not the initial element (i.e. p.myElement) so I cannot access the data associated with the original element (i.e. data-id). How should I access the original targeted element within the getData method? If my entire general approach is not ideally, please feel let me know and recommend a better approach as this is very much of a learning experience.

As a side non-official question, how do I prevent hovering to the right of the element from initiating the popup? I recognize that this is probably more of a HTML question, and while I do not expect an answer, would be very happy to get one.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> 
        <title>screenshot</title>  
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script> 
        <script src="jquery.ajaxTip.js" type="text/javascript"></script> 
        <style type="text/css">

            .myElement{margin:100px;}
            .ajaxToolActive{color:blue;}

            .myAjaxTip {
                position:absolute;
                border:1px solid #CECECE;
                background:white;
                padding:10px;
                display:none;
                color:black;
                font-size:11px;-moz-border-radius:4px;
                box-shadow: 3px 1px 6px #505050;
                -khtml-border-radius:4px;
                -webkit-border-radius:4px;
                border-radius:4px;
            }
        </style> 

        <script type="text/javascript">
            $(function(){
                $('.myElement').ajaxTip({
                    display: function(d){return '<p>'+d.name+'</p><p>'+d.address+'</p><p>'+d.city+', '+d.state+'</p>';},
                    getData:function(){console.log(this);return {id:123}},
                    'class':'myAjaxTip'
                });
            });
        </script>
    </head>

    <body>
        <p class="myElement" data-id="1" title="ajaxTip Popup">John Doe</p>
        <p class="myElement" data-id="2" title="ajaxTip Popup">Jane Doe</p>
        <p class="myElement" data-id="3" title="ajaxTip Popup">Baby Doe</p>
    </body> 
</html> 


/*
* jQuery ajaxTip
* Copyright 2013 Michael Reed
* Dual licensed under the MIT and GPL licenses.
* 
* Notes
*/
(function( $ ){

    var methods = {
        init : function( options ) {
            // Create some defaults, extending them with any options that were provided
            var settings = $.extend({
                'url'      : 'getAjaxTip.php',        //To include extra data sent to the server, included it in the url
                'class'    : 'standardAjaxTip',
                'mouseMove': true,
                'delay'    : 250,   //miliseconds to delay before requesting data from server
                'xOffset'  : 20,
                'yOffset'  : 10,
                'dataType' : 'json',
                'getData'  : function(){return {}}, //Use to set additional data to the server
                'display'  : function(data){   //User function must include function(data) {... return string}
                    var string='';
                    for (var key in data) {string+='<p>'+data[key]+'</p>';}
                    return string;
                }
                }, options  || {});     //Just in case user doesn't provide options

            return this.each(function(){
                var showing,title,timeoutID,ajax,$t=$(this),ajaxTip;
                $t.hover(function(e) {
                    if(!showing){
                        title = this.title;this.title = "";//Prevent title from being displayed,and save for later to put back    
                        timeoutID=window.setTimeout(function() {
                            ajax=$.get( settings.url,settings.getData(),function(data){
                                ajaxTip=$('<div />').addClass(settings.class).html(((title != '')?'<h3>'+title+'</h3>':'')+settings.display(data))
                                .css("top",(e.pageY - settings.yOffset) + "px")
                                .css("left",(e.pageX + settings.xOffset) + "px")
                                .appendTo('body').fadeIn("fast");                    
                                showing = true;
                                $t.addClass('ajaxToolActive');
                                }, settings.dataType);
                            },settings.delay); //Delay before requesting data from server
                    }
                    },
                    function()
                    {
                        //When not hover
                        if (typeof ajax == 'object') {ajax.abort();}
                        window.clearTimeout(timeoutID);
                        this.title = title;    
                        $t.removeClass('ajaxToolActive');
                        if(showing){ajaxTip.remove();}
                        showing = false;
                });

                $t.mousemove(function(e) {
                    if(settings.mouseMove && showing) {ajaxTip.css("top",(e.pageY - settings.yOffset) + "px").css("left",(e.pageX + settings.xOffset) + "px");}
                });
            });
        },

        //Add additional methods as needed
        //destroy : function() {}

    };

    $.fn.ajaxTip = function(method) {
        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.ajaxTip' );
        }    
    };


})( jQuery );

Upvotes: 1

Views: 170

Answers (1)

jcubic
jcubic

Reputation: 66490

You can change the context of getData using apply or call methods

ajax=$.get( settings.url, settings.getData.call($t),function(data){

in this case in your getData function this will be $t jquery object, so you can call

$('.myElement').ajaxTip({

    display: function(d){
        return '<p>'+d.name+'</p><p>'+d.address+'</p><p>'+d.city+', '+d.state+'</p>';
    },
    getData:function(){
       alert(this.data('id'));
    },
    'class':'myAjaxTip'
});

Upvotes: 1

Related Questions