-1

I have created a website that lets users create and add events, now I have added a search so that users can search through different events, the problem is when the event searched is not present, it should log an error message saying "No events found" but this message is displayed multiple times depending on how many events are currently present instead of showing it only once because of the forEach() method. What should I do to make it work and display the error message only once, if no event is found with that name.

search.ejs


<div class="container">
    <header class="jumbotron" style="padding-left: 0px; padding-top: 5px; padding-bottom: 5px;">
       <h2>Search Results:</h2>
    </header>
   <!-- <% console.log(search_event)%> -->
   <div class="row text-center">

        <% events.forEach(function(i){ %>

          <% if(i.name.includes(search_event)) { %>

         <div class="col-md-3 col-sm-6">                                              <!--Double cols to make the site responsive and mobile compatible-->
          <div class="thumbnail">
            <img src=" <%= i.image %>">
            <div class="caption">
              <h4> <%= i.name%> </h4> 
            </div>
            <p>
              <a href="/events/<%= i._id %>" class="btn btn-primary">More Info</a>
            </p>
          </div>
        </div>

        <% } else  { %>

           <h4> No such event exists </h4>
          <% } %>
       <% });%>

    </div>
</div>
<% include partials/footer  %>
  • 1
    Possible duplicate of [Short circuit Array.forEach like calling break](https://stackoverflow.com/questions/2641347/short-circuit-array-foreach-like-calling-break). You can find your way to stop `forEach` in that answer. – Krishna Prashatt May 13 '19 at 06:30
  • I went through that but it didn't solve the issue – Vedant Soni May 13 '19 at 06:31
  • You cannot stop a `forEach` - it runs once for each element in the array. That's just how it works. If you need to iterate over and do an early exit, use a loop. – VLAZ May 13 '19 at 06:33
  • I tried using for loop, but it wouldn't work with the function. Could you please show me how ? – Vedant Soni May 13 '19 at 06:35
  • use `.every` (return false to stop) or `.some` (return true to stop) - oh, wait, I thought this was a javascript question, nevermind – Jaromanda X May 13 '19 at 06:35
  • `.every()` iterates over only the first event created, this solves the error problem to display it once but this would hamper the functioning of search as it searches only for the first created event, `.some()` was also not working. – Vedant Soni May 13 '19 at 06:37

3 Answers3

1

You should pre-compute how many items will be displayed by using Array.prototype.filter.

If this array has length, you should iterate and display them. If there is no length, display "no results".


var filteredEvents = events.filter(event => event.name.includes(search_event));

if (filteredEvents.length) {
 // forEach
} else {
 // no results
}
neaumusic
  • 10,027
  • 9
  • 55
  • 83
  • The problem with this is that you iterate twice. Once for the filter, then the subsequent `forEach`, all be it on a smaller (hopefully) set. – Jon P May 13 '19 at 07:38
  • You could add them to a template variable and check whether that template has children before rendering it. I wouldn't worry about iteration, the only expense with JS/CSS/HTML is when you have to actually update the DOM more than once (see performance tab in DevTools) – neaumusic May 13 '19 at 16:38
0

Just set a flag. and check if exist. it will not allow it to enter if it prints once.

<div class="container">
    <header class="jumbotron" style="padding-left: 0px; padding-top: 5px; padding-bottom: 5px;">
       <h2>Search Results:</h2>
    </header>
   <!-- <% console.log(search_event)%> -->
   <div class="row text-center">
        <% var error = false; %>
        <% events.forEach(function(i){ %>

          <% if(i.name.includes(search_event)) { %>

         <div class="col-md-3 col-sm-6">                                              <!--Double cols to make the site responsive and mobile compatible-->
          <div class="thumbnail">
            <img src=" <%= i.image %>">
            <div class="caption">
              <h4> <%= i.name%> </h4> 
            </div>
            <p>
              <a href="/events/<%= i._id %>" class="btn btn-primary">More Info</a>
            </p>
          </div>
        </div>

        <% } else  { %>
        <% if(!error) { %>
          <% error = true; %>
           <h4> No such event exists </h4>
          <% } %>
         <% } %>
       <% });%>

    </div>
</div>
<% include partials/footer  %>
Syed mohamed aladeen
  • 6,507
  • 4
  • 32
  • 59
0

You can actually do this with straight css and set the no results to display: none, but have a style rule that shows it if the preceding row is empty.

I have added classnames to each of hte rows - search results and no results. then simply toggling the display state using the :empty pseudo selector and the "+" direct sibling combinator.

.no-results-wrapper {
  display: none;
}

.search-results-wrapper:empty + .no-results-wrapper {
  display: block;
}
<div class="container">
    <header class="jumbotron" style="padding-left: 0px; padding-top: 5px; padding-bottom: 5px;">
       <h2>Search Results:</h2>
    </header>
   <!-- <% console.log(search_event)%> -->
   <div class="row text-center search-results-wrapper">
        <% events.forEach(function(i){ %>
          <% if(i.name.includes(search_event)) { %>
         <div class="col-md-3 col-sm-6">                                           
          <div class="thumbnail">
            <img src=" <%= i.image %>">
            <div class="caption">
              <h4> <%= i.name%> </h4> 
            </div>
            <p>
              <a href="/events/<%= i._id %>" class="btn btn-primary">More Info</a>
            </p>
          </div>
        </div>
        <% }%>
      <% });%>
    </div>
     
     <div class="no-results-wrapper">
       <h4> No such event exists </h4>
     </div>

</div>
<% include partials/footer  %>
gavgrif
  • 15,194
  • 2
  • 25
  • 27