0

I've been watching tutorials on using JSON data and JS, decided to work with an API and make a simple APP. I ran into a snag and I'm not sure what's causing the issue. The issue is around the way I'm using user input to modify the query string. When I make my endpoint something static and get rid of the 'movieSearch' function,like this:

const movies = [];
const endpoint = 'http://www.omdbapi.com/?apikey=myAPIkey=batman';

fetch(endpoint)
 .then(blob => blob.json())
 .then(data => movies.push(...data.Search));

It works as desired, granted it's static.

My current code is:

  const movies = [];

  function movieSearch() {
    const replace = this.value;
    const endpoint = 'http://www.omdbapi.com/?apikey=myAPIkey=' + replace;

    movies.length = 0;

    fetch(endpoint)
      .then(blob => blob.json())
      .then(data => movies.push(...data.Search));
  }

  function findMatches(wordToMatch, movies) {
    return movies.filter(film => {
      const regex = new RegExp(wordToMatch, 'gi');
      return film.Title.match(regex) || film.Year.match(regex)
    })
  }

  function displayMatches() {
    const matchArray = findMatches(this.value, movies);
    const html = matchArray.map(film => {
      const regex = new RegExp(this.value, 'gi');
      const titleName = film.Title.replace(regex, `<span class="hl">${this.value}</span>`)
      const yearName = film.Year.replace(regex, `<span class="hl">${this.value}</span>`)
      return `
        <li>
          <span class="name">${titleName}, ${yearName}</span>
          <span class="population">${film.imdbID}</span>
        </li>
      `;
    }).join('');
    suggestions.innerHTML = html;
  }

  const searchInput = document.querySelector('.search');
  const suggestions = document.querySelector('.suggestions');

  searchInput.addEventListener('keyup', displayMatches);
  searchInput.addEventListener('change', displayMatches);
  searchInput.addEventListener('keyup', movieSearch);

The displayMatches function starts acting funny and sometimes returns the list items and other times doesn't. I can't figure out what's causing it. Whichever way I call my endpoint my movies array looks the same, so I'm thoroughly confused.

Any suggestions? Is there a better way to do this?

My HTML is fairly simple right now:

<form class="search-form">
 <input type="text" class="search" placeholder="Movies">
 <ul class="suggestions">
  <li>test1</li>
  <li>test2</li>
 </ul>
</form>

