Thank you for posting back your question. As promised here is my answer.
Some comments
Here are a few points I should mention:
I like your code because you're using quite a lot of Array
's methods and template literals and you're handling the asynchronous call nicely.
the first time I read the code I immediately noticed there were two identical chunks of code: mainly the HTML formatting part, it is redundant and can use a good refactoring. This way you can easily reduce the number of repeated pieces of code. Also, there are too many levels in your function searchTvShows
.
you may want to choose an alternative to the classic .innerHTML +=
. Adding HTML to the page with this method forces the browser to re-render the DOM which is not very efficient. You could instead create a new HTML element and append it to an existing one.
there are hardly any comments in your code (you should add more meaningful comments to help understand your code. For example this statement .slice(0, 9)
doesn't need to have the comment // tar element 0-9 i arrayen
because it's obvious.
you're using both .querySelector
and .getElementById
, maybe you should just stick with the latter, it's more efficient to use because you can select by CSS selector. Also why some HTML elements have id
others have a class
? You can minimize the number of times you call these methods by preparing an object containing all the used elements. This way you can access them without needing to reselect them.
You may want to use the keyup
event instead of the keydown
. The latter will run the function for the before last letter. So it is not updating the search properly.
there is no consistency in the use of semicolons ;
.
Refactored code
const elements = {
input: document.querySelector('#inputSearchField'),
app: document.querySelector('#app')
};
// filters applied on the recieved data objects
const topTen = json => json
.filter(show => show.rating.average)
.sort((a, b) => a.rating.average > b.rating.average ? -1 : 1)
.slice(0, 9)
const fixMap = shows => shows.map(s => s.show)
// fetch and show search results from API source
const searchTvShows = (filter = false, target = undefined) => {
const url = `https://api.tvmaze.com/${target ? `search/shows?q=${target}` : `shows`}`;
console.log(url)
fetch(url)
.then(blob => blob.json())
.then(json => filter ? filter(json) : json)
.then(shows => {
elements.app.innerHTML = shows.map((show) => formatShow(show)).join(' ') || "<div>No match</div>";
});
}
// HTML formatting of a show
const formatShow = (show) => `
<div class="col-sm movie-content">
<div class="movie-image">
${show.image
? `<img src="${show.image.medium}">`
: `<img class="fallbackImage" src="design/icons/No_image_available.svg">`
}
</div>
<div class="movie-info">
<h1>${show.name}</h1>
</div>
</div>
`
This way you can call the featured list and the result list with the same function searchTvShows
:
featured films:
searchTvShows(topTen)
↑
filter applied
to the search
updating search results:
elements.input.addEventListener('keyup',()=>searchTvShows(fixMap, event.target.value))
↑ ↑
access saved filter to
HTML element fix the response
({show}) vs (show)
const elements = {
input: document.querySelector('#inputSearchField'),
app: document.querySelector('#app')
};
// filters applied on the recieved data objects
const topTen = json => json
.filter(show => show.rating.average)
.sort((a, b) => a.rating.average > b.rating.average ? -1 : 1)
.slice(0, 9)
const fixMap = shows => shows.map(s => s.show)
// fetch and show search results from API source
const searchTvShows = (filter = false, target = undefined) => {
const url = `https://api.tvmaze.com/${target ? `search/shows?q=${target}` : `shows`}`;
console.log(url)
fetch(url)
.then(blob => blob.json())
.then(json => filter ? filter(json) : json)
.then(shows => {
elements.app.innerHTML = shows.map((show) => formatShow(show)).join(' ') || "<div>No match</div>";
});
}
// HTML formatting of a show
const formatShow = (show) => `
<div class="col-sm movie-content">
<div class="movie-image">
${show.image
? `<img src="${show.image.medium}">`
: `<img class="fallbackImage" src="design/icons/No_image_available.svg">`
}
</div>
<div class="movie-info">
<h1>${show.name}</h1>
</div>
</div>
`
elements.input.addEventListener('keyup', () => searchTvShows(fixMap, event.target.value))
searchTvShows(topTen)
.fallbackImage {
background: lightgrey;
height: 200px;
width: 200px;
}
<input id="inputSearchField">
<div id="app"></div>