21

I got some help earlier regarding selectors, but I'm stuck with the following.

Lets say you have a plugin like this

$('#box').customplugin();

how can I get the #box as a string in the plugin? Not sure if that's the correct way of doing it, and any other solution would be great as well.

Considering #box is a select dropdown,

The problem I'm having is if I do the regular javascript

$('#box').val(x);

The correct option value gets selected,

but if i try the same inside a plugin

.....
this.each(function() {
var $this = $(this);


$this.val(x);

the last code doesn't really do anything.

I notice I'm having trouble targeting #box inside the plugin because it's a object and not a string...

Any help would be appreciated.

Thanks!

Edit:: Putting in the code I'm working in for better understanding

(function($){
$.fn.customSelect = function(options) {
    var defaults = {
        myClass : 'mySelect'
    };
    var settings = $.extend({}, defaults, options);


    this.each(function() {
        // Var          
        var $this = $(this);
        var thisOpts = $('option',$this);
        var thisSelected = $this[0].selectedIndex;
        var options_clone = '';

        $this.hide();

        options_clone += '<li rel=""><span>'+thisOpts[thisSelected].text+'</span><ul>'
        for (var index in thisOpts) {
            //Check to see if option has any text, and that the value is not undefined
            if(thisOpts[index].text && thisOpts[index].value != undefined) {
                options_clone += '<li rel="' + thisOpts[index].value + '"><span>' + thisOpts[index].text + '</span></li>'
            }
        }
        options_clone += '</ul></li>';

        var mySelect = $('<ul class="' + settings.myClass + '">').html(options_clone); //Insert Clone Options into Container UL
        $this.after(mySelect); //Insert Clone after Original

        var selectWidth = $this.next('ul').find('ul').outerWidth(); //Get width of dropdown before hiding
        $this.next('ul').find('ul').hide(); //Hide dropdown portion

        $this.next('ul').css('width',selectWidth);

        //on click, show dropdown
        $this.next('ul').find('span').first().click(function(){
            $this.next('ul').find('ul').toggle();
        });

        //on click, change top value, select hidden form, close dropdown
        $this.next('ul').find('ul span').click(function(){
            $(this).closest('ul').children().removeClass('selected');
            $(this).parent().addClass("selected");
            selection = $(this).parent().attr('rel');
            selectedText = $(this).text();
            $(this).closest('ul').prev().html(selectedText);
            $this.val(selection); //This is what i can't get to work
            $(this).closest('ul').hide();
        });

    });
    // returns the jQuery object to allow for chainability.
    return this;
}
eek meek
  • 301
  • 2
  • 4
  • 11

4 Answers4

18

Just a heads-up: .selector() is deprecated in jQuery 1.7 and removed in jQuery 1.9: api.jquery.com/selector. – Simon Steinberger

Use the .selector property on a jQuery collection.

Note: This API has been removed in jQuery 3.0. The property was never a reliable indicator of the selector that could be used to obtain the set of elements currently contained in the jQuery set where it was a property, since subsequent traversal methods may have changed the set. Plugins that need to use a selector string within their plugin can require it as a parameter of the method. For example, a "foo" plugin could be written as $.fn.foo = function( selector, options ) { /* plugin code goes here */ };, and the person using the plugin would write $( "div.bar" ).foo( "div.bar", {dog: "bark"} ); with the "div.bar" selector repeated as the first argument of .foo().

var x = $( "#box" );
alert( x.selector ); // #box

In your plugin:

$.fn.somePlugin = function() {

    alert( this.selector ); // alerts current selector (#box )

    var $this = $( this );

    // will be undefined since it's a new jQuery collection
    // that has not been queried from the DOM.
    // In other words, the new jQuery object does not copy .selector
    alert( $this.selector );
}

However this following probably solves your real question?

$.fn.customPlugin = function() {
    // .val() already performs an .each internally, most jQuery methods do.
    // replace x with real value.
    this.val(x);
}

$("#box").customPlugin();
BGerrissen
  • 21,250
  • 3
  • 39
  • 40
  • hm... does it work the same in a plugin? its giving me an empty value when I do an alert.. – eek meek Mar 29 '11 at 19:02
  • thanks for the update, i think my problem is because I have the function inside a this.each(function). How would I target it there? – eek meek Mar 29 '11 at 19:05
  • Get it before the `.each` from the current jQuery instance. There's no need to do it in the each since all found elements came from the same query. – BGerrissen Mar 29 '11 at 19:08
  • I see... one last question, if the plugin can have multiple selectors, the initial selector set before the each loop gives all of them. Is it possible to have it only show the correct selector for each "each" statement? – eek meek Mar 29 '11 at 19:11
  • Hmm, after re-reading your question, you don't need the .selector at all, gimme a sec. – BGerrissen Mar 29 '11 at 19:11
  • Well updated again, though I need more code/explanation to get what you really want to achieve. – BGerrissen Mar 29 '11 at 19:19
  • updated my post, i think the problem is that the val() goes inside a click function, and "this" ends up selecting another selector... – eek meek Mar 29 '11 at 19:21
  • thank you very much for this answer and explanation @BGerrissen . this solved a long hours problem i was facing... yahoooo – Codex73 Feb 08 '13 at 17:16
  • 1
    Just a heads-up: .selector() is deprecated in jQuery 1.7 and removed in jQuery 1.9: http://api.jquery.com/selector/ – Simon Steinberger Aug 31 '14 at 09:06
  • this only returns undefined – Fernando Torres Dec 29 '20 at 08:11
5

This page talks about getting the selector:

http://api.jquery.com/selector/

Craig
  • 7,471
  • 4
  • 29
  • 46
  • So basically the OP can use it like `this.selector`. – pimvdb Mar 29 '11 at 18:56
  • Thanks, would you know any reason why the value of selector is undefined for me? – eek meek Mar 29 '11 at 19:00
  • @HyungSuh Is it because you used `$.plugin` instead of `$.fn.plugin`? It is a very easy mistake and then `this` wouldn't be defined. – Evan Moran Mar 31 '13 at 22:28
  • 1
    Just a note that it's been deprecated. I'm still looking for a good replacement. This function is close, but not 100%: http://stackoverflow.com/questions/2420970/how-can-i-get-selector-from-jquery-object – Phil LaNasa Jan 01 '14 at 12:11
4

That's how I get selector strings inside my plugins in 2017:

(function($, window, document, undefined) { 
    $.fn._init = $.fn.init
    $.fn.init = function( selector, context, root ) {
        return (typeof selector === 'string') ? new $.fn._init(selector, context, root).data('selector', selector) : new $.fn._init( selector, context, root );
    };
    $.fn.getSelector = function() {
        return $(this).data('selector');
    };
    $.fn.coolPlugin = function() {
        var selector = $(this).getSelector(); 
        if(selector) console.log(selector); // outputs p #boldText
    }
})(jQuery, window, document);

// calling plugin
$(document).ready(function() {
    $("p #boldText").coolPlugin();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>some <b id="boldText">bold text</b></p>

The idea is to conditionally wrap jQuery's init() function based on whether a selector string is provided or not. If it is provided, use jQuery's data() method to associate the selector string with the original init() which is called in the end. Small getSelector() plugin just takes previously stored value. It can be called later inside your plugin. It should work well with all jQuery versions.

curveball
  • 4,320
  • 15
  • 39
  • 49
1

Because of the deprecation and removal of jQuery's .selector, I have experimented with javascript's DOM Nodes and came up with a 2017 and beyond solution until a better way comes along...

//** Get selector **//

    // Set empty variables to work with
    var attributes = {}, // Empty object 
        $selector = ""; // Empty selector

    // If exists... 
    if(this.length) {
        // Get each node attribute of the selector (class or id) 
        $.each(this[0].attributes, function(index, attr) {
            // Set the attributes in the empty object
            // In the form of name:value
            attributes[attr.name] = attr.value;
        }); 
    }
    // If both class and id exists in object        
    if (attributes.class && attributes.id){
        // Set the selector to the id value to avoid issues with multiple classes
        $selector = "#" + attributes.id
    }
    // If class exists in object
    else if (attributes.class){
        // Set the selector to the class value
        $selector = "." + attributes.class
    }
    // If id exists in object
    else if (attributes.id){
        // Set the selector to the id value
        $selector = "#" + attributes.id
    }
    // Output
    // console.log($selector);
    // e.g: .example   #example

So now we can use this for any purpose. You can use it as a jQuery selector... eg. $($selector)

EDIT: My original answer would only get the attribute that appears first on the element. So if we wanted to get the id that was placed after the class on the element, it wouldn't work.

My new solution uses an object to store the attribute information, therefore we can check if both or just one exists and set the required selector accordingly. With thanks to ManRo's solution for the inspiration.

Studocwho
  • 2,404
  • 3
  • 23
  • 29