59

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?

jumps4fun
  • 3,994
  • 10
  • 50
  • 96
  • 3
    The 'odd' result you're seeing in the console is is the jQuery object itself. You can also see that the `length` property is `0`, which means the element is not found from the selector you provided, hence the use of `prop()` has no effect. As you can see in [this example](https://jsfiddle.net/d6dudukk/1/) your code as you've described it works. This means that you need to check the console for errors elsewhere in your code. The issue could be that you haven't included the jQuery library properly, or that you're running your code before the DOM is ready. – Rory McCrossan Dec 28 '15 at 14:03
  • Most likely the last one. My checkboxes are created from dynamic data. The checkbox-html is generated, and added to the document through a method, which is called everytime a datepicker is changed, which it is when loading the object to populate the form. In other words, just before checking which checkboxes to check. It is done by triggering a `changeDate`-event, which I do not suppose halts the execution of my population method, until it is done creating the checkbox DOM-elements. @RoryMcCrossan, your comment is actually a full answer to my question. You should write it up as an answer. – jumps4fun Dec 28 '15 at 14:31
  • Given, it doesn't solve my problem, but it answers the question perfectly, and gives me a chance to move on, and investigate the next step. Any further questions I have will be more suitable for a new question though. – jumps4fun Dec 28 '15 at 14:32
  • `.prop("checked", "checked")` should be `.prop("checked", true)` – Blazemonger Dec 28 '15 at 14:35
  • @Blazemonger, you're right, but it doesn't really matter in this question, does it? ref: http://stackoverflow.com/questions/10650233/checked-checked-vs-checked-true – jumps4fun Dec 28 '15 at 14:40
  • 1
    (That's why I submitted it as a comment and not an answer.) Are you running your code after the page is fully loaded? If not, the DOM won't be loaded and no selectors will match anything. – Blazemonger Dec 28 '15 at 14:40
  • My previous comment will answer your question perfectly – jumps4fun Dec 28 '15 at 14:41

6 Answers6

36

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 look 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.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
Hackerman
  • 12,139
  • 2
  • 34
  • 45
  • 2
    While it might be great code, this doesn't answer any part of my question. Also It wouldn't solve anything, as it seems my checkboxes are not ready at the time of trying to populate them. Meaning, this method would iterate over exactly zero DOM-elements. – jumps4fun Dec 28 '15 at 14:35
  • Are you creating those checkboxes with ajax or something??...if you click on the fiddle, its works and the checkboxes are checked....Maybe if you post that part of your code we can help you in a better way. – Hackerman Dec 28 '15 at 14:46
  • 3
    @KjetilNordin, i'm not doing this for the rep, i'm doing it to helping others, so do not worry. Maybe this answer serves others, so i'm not going to delete it, points doesn't mathers. And as you says: it looks like a great code xD. – Hackerman Dec 28 '15 at 14:58
  • Hehe, thanks. Your kind is the reason I love this network. I have to say though, I didn't actually call it great code. I just pointed out that even if it was great code, it wasn't answering the question. In my mind it actually seems a bit slower than my current code, as you both iterate through every single checkbox, and for each of them checks if the id exists in an array. I can't say for sure, but my gut feeling is that my original way is faster, and just as easy to read. Anyway, my specific way of constructing the checkboxes is still better left for another question. It is a lot of code. – jumps4fun Dec 28 '15 at 15:05
  • 2
    I eat my words! And what a great resource you just shared with me there, with http://jsperf.com/. I didn't know about that one. I will probably use it a lot in the future. Come to think of it, It makes sense, as you only perform a single jquery select, and although there is more traversing, it seems to be way less resource demanding. You my friend, have taought me a lesson :). Thank you! – jumps4fun Dec 28 '15 at 15:24
  • ...If you would add a short line on what the n.fn.init[0]-object is, I will mark your answer as accepted. That way, it will hopefully be useful to others in the future! – jumps4fun Dec 28 '15 at 15:26
  • 3
    Answer edited...start as a small one and grow up a little :) – Hackerman Dec 28 '15 at 15:51
  • Now your answer is amazing! :) – jumps4fun Dec 28 '15 at 16:07
7

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.

Community
  • 1
  • 1
Arthur Tarasov
  • 3,517
  • 9
  • 45
  • 57
7

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/

celerno
  • 1,367
  • 11
  • 30
5

I faced this issue because my selector was depend on id meanwhile I did not set id for my element

my selector was

$("#EmployeeName")

but my HTML element

<input type="text" name="EmployeeName">

so just make sure that your selector criteria are valid

Basheer AL-MOMANI
  • 14,473
  • 9
  • 96
  • 92
  • ...meaning that the n.fn.init[0] is returned if you console print a jquery selection function, which returns no matching elements. It could be both timing, or a wrong selection string. I think this adds to the completeness of answering the title of the question. +1 – jumps4fun Jan 05 '17 at 09:50
2

I just want to add something to these great answers. If your DOM element ins't loading in time. You can still set the value.

let Ctrl = $('#mySelectElement'); ... Ctrl.attr('value', myValue);

after that most DOM elements that accept a value attribute should populate correctly.

Train
  • 3,420
  • 2
  • 29
  • 59
-3

Error is that you are using 'ID' in lower case like 'checkbox1' but when you loop json object its return in upper case. So you need to replace checkbox1 to CHECKBOX1.

In my case :-

var response = jQuery.parseJSON(response);

$.each(response, function(key, value) {
   $.each(value, function(key, value){
        $('#'+key).val(value);
   });
});

Before

  <input type="text" name="abc" id="abc" value="">

I am getting the same error but when i replace the id in html code its work fine.

After

<input type="text" name="abc" id="ABC" value="">
Subhan Raza
  • 67
  • 1
  • 2
  • "_when you loop json object its return in upper case_" this is incorrect. Also, the question haven't got anything to do with json. – Nikolaj Dam Larsen Feb 05 '17 at 22:10
  • As Nikolaj said, this is not really relevant for this particular question, even if you experienced a similar error message. Actually, it it not only irrelevant, the answer is actually plain wrong, as my problem had nothing to do with character casing. – jumps4fun Feb 06 '17 at 12:01