1

I'm working on a search function for a list of students in Jquery and while i can get the right results to print to the console, the results are not appearing on the page. I am getting the following error in the console when there is a match. I'm just not sure if there is something wrong with the way i am declaring the listStudents variable on the selector? Is is not possible to run the each function on a selector array such as this? I'm stumped.

Uncaught TypeError: listName.each is not a function
    at showPage (main.js:10)
    at searchList (main.js:92)
    at HTMLButtonElement.<anonymous> (main.js:54)

below is my JS file

var listStudents = $(".student-list").children();
var numStudents = listStudents.length;;


function showPage(pageNum, listName) {
    // first hide all students on the page
    $(".student-list li").hide();
    pageNum = parseInt(pageNum);
    // Then loop through all students in our student list argument
    listName.each(function(index){
    // if student should be on this page number
        if ((index >= ((pageNum*10)-10)) &&  (index <= (pageNum*10))) {
        // show the student
            $(this).show();
            }
    });

 }

function getNumPages(numStudents){
    numPages = Math.ceil(numStudents/10);
    return numPages;
    }


function appendPageLinks(numStudents) {
    // determine how many pages for this student list
    pages  = getNumPages(numStudents);
    // create a page link section
    var nav = "<div class='pagination'><ul>"
    for (i=1; i<pages+1; i+=1){
        nav += ("<li>" + "<a href='#' id=" + i + ">" + i + "</a>" + "</li>");
    };
    nav += ("</ul></div>");
    $(".student-list").after(nav);

    // define what happens when you click a link
    var active = $('.pagination a').click(function(){
        // Use the showPage function to display the page for the link clicked
        var id = $(this).attr('id');
        showPage(id,listStudents);
        // mark that link as “active”
        active.removeClass('active');
        $(this).addClass("active");
        });
}

function appendSearchBox(){
    var search = "<div class='student-search'><input id='search' placeholder='Search for students...'><button>Search</button></div>"
    $(".students").after(search);

    // Add click event handler
    $("button").click(function() {
        searchList();
    });

}

function searchList() {
    var matched = []
    // Obtain the value of the search input
    input = $("#search").val();
    // remove the previous page link section
    $('.pagination').hide();
    // Loop over the student list, and for each student…
    listStudents.each(function(){
        // ...obtain the student’s name…
        var name = $(this).find("h3").text();
        // ...and the student’s email…
        var email = $(this).find(".email").text();
        // ...if the search value is found inside either email or name…
        if (name.includes(input) || email.includes(input))  {
             // ...add this student to list of “matched” student
             matched.push($(this));
             $(".student-list").hide();
             console.log(email);
             console.log(name);
             }
     });
     // If there’s no “matched” students…
     if (matched.length === 0){
         // ...display a “no student’s found” message
         $(".student-list li").hide();
         var message = ("Sorry, no student's found!");
         $("#message").show();
     } else if (matched.length <= 10) {
        // ...call appendPageLinks with the matched students
         $(".student-list li").hide();
         showPage(1, matched);
     } else {
        $(".student-list li").hide();
        showPage(1, matched);
        appendPageLinks(matched.length);
     }
    $('#search').value = ''; // Clears search field
}

//Dynamically add search
appendSearchBox();
//Create pagination dynamically
appendPageLinks(numStudents);
//Show first page on load
showPage(1, listStudents);

here is an example of what student list in HTML looks like--and I am calling Jquery

 <div class="page-header cf">
        <h2 class="students">Students</h2>

      </div>
      <ul class="student-list">
        <li class="student-item cf">
            <div class="student-details">
                <img class="avatar" src="https://randomuser.me/api/portraits/thumb/women/67.jpg">
                <h3>iboya vat</h3>
                <span class="email">iboya.vat@example.com</span>
            </div>
            <div class="joined-details">
                   <span class="date">Joined 07/15/15</span>
           </div>
        </li>
