DEV Community

Cover image for Node App: How to create netflix clone. Netflix clone with HTML,CSS, JS.
Modern Web
Modern Web

Posted on • Updated on

Node App: How to create netflix clone. Netflix clone with HTML,CSS, JS.

Hello, Today we'll see, how we can easily create a netflix clone using HTML, CSS and JS only. No other library. We'll also use TMDB API to fetch real data from their database.

Netflix Clone, we all use netflix in our day to day life. And if you are just starting with web development. This project can be a good practice project for you. This netflix clone is a dynamic site and has everything you need for fullstack development practice. It runs on a Node.js server. It uses TMDB API for all data.

Features

  1. Looks similar to Netflix.
  2. Dynamic site run on Node.js server.
  3. All data is coming from TMDB API.
  4. Dedicated Dynamic Movies Info page.
  5. Has movie trailers, and recommendations.
  6. Has smooth card slider effect.

Capture-2 (1)

To see demo or you want full coding tutorial video. You can watch the tutorial below.

Video Tutorial

I appreciate if you can support me by subscribing my youtube channel.

So, without wasting more time let's see how to code this.

Code

As this is a node.js web app. We need NPM and Node.js in order to start with, so make sure you have them installed in your system.

So let's start with its folder structure.

Folder Structure.

This is our folder structure.

Folder Structure

NPM Init

Let's start with initializing NPM. So outside public folder, In your root directory, open Command Prompt or terminal. And execute. npm init

It will ask you for some details. You can press enter to have default project details. After executing npm init you should see a package.json file.

Great Now install Some libraries that we need in order to create a server.

Installing Libraries

After creating package.json file. Run this command.

npm i express.js nodemon
Enter fullscreen mode Exit fullscreen mode

i - means install.
express.js - is a library we need to create server.
nodemon - is a library which allow you to run server seamlessly even after making changes to the server.

After installation complete, you should be able to see node_modules folder in your root directory.

Now open package.json file in your text editor. And edit it a little bit.

  1. Change the value on "main" key to "server.js".
    main

  2. Delete "test" cmd from "scripts" object. And add new cmd called "start" and set it value to "nodemon server.js".
    scripts

Server.js

After editing package.json create JS file server.js in the root directory.

And write this in server.js.

const express = require('express');
const path = require('path');

let initial_path = path.join(__dirname, "public");

let app = express();
app.use(express.static(initial_path));

app.get('/', (req, res) => {
    res.sendFile(path.join(initial_path, "index.html"));
})

app.listen(3000, () => {
    console.log('listening on port 3000......');
})
Enter fullscreen mode Exit fullscreen mode
Explanation

In the top, we are using require method to import library so that we can use it in this file. We are importing two libraries express and path.

path library is used to track paths.

After done importing libraries. We are setting a variable app equal to express(), which enable all the server related features to our app variable. And we also have initial_path which is holding our public folder path.

After that we have, app.use() which is used as a middle ware And inside this we have express.static() which allow us to set our static directory path. In this case we are setting our public folder as a static path, because our HTML files are inside that folder.

app.get('/') is a listener, And in this case it is listening for a GET request to our root / path. And whenever we get any GET request on /. We will serve them index.html file. That's what res.sendFile() do.

And the last block of our server.js is app.listen which is used to add a server's listening port. In this case, we set it to 3000. So our server will run on localhost:3000. Not any other port.

Now in your terminal or cmd prompt. Run npm start to start the server. And, open your browser to localhost:3000. You'll be able to see index.html file.

So up until now we have created our server and successfully serving our index.html file to / path.

So let's do some front end work here. Now

Home page.

So for our Home page, we will use these files. index.html, style.css, home.js, api.js, scroll.js.

Let's start from index.html file. Start typing basic HTML structure. And after that link style.css file. And let's create navbar first.

