eek meek
eek meek

Reputation: 301

Getting initial selector inside jquery plugin

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;
}

Upvotes: 21

Views: 13303

Answers (4)

BGerrissen
BGerrissen

Reputation: 21680

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();

Upvotes: 18

Studocwho
Studocwho

Reputation: 2478

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.

Upvotes: 1

curveball
curveball

Reputation: 4505

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.

Upvotes: 4

Craig
Craig

Reputation: 7671

This page talks about getting the selector:

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

Upvotes: 5

Related Questions