</ul>
</div>
John Rogerson
  • 1,153
  • 2
  • 19
  • 51
  • 4
    `$.each(listName, function(index, val){})` - see jQuery documentation on [**$.each**](http://api.jquery.com/jquery.each/) – Nope Sep 07 '17 at 14:12
  • What version of jquery do you use? – wrager Sep 07 '17 at 14:12
  • 6
    Please don't post your entire code. 95% of this code are not related to your problem at all but you still force everyone to read them anyway. Concentrate on the relevant bits and throw out the rest. – Tomalak Sep 07 '17 at 14:13
  • jquery 1.12.4, and I understand rules about posting code, but felt that in order to figure out what is happening it might be necessary to see it all? – John Rogerson Sep 07 '17 at 14:15
  • @JohnRogerson Best is to only post enough code to replicate the issue which in this case could have been as short as a hard-coded version of your array object using `.each` to replicate the error. A snippet can be created in the question linking jQuery as well. See this for more details - [**How to create a Minimal, Complete, and Verifiable example**](https://stackoverflow.com/help/mcve) - The good thing about making a minimal example to demo your issue is that you find the error a lot of the time yourself in the process :) Win/Win – Nope Sep 07 '17 at 14:18
  • No, not really. What's necessary is the minimum code that reproduces the problem. The function calls with arguments. The function bodies only as far as necessary to determine the value of the relevant arguments. That amounts to about 10-15 lines of code here. Everything else should not be in the question. Reduce, rewrite, and reproduce the error. This also helps *you* to understand what's going on. – Tomalak Sep 07 '17 at 14:18
  • ok, thanks for explaining--will work to better clarify the code – John Rogerson Sep 07 '17 at 14:26
  • i did change both each loops to format using $.each and the error clears but search results aren't appearing... – John Rogerson Sep 07 '17 at 14:27
  • Ok I determined the problem. In my searchList function, after I pushed the results to the 'matched' list, i was calling `'student-list'.hide(); which was actually hiding the search results. Thanks for all of your responses. – John Rogerson Sep 07 '17 at 14:31
  • A general tip for working with jQuery. Get into the habit of prefixing all variables that are containing (or are supposed to contain) a jQuery object with `$`. So, instead of `listName`, call it `$listName`, all the way through. This makes you see assignment mistakes earlier. In this case your assignment mistake is not obvious, but `$(".student-list").children()` *does not* return a jQuery object. Check the documentation. You mean `$(".student-list > *")`. – Tomalak Sep 07 '17 at 14:37
  • And another, related tip for working with jQuery: Explicitly wrapping things in `$()` never hurts. This is especially useful for function arguments that could be multiple things (a DOM object, an array of DOM objects - like in your case - , or a jQuery object) but you want to use jQuery methods on them. `$(listName).each(...)` would have worked with any type of value `listName` might have. This also would have cleared the error. – Tomalak Sep 07 '17 at 14:42
  • @Tomalak good stuff--very informative for someone fairly new to jQuery. Much appreciated. – John Rogerson Sep 07 '17 at 14:50
  • And the last tip, generally applicable: Avoid misleading variable names. For me as an uninvolved third party, `listName` implies that the variable contains the name of a list, i.e. a string. Like `filename` would be the name of a file. Calling it `$names` would imply that it's a list of names (plural) and supposed to be jQuery. That's much more on point. Staying within your own convention would also have been slightly better, i.e. `listNames` (plural again, just like `listStudents`), but the plural already conveys the meaning "it's a list", so the `list` prefix becomes somewhat superfluous. – Tomalak Sep 07 '17 at 14:57

1 Answers1

6

Use $.each() or forEach to iterate over arrays.

var array = [1, 2, 3];

$.each(array, function(index, value) {
    console.log(index, value);
});

array.forEach(function(value) {
    console.log(value);
});

As the jQuery docs states:

The $.each() function is not the same as $(selector).each(), which is used to iterate, exclusively, over a jQuery object. The $.each() function can be used to iterate over any collection, whether it is an object or an array.

JasonK
  • 5,214
  • 9
  • 33
  • 61