Thanks! (I'm trying to do this all in JS)

Edit:

An example of the JSON data when searching batman with the API:

{"Search":[{"Title":"Batman Begins","Year":"2005","imdbID":"tt0372784","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BZmUwNGU2ZmItMmRiNC00MjhlLTg5YWUtODMyNzkxODYzMmZlXkEyXkFqcGdeQXVyNTIzOTk5ODM@._V1_SX300.jpg"},{"Title":"Batman v Superman: Dawn of Justice","Year":"2016","imdbID":"tt2975590","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BYThjYzcyYzItNTVjNy00NDk0LTgwMWQtYjMwNmNlNWJhMzMyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Batman","Year":"1989","imdbID":"tt0096895","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTYwNjAyODIyMF5BMl5BanBnXkFtZTYwNDMwMDk2._V1_SX300.jpg"},{"Title":"Batman Returns","Year":"1992","imdbID":"tt0103776","Type":"movie","Poster":"https://ia.media-imdb.com/images/M/MV5BOGZmYzVkMmItM2NiOS00MDI3LWI4ZWQtMTg0YWZkODRkMmViXkEyXkFqcGdeQXVyODY0NzcxNw@@._V1_SX300.jpg"},{"Title":"Batman Forever","Year":"1995","imdbID":"tt0112462","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BNWY3M2I0YzItNzA1ZS00MzE3LThlYTEtMTg2YjNiOTYzODQ1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Batman & Robin","Year":"1997","imdbID":"tt0118688","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMGQ5YTM1NmMtYmIxYy00N2VmLWJhZTYtN2EwYTY3MWFhOTczXkEyXkFqcGdeQXVyNTA2NTI0MTY@._V1_SX300.jpg"},{"Title":"The Lego Batman Movie","Year":"2017","imdbID":"tt4116284","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTcyNTEyOTY0M15BMl5BanBnXkFtZTgwOTAyNzU3MDI@._V1_SX300.jpg"},{"Title":"Batman: The Animated Series","Year":"1992–1995","imdbID":"tt0103359","Type":"series","Poster":"https://m.media-amazon.com/images/M/MV5BNzI5OWU0MjYtMmMwZi00YTRiLTljMDAtODQ0ZGYxMDljN2E0XkEyXkFqcGdeQXVyNTA4NzY1MzY@._V1_SX300.jpg"},{"Title":"Batman: Under the Red Hood","Year":"2010","imdbID":"tt1569923","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BYTdlODI0YTYtNjk5ZS00YzZjLTllZjktYmYzNWM4NmI5MmMxXkEyXkFqcGdeQXVyNTA4NzY1MzY@._V1_SX300.jpg"},{"Title":"Batman: The Dark Knight Returns, Part 1","Year":"2012","imdbID":"tt2313197","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMzIxMDkxNDM2M15BMl5BanBnXkFtZTcwMDA5ODY1OQ@@._V1_SX300.jpg"}],"totalResults":"344","Response":"True"}
7
  • 1
    Guess: because the movieSearch function is async the movies array might not always be updated in time. Try adding console.log(movies) in the displayMatches function. Commented Aug 8, 2018 at 0:48
  • 1
    I tried to reproduce your issue but it seams to work for me: jsbin.com/zonipedada/edit?html,js,output I did some minor changes to make it work with an open API that I could use for testing. Commented Aug 8, 2018 at 1:13
  • 1
    Tip: for basic string search you can use 'string'.includes('value'): jsbin.com/boxepeloca/edit?html,js,output Commented Aug 8, 2018 at 1:17
  • 1
    I don't think so by just looking at it, would it be possible for you to post a jsbin or jsfiddle example? If the API key is supposed to go into a url variable it's going to be public anyway... Commented Aug 8, 2018 at 1:40
  • 1
    @Abbe Sure! Here it is: jsbin.com/jimaqateqo/edit?html,js,output Commented Aug 8, 2018 at 1:43

1 Answer 1

1

Issues causing this behavior:

  1. The movieSearch function is async and might not update the data in time.
  2. The API sometimes return an error.

This solved by the code below, note that I moved everything into the fetch resolver making sure the search only executes when the API has responded.

Here is a JS Bin: https://jsbin.com/kicesivigu/1/edit?html,js,output

  function findMatches(wordToMatch, movies) {
    return movies.filter(film => {
      console.log(film.Title, wordToMatch);
      console.log(film.Title.toLowerCase().includes(wordToMatch));
      return film.Title.toLowerCase().includes(wordToMatch) || film.Year.toLowerCase().includes(wordToMatch);
    });
  }

  function displayMatches(movies, value) {
    const matchArray = findMatches(value.toLowerCase(), movies);
    const html = matchArray.map(film => {
      const regex = new RegExp(value, 'gi');
      const titleName = film.Title.replace(regex, `<span class="hl">${value}</span>`);
      const yearName = film.Year.replace(regex, `<span class="hl">${value}</span>`);
      return `
        <li>
          <span class="name">${titleName}, ${yearName}</span>
          <span class="population">${film.imdbID}</span>
        </li>
      `;
    }).join('');
    suggestions.innerHTML = html;
  }

  const searchInput = document.querySelector('.search');
  const suggestions = document.querySelector('.suggestions');


searchInput.addEventListener('keyup', () => {
  const endpoint = 'https://www.omdbapi.com/?apikey=63f88e02&s=' + searchInput.value;

  fetch(endpoint)
    .then(blob => blob.json())
    .then(data => {
      console.log('response from API');
      console.log(data);
      if (!data.Error) displayMatches(data.Search, searchInput.value);
     });
});
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much, this solved the problem and helped me understand how I should have wrote it. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.