<!-- navbar -->
<nav class="navbar">
    <img src="img/logo.png" class="logo" alt="">
    <div class="join-box">
        <p class="join-msg">unlimited tv shows & movies</p>
        <button class="btn join-btn">join now</button>
        <button class="btn">sign in</button>
    </div>
</nav>
Enter fullscreen mode Exit fullscreen mode

Make sure your server is running, if it is not then run npm start in your terminal.

Output

navbar

All the CSS properties I'll use are easy to understand. So i'll only explain you JS only. But if you have doubt in any part. Even in CSS. Feel free to ask me in discussions.

Now style the navbar

*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body{
    width: 100%;
    position: relative;
    background: #181818;
    font-family: 'roboto', sans-serif;
}

.navbar{
    width: 100%;
    height: 60px;
    position: fixed;
    top: 0;
    z-index: 9;
    background: #000;
    padding: 0 2.5vw;
    display: flex;
    align-items: center;
}

.logo{
    height: 60%;
}

.join-box{
    width: fit-content;
    display: flex;
    justify-content: center;
    align-items: center;
    height: auto;
    margin-left: auto;
}

.join-msg{
    color: #fff;
    text-transform: uppercase;
}

.btn{
    border: 1px solid #fff;
    border-radius: 2px;
    background: none;
    color: #fff;
    height: 35px;
    padding: 0 10px;
    margin-left: 10px;
    text-transform: uppercase;
    cursor: pointer;
}

.join-btn{
    background: #dd0e15;
    border-color: #dd0e15;
}
Enter fullscreen mode Exit fullscreen mode
Output

navbar 2
Now create movie section.

<!-- main section -->
<header class="main">
    <h1 class="heading">movies</h1>
    <p class="info">Movies move us like nothing else can, whether they're scary, funny, dramatic, romantic or anywhere in-between. So many titles, so much to experience.</p>
</header>
Enter fullscreen mode Exit fullscreen mode

And style it

.main{
    position: relative;
    margin-top: 60px;
    width: 100%;
    padding: 40px 2.5vw;
    color: #fff;
}

.heading{
    text-transform: capitalize;
    font-weight: 900;
    font-size: 50px;
}

.info{
    width: 50%;
    font-size: 20px;
    margin-top: 10px;
}
Enter fullscreen mode Exit fullscreen mode

main-2
And we have to create a movie list element inside .main element, this will hold our same genres movie.

<div class="movie-list">

    <button class="pre-btn"><img src="img/pre.png" alt=""></button>

    <h1 class="movie-category">Popular movie</h1>

    <div class="movie-container">
        <div class="movie">
            <img src="img/poster.jpg" alt="">
            <p class="movie-title">movie name</p>
        </div>
    </div>

    <button class="nxt-btn"><img src="img/nxt.png" alt=""></button>

</div>
Enter fullscreen mode Exit fullscreen mode

You can see here, we have pre-btn and nxt-btn with them we also have a movie-card element. Well, we will create movie card and list element all with JS but for styling purpose we are creating one card here. Just for the sake of CSS.

.movie-list{
    width: 100%;
    height: 250px;
    margin-top: 40px;
    position: relative;
}

.movie-category{
    font-size: 20px;
    font-weight: 500;
    margin-bottom: 20px;
    text-transform: capitalize;
}

.movie-container{
    width: 100%;
    height: 200px;
    display: flex;
    align-items: center;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-behavior: smooth;
}

.movie-container::-webkit-scrollbar{
    display: none;
}

.movie{
    flex: 0 0 auto;
    width: 24%;
    height: 200px;
    text-align: center;
    margin-right: 10px;
    cursor: pointer;
    position: relative;
}

.movie img{
    width: 100%;
    height: 170px;
    object-fit: cover;
}

.movie p{
    text-transform: capitalize;
    height: 20px;
    overflow: hidden;
}

.pre-btn,
.nxt-btn{
    position: absolute;
    height: 200px;
    top: 50%;
    transform: translateY(-50%);
    width: 2.5vw;
    background: #181818;
    border: none;
    outline: none;
    opacity: 0;
}

