Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my JQuery selector returning a n.fn.init[0], and what is it?

I have a set of dynamically generated checkboxes, where each of them has a data-id attribute corresponding to a database integer id. When i populate my html-form with an object to edit, there is a list of integers representing which checkboxes should be checked. The checkboxes are wrapped in a div with class checkbox-wrapper.

So html looks like this:

<div class="checkbox-wrapper">
    <input type="checkbox" id="checkbox1" data-id="1">
    <label for="checkbox1">Checkbox 1</label>
</div>
<div class="checkbox-wrapper">
    <input type="checkbox" id="checkbox2" data-id="2">
    <label for="checkbox2">Checkbox 2</label>
</div>
<div class="checkbox-wrapper">
    <input type="checkbox" id="checkbox3" data-id="99">
    <label for="checkbox3">Checkbox 99</label>
</div>

Note that the id runs on auto increment index numbers, while data-id might have a different id value. I want to select them by data-id.

Now, using JQuery, I know I can select the relevant checkboxes like this:

$(".checkbox-wrapper>input[data-id='99']");
$(".checkbox-wrapper>input[data-id='1']");

This works in my console, in chrome, and it returns the relevant DOM-element. Likewise, this below, sets the checkboxes to checked:

$(".checkbox-wrapper>input[data-id='99']").prop("checked", "checked");
$(".checkbox-wrapper>input[data-id='1']").prop("checked", "checked");

However, if I iterate through a list of integers in my javascript code (not directly in the console), and log the returned elements, based on the id values, I get some weird results:

var ids = [1,2]
$.each(ids, function(index, myID){
    console.log($(".checkbox-wrapper>input[data-id='"+myID+"']"));
    $(".checkbox-wrapper>input[data-id='"+myID+"']").prop("checked", "checked");    
}); 

First of all, no checkboxes are checked. Second, my console prints strange results:

n.fn.init[0]
    context: document
    length: 0
    prevObject: n.fn.init[1]
    selector: ".checkbox-wrapper>input[data-id='1']"
    __proto__: n[0]

n.fn.init[0]
    context: document
    length: 0
    prevObject: n.fn.init[1]
    selector: ".checkbox-wrapper>input[data-id='2']"
    __proto__: n[0]

The printed selector Strings seems perfect. The exact same selectors returns the DOM-elements, when written directly into the chrome console. Then they return objects like this:

[<input type=​"checkbox" id=​"checkbox1" data-id=​"1">​]

What is the n.fn.init[0], and why it is returned? Why are my two seemingly identical JQuery functions returning different things?

like image 378
jumps4fun Avatar asked Dec 28 '15 13:12

jumps4fun


People also ask

What does jQuery FN init mean?

fn. init() {...} , is given the jQuery prototype so that its object 'type' is of jQuery , and that all instances of it are actually instances of jQuery . Follow this answer to receive notifications.

What does jQuery selector return?

The jQuery Object: The Wrapped Set: Selectors return a jQuery object known as the "wrapped set," which is an array-like structure that contains all the selected DOM elements. You can iterate over the wrapped set like an array or access individual elements via the indexer ($(sel)[0] for example).

What is prevObject jQuery?

jQuery returns prevObject if the DOM does not have the element for which jQuery is being run. You might see the element in your source at the run-time however, it is not not bound to the DOM and therefore, it shows prevObject.

What is a jQuery element?

version added: 1.0jQuery( "element" ) Refers to the tagName of DOM nodes.


3 Answers

Another approach(Inside of $function to asure that the each is executed on document ready):

var ids = [1,2];
$(function(){
  $('.checkbox-wrapper>input[type="checkbox"]').each(function(i,item){
    if(ids.indexOf($(item).data('id')) > -1){
       $(item).prop("checked", "checked");
    }
  });
});

Working fiddle: https://jsfiddle.net/robertrozas/w5uda72v/

What is the n.fn.init[0], and why it is returned? Why are my two seemingly identical JQuery functions returning different things?

Answer: It seems that your elements are not in the DOM yet, when you are trying to find them. As @Rory McCrossan pointed out, the length:0 means that it doesn't find any element based on your search criteria.

About n.fn.init[0], lets look at the core of the Jquery Library:

var jQuery = function( selector, context ) {
   return new jQuery.fn.init( selector, context );
};

Looks familiar, right?, now in a minified version of jquery, this should looks like:

var n = function( selector, context ) {
   return new n.fn.init( selector, context );
};

So when you use a selector you are creating an instance of the jquery function; when found an element based on the selector criteria it returns the matched elements; when the criteria does not match anything it returns the prototype object of the function.

like image 53
Hackerman Avatar answered Oct 17 '22 09:10

Hackerman


Here is how to do a quick check to see if n.fn.init[0] is caused by your DOM-elements not loading in time. Delay your selector function by wrapping it in setTimeout function like this:

function timeout(){ 

    ...your selector function that returns n.fn.init[0] goes here...

}

setTimeout(timeout, 5000)

This will cause your selector function to execute with a 5 second delay, which should be enough for pretty much anything to load.

This is just a coarse hack to check if DOM is ready for your selector function or not. This is not a (permanent) solution.

The preferred ways to check if the DOM is loaded before executing your function are as follows:

1) Wrap your selector function in

$(document).ready(function(){  ... your selector function...  };

2) If that doesn't work, use DOMContentLoaded

3) Try window.onload, which waits for all the images to load first, so its least preferred

window.onload = function () {  ... your selector function...  }

4) If you are waiting for a library to load that loads in several steps or has some sort of delay of its own, then you might need some complicated custom solution. This is what happened to me with "MathJax" library. This question discusses how to check when MathJax library loaded its DOM elements, if it is of any help.

5) Finally, you can stick with hard-coded setTimeout function, making it maybe 1-3 seconds. This is actually the very least preferred method in my opinion.

This list of fixes is probably far from perfect so everyone is welcome to edit it.

like image 7
Arthur Tarasov Avatar answered Oct 17 '22 08:10

Arthur Tarasov


Your result object is a jQuery element, not a javascript array. The array you wish must be under .get()

As the return value is a jQuery object, which contains an array, it's very common to call .get() on the result to work with a basic array. http://api.jquery.com/map/

like image 6
celerno Avatar answered Oct 17 '22 08:10

celerno