.pre-btn{
    left: -2.5vw;
}

.nxt-btn{
    right: -2.5vw;
}

.pre-btn img,
.nxt-btn img{
    width: 20px;
    height: 20px;
    object-fit: contain;
}

.nxt-btn:hover,
.pre-btn:hover{
    opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture-3

Once we are done styling our cards. we can commit them.

<header class="main">
    <h1 class="heading">movies</h1>
    <p class="info">Movies move us like nothing else can, whether they're scary, funny, dramatic, romantic or anywhere in-between. So many titles, so much to experience.</p>
    <!-- movie list -->
    <!-- <div class="movie-list">

        <button class="pre-btn"><img src="img/pre.png" alt=""></button>

        <h1 class="movie-category">Popular movie</h1>

        <div class="movie-container">
            <div class="movie">
                <img src="img/poster.jpg" alt="">
                <p class="movie-title">movie name</p>
            </div>
        </div>

        <button class="nxt-btn"><img src="img/nxt.png" alt=""></button>

    </div> -->
</header>
Enter fullscreen mode Exit fullscreen mode

Our main section should look like this. As we are done with homepage.

Now add all JS files in index.html file. As we need them now.

<script src="js/api.js"></script>
<script src="js/scroll.js"></script>
<script src="js/home.js"></script>
Enter fullscreen mode Exit fullscreen mode

Make sure you add these files in exactly same order.

Now go to TMDB Official Site TO create an API key. If you don't know how to create it. Watch This.

After creating API key paste it into api.js file

api.js
let api_key = "your api key";
Enter fullscreen mode Exit fullscreen mode

And after that go to TMDB Documentation. And find these three HTTP links.

api.js
let api_key = "your api key";

let img_url = "https://image.tmdb.org/t/p/w500";
let genres_list_http = "https://api.themoviedb.org/3/genre/movie/list?";
let movie_genres_http = "https://api.themoviedb.org/3/discover/movie?";
Enter fullscreen mode Exit fullscreen mode
  1. img_url - is to fetch image. Because we'll get movie image's path id. For example if we got image id as 123 then the image url will be https://image.tmdb.org/t/p/w500/123
  2. genres_list_http - is to fetch movie genres list so we don't have to fetch different genres movie manually.
  3. movie_genres_http - is to fetch the movie having same genres.

After done with these HTTPs. Open home.js file.

home.js
fetch(genres_list_http + new URLSearchParams({
    api_key: api_key
}))
.then(res => res.json())
.then(data => {
    data.genres.forEach(item => {
        fetchMoviesListByGenres(item.id, item.name);
    })
});
Enter fullscreen mode Exit fullscreen mode
Explanation

Here, we are using fetch method to genres_list_http that we have declared in api.js file. And using new URLSearchParams for adding api_key parameters to the link. And after getting res we are converting it to JSON be res.json() and after converting it to JSON we got the fetched data. Inside that. before understanding what we are doing. First see our fetched data structure.

Capture-2

So as to understood the data structure. Now understand what we are doing after getting JSON data.

data.genres.forEach(item => {
    fetchMoviesListByGenres(item.id, item.name);
})
Enter fullscreen mode Exit fullscreen mode

As we have an array of genres, we are looping through each and every genres using forEach method. And inside that we are calling fetchMoviesListByGenres(id, genres) which we'll create next.

Now fetch movies with genres.

const fetchMoviesListByGenres = (id, genres) => {
    fetch(movie_genres_http + new URLSearchParams({
        api_key: api_key,
        with_genres: id,
        page: Math.floor(Math.random() * 3) + 1
    }))
    .then(res => res.json())
    .then(data => {
        makeCategoryElement(`${genres}_movies`, data.results);
    })
    .catch(err =>  console.log(err));
}
Enter fullscreen mode Exit fullscreen mode
Explanation

Here we are doing the same, we are fetching data but in this case we are making request to movie_genres_http and adding some more parameters.
with_genres param will give us movie with only that genres for instance if our genres id if for comedy movies, then we'll only get comedy movies.
page param will give use what of the result we want and in this case we are using Math.random() to fetch some random page of movie result.

After getting the data, we are performing the same res.json() to covert it into JSON. And calling makeCategoryElement(category, data) which will create our movie categories. Same if you want you can console log the data structure.

Now create movie categories. But before that select our main element from HTML.

const main = document.querySelector('.main');
Enter fullscreen mode Exit fullscreen mode
const makeCategoryElement = (category, data) => {
    main.innerHTML += `
    <div class="movie-list">

        <button class="pre-btn"><img src="img/pre.png" alt=""></button>

        <h1 class="movie-category">${category.split("_").join(" ")}</h1>

        <div class="movie-container" id="${category}">

        </div>

        <button class="nxt-btn"><img src="img/nxt.png" alt=""></button>

    </div>
    `;
    makeCards(category, data);
}
Enter fullscreen mode Exit fullscreen mode
Explanation

In this function, we have two arguments one is category and second is data. So the first thing our function is doing is adding a .movie-list element to our main element using innerHTML. If you remember this we created in our HTML file but at last commented copy that code and paste it here. Make sure you use += not = because we don't want to re-write its HTML.

<h1 class="movie-category">${category.split("_").join(" ")}</h1>
if you see this line. First of all we are using JS template string if you don;t use that you'll be not able to write like this. So here as we had an h1 element. we are setting it's text to our category that we got at the start of the function. But we also performing some methods here.Let's see them in detail.

for instance, assume category is equal to comedy.

  1. <h1 class="movie-category">${category}</h1> Then output will be - comdey_movies. But we don't wont _ that why we split it.
  2. <h1 class="movie-category">${category.split("_")}</h1> Then it will not work because now we have an array ["comedy", "movies"]. That's why use join method to join the array.
  3. <h1 class="movie-category">${category.split("_").join(" ")}</h1> Then the output will be - Comedy Movies

I hope you understood this.

And then we are setting up a unique id to movie-container element so we can add card to it later. And at the very last, we are calling makeCards(category, data) to make cards inside that movie container element.

Now create a cards.

const makeCards = (id, data) => {
    const movieContainer = document.getElementById(id);
    data.forEach((item, i) => {

    })
}
Enter fullscreen mode Exit fullscreen mode
Explanation

Inside this function, we are selecting the movie container element on the start using that id we got from the above function. And after that we are looping through data using forEach method. Inside that We are checking some condition.

if(item.backdrop_path == null){
   item.backdrop_path = item.poster_path;
   if(item.backdrop_path == null){
      return;
  }
}
Enter fullscreen mode Exit fullscreen mode

This condition is checking, if we don't have movie backdrop image path in our result set it to poster_path and we don't have that too. Don't make the card. Sometime TMDB movie's data do not have image path in it that's why we are checking for it.

After that we have

movieContainer.innerHTML += `
<div class="movie" onclick="location.href = '/${item.id}'">
    <img src="${img_url}${item.backdrop_path}" alt="">
    <p class="movie-title">${item.title}</p>
</div>
`;
Enter fullscreen mode Exit fullscreen mode

Here, we are using the innerHTML method to append the card HTML structure that we already made at the start. And again here also we are using template strings. If you see we have onclick event to movie-card element which, in that event we are using location.href to redirect user to movie page that we'll create next.

if(i == data.length - 1){
    setTimeout(() => {
        setupScrolling();
    }, 100);
}
Enter fullscreen mode Exit fullscreen mode

And this is checking for the last cast. when we are done creating cards. we are running setupScrolling() function to setup slider effect. We also have to create this.

After writing this much of JS. Now we can see the output without any errors.

Output

Capture

But we haven't created our slider effect write. For that open scroll.js file.

scroll.js
const setupScrolling = () => {
    const conainter = [...document.querySelectorAll('.movie-container')];
    const nxtBtn = [...document.querySelectorAll('.nxt-btn')];
    const preBtn = [...document.querySelectorAll('.pre-btn')];
}
Enter fullscreen mode Exit fullscreen mode
Explanation

First in this function we are selecting our containers, next buttons and previous buttons using querySelectorAll method.

After selecting them. Inside the function type this.

conainter.forEach((item, i) => {
    let containerDimensions = item.getBoundingClientRect();
    let containerWidth = containerDimensions.width;
})
Enter fullscreen mode Exit fullscreen mode

Here we are looping through each container element. And using getBoundingClientRect method to get container's dimensions. And at last storing containerDimensions.width (which of course give container width) to containerWidth.

After that inside this for loop add this.

nxtBtn[i].addEventListener('click', () => {
    item.scrollLeft += containerWidth;
})

preBtn[i].addEventListener('click', () => {
    item.scrollLeft -= containerWidth;
}
Enter fullscreen mode Exit fullscreen mode

Here we are selecting our nxtBtn and preBtn with container's index. And adding click event to them. And just performing simple maths.

After this we should be able to get our slider effect.

Our Home page is done.

Server.js

Now for about page we need to add some more codes in server.js.
Type this before app.listen();

app.get('/:id', (req, res) => {
    res.sendFile(path.join(initial_path, "about.html"));
})

app.use((req, res) => {
    res.json("404");
})
Enter fullscreen mode Exit fullscreen mode

Here, we are adding GET request listener to /:id path. THis means anything with a single slash in front, execute the code. It will work for /123 but not for /123/12/1. And at last we have app.use() which again use as a middle ware and this means that if the requesting path is not the same as above paths. Execute this. Means 404 message.

After this you'll be able to redirect yourself to movie detail page by clicking on movie card.

About Page

Let's create this last page. For this link both about.css and style.css file so we don't have to write lot of CSS.

And copy paste the navbar here. After that create movie-info element

about.html
<!-- movie info -->
<div class="movie-info">
    <div class="movie-detail">
        <h1 class="movie-name">Movie Name</h1>
        <p class="genres">Comedy</p>
        <p class="des">Lorem ipsum dolor sit amet consectetur, adipisicing elit. In commodi incidunt odit inventore suscipit, debitis officia modi exercitationem animi nemo.</p>
        <p class="starring"><span>Starring:</span></p>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

And style it.

.movie-info{
    width: 100%;
    height: calc(100vh - 60px);
    margin-top: 60px;
    background-size: cover;
    background-repeat: no-repeat;
}

.movie-detail{
    width: 50%;
    height: 100%;
    background: rgb(24, 24, 24);
    background: linear-gradient(90deg, rgba(24, 24, 24, 1), rgba(24, 24, 24, 0) 100%);
    padding: 5vw;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    color: #fff;
}

.movie-name{
    font-size: 30px;
    font-weight: 500;
}

.genres{
    opacity: 0.6;
    margin: 30px 0;
}

.des{
    width: 70%;
    line-height: 20px;
    margin-bottom: 30px;
}

.starring span{
    opacity: 0.6;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture-4
Once CSS is complete you can remove all the text from the info elements making them totally empty.

<h1 class="movie-name"></h1>
<p class="genres"></p>
<p class="des"></p>
<p class="starring"><span>Starring:</span></p>
Enter fullscreen mode Exit fullscreen mode

Like this.

Now create video recommendation.

<div class="trailer-container">
    <h1 class="heading">Video Clip</h1>
    <iframe src="" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
Enter fullscreen mode Exit fullscreen mode

You can notice we have iframe here. And this is little hard to understand so I suggest you watch this to understand video trailer better.
Style It.

.trailer-container,
.recommendations{
    color: #fff;
    padding: 5vw 5vw 0;
}

.heading{
    font-size: 30px;
    font-weight: 300;
    margin-bottom: 20px;
}

iframe{
    width: 400px;
    height: 200px;
}
Enter fullscreen mode Exit fullscreen mode

In output we'll see nothing except our movie info element and a video clip text. Because our iframe source is empty.

Now create recommendation container.

<div class="recommendations">
    <h1 class="heading">More Like This</h1>
    <div class="recommendations-container">
        <div class="movie">
            <img src="img/poster.jpg" alt="">
            <p class="movie-title">movie name</p>
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS

.recommendations-container{
    width: 100%;
    display: flex;
    flex-wrap: wrap;
}

.movie p{
    position: absolute;
    bottom: 30px;
    width: 100%;
    height: 30px;
    line-height: 30px;
    background: rgba(0, 0, 0, 0.5);
    text-align: center;
    opacity: 0;
}

.movie:hover p{
    opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode
Output

Capture05
As we have done styling. You can comment .movie element. This is the same element that we have created in home page.

Add scripts to this page also. And remeber to add this is same exact order.

<script src="js/api.js"></script>
<script src="js/about.js"></script>
Enter fullscreen mode Exit fullscreen mode

Now open api.js file. And add this.

let original_img_url = "https://image.tmdb.org/t/p/original";
let movie_detail_http = "https://api.themoviedb.org/3/movie";
Enter fullscreen mode Exit fullscreen mode

You can find these HTTPs from TMDB documentation.
original_img_url - This is to fetch movie image in original resolution.
movie_detail_http - This is to fetch details of a particular movie.

Now open about.js. And write this.

let movie_id = location.pathname;
Enter fullscreen mode Exit fullscreen mode

by location.pathname you will be able to extract movie id from the URL. For example if the URL is localhost:3000/123 then this will return /123 which is our movie id.

After that fetch movie details using the same fetch method. and pass the fetched data to a function called setupMovieInfo(data).

// fetching movie details
fetch(`${movie_detail_http}${movie_id}?` + new URLSearchParams({
    api_key: api_key
}))
.then(res => res.json())
.then(data => {
    setupMovieInfo(data);
})
Enter fullscreen mode Exit fullscreen mode

Let's create setupMovieInfo.

const setupMovieInfo = (data) => {
    const movieName = document.querySelector('.movie-name');
    const genres = document.querySelector('.genres');
    const des = document.querySelector('.des');
    const title = document.querySelector('title');
    const backdrop = document.querySelector('.movie-info');

    title.innerHTML = movieName.innerHTML = data.title; 
    genres.innerHTML = `${data.release_date.split('-')[0]} | `;
    for(let i = 0; i < data.genres.length; i++){
        genres.innerHTML += data.genres[i].name + formatString(i, data.genres.length);
    }

    if(data.adult == true){
        genres.innerHTML += ' | +18';
    }

    if(data.backdrop_path == null){
        data.backdrop_path = data.poster_path;
    }

    des.innerHTML = data.overview.substring(0, 200) + '...';

    backdrop.style.backgroundImage = `url(${original_img_url}${data.backdrop_path})`;
}
Enter fullscreen mode Exit fullscreen mode
Explanation

This function is very simple, at start it is selecting all elements like movie name, title tag, des, genres. And after selecting all the elements. We are setting the value using innerHTML method. But for genres we have some conditions, like at first we are adding only released year by doing some formatting. And after that we are loopin through all the genres movie's data have and adding them to the genres with some formatting. And yes, you can see formatString function let's create this.

const formatString = (currentIndex, maxIndex) => {
    return (currentIndex == maxIndex - 1) ? '' : ', ';
}
Enter fullscreen mode Exit fullscreen mode

After genres we are checking for backdrop_path as we checked it before in homepage. And setting up the image as a background image.

Then as we don't get the cast info with the movies detail. We have to fetch it seperately.

//fetching cast info

fetch(`${movie_detail_http}${movie_id}/credits?` + new URLSearchParams({
    api_key: api_key
}))
.then(res => res.json())
.then(data => {
    const cast = document.querySelector('.starring');
    for(let i = 0; i < 5; i++){
        cast.innerHTML += data.cast[i].name + formatString(i, 5);
    }
})
Enter fullscreen mode Exit fullscreen mode

And I think this is very easy to understand. But if you have a doubt ask me in discussions.

Now if we see the output.

Output

Capture-2 (1)

Now let's fetch video clips.

/ fetching video clips

fetch(`${movie_detail_http}${movie_id}/videos?` + new URLSearchParams({
    api_key: api_key
}))
.then(res => res.json())
.then(data => {
    let trailerContainer = document.querySelector('.trailer-container');

    let maxClips = (data.results.length > 4) ? 4 : data.results.length;

    for(let i = 0; i < maxClips; i++){
        trailerContainer.innerHTML += `
        <iframe src="https://youtube.com/embed/${data.results[i].key}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
        `;
    }
})
Enter fullscreen mode Exit fullscreen mode

Here, we are fetching videos detail related to movies. And after getting results we are checking a condition to set maxClips because we want 4 clips at most. And after that we are looping maxClips time. And creating an Iframe this is the same structure that we have in our HTML file. Copy that from there to here. But notice it's src attribute carefully.

Output

Capture-3

Now the last thing create recommendations.

// fetch recommendations

fetch(`${movie_detail_http}${movie_id}/recommendations?` + new URLSearchParams({
    api_key: api_key
}))
.then(res => res.json())
.then(data => {
    let container = document.querySelector('.recommendations-container');
    for(let i = 0; i < 16; i++){
        if(data.results[i].backdrop_path == null){
            i++;
        }
        container.innerHTML += `
        <div class="movie" onclick="location.href = '/${data.results[i].id}'">
            <img src="${img_url}${data.results[i].backdrop_path}" alt="">
            <p class="movie-title">${data.results[i].title}</p>
        </div>
        `;
    }
})
Enter fullscreen mode Exit fullscreen mode

And at the last step of the project. We are fetching similar movies like that from TMDB. And, after getting the data we are making only 16 cards. This is very similar to what we did for creating card in home.js.

Output

Capture-4

We are done.

So, that's it. I hope you understood each and everything. If you have doubt or I missed some thing let me know in the comments.

Articles you may found Useful

  1. Infinte CSS loader
  2. Best CSS Effect
  3. Wave Button Hover Effect
  4. Youtube API - Youtube Clone
  5. Gradient Checkbox

I really appreciate if you can subscribe my youtube channel. I create awesome web contents. Subscribe

Source Code

Thanks For reading.

Discussion (7)

Collapse
dev_sky profile image
Sky • Edited

Followed the Whole thing, very well done. However there are some things that were not explained enough and had to force me to look at your source code for the solution.

  • When explaining about taking or commenting a piece of code out, it's good practice to show the what that snippet would look like in the end.

  • you didn't explain how or where to get the images used in this example
  • There was also some small typos but it helps to practice debugging so i consider that a plus imo lol.

    Other than that, a great project that helped me practice API fetching and manipulating the DOM more with JS.

    Keep it the good work.

    Collapse
    kasunkalanamith profile image
    kasunKalanamith

    Awesome 👍💯

    Collapse
    briannaxrene profile image
    briannaxrene

    This is very cool, I'm bookmarking it for later to get a full read-through!

    Collapse
    elias89 profile image
    Elias • Edited

    I've seen several posts about people trying to create Youtube's UI clones, Facebook's IU clones, Twitter's UI clone.. what's the point?

    Collapse
    kunaal438 profile image
    Modern Web Author

    These projects are just for practice purpose

    Collapse
    esger profile image
    Esger Jellema

    HMTL ??

    Collapse
    kunaal438 profile image
    Modern Web Author

    Oh! My bad I misspelled it. It is HTML.