How can I convert a normal javascript code to angular component specific code which uses event handling

1k views Asked by At

I am trying to convert a javascript code that handles events related to tabs on a page, i.e. whenever a user clicks on a particular tab a red border should appear underneath it (Just like how the Netflix landing page website works). But I am getting an error when pasting the same code in my landing page component typescript file. I am providing the landing.component.html, landing.component.css, landing.component.ts and the javascript file (main.js) which I want to convert.

landing.component.html

<header class="showcase">
<div class="showcase-top">
    <img src="../../assets/logo.png" alt="Netflix">
    <a href="#" class="btn btn-rounded">Sign In</a>
</div>
<div class="showcase-content">
    <h1>See what's next</h1>
    <p>Watch anywhere. Cancel anytime</p>
    <a href="#" class="btn btn-xl">
        Watch Free for 30 Days <i class="fas fa-chevron-right btn-icon"></i>
    </a>
</div>
</header>
<section class="tabs">
<div class="container-fluid">
    <div id="tab-1" class="tab-item tab-border">
        <i class="fas fa-door-open fa-3x"></i>
        <p class="hide-sm">Cancel Anytime</p>
    </div>
    <div id="tab-2" class="tab-item">
        <i class="fas fa-tablet-alt fa-3x"></i>
        <p class="hide-sm">Watch Anywhere</p>
    </div>
    <div id="tab-3" class="tab-item">
        <i class="fas fa-tags fa-3x"></i>
        <p class="hide-sm">Pick your price</p>
    </div>
</div>
</section>
<section class="tab-content">
<div class="container-fluid">
    <!-- Tab 1 Content -->
    <div id="tab-1-content" class="tab-content-item show">
        <div class="tab-1-content-inner">
            <div>
                <p class="text-lg">
                   If you decide Netflix isn't for you- no problem. 
                </p>
                <a href="#" class="btn btn-lg">Watch Free For 30 Days</a>
            </div>
            <img src="../../assets/tab-content-1.png" alt="">
        </div>
    </div>

    <!-- Tab 2 Content -->
    <div id="tab-2-content" class="tab-content-item">
        <div class="tab-2-content-top">
            <p class="text-lg">
                If you decide Netflix isn't for you.
            </p>
            <a href="#" class="btn btn-lg">Watch Free For 30 Days</a>
        </div>
        <div class="tab-2-content-bottom">
            <div>
                <img src="../../assets/tab-content-2-1.png" alt="">
                <p class="text-md">Watch on your TV</p>
                <p class="text-dark">Smart TVs, PlayStation, Xbox, Chromecast, Apple TV, Blu-ray players and more.</p>
            </div>
            <div>
                <img src="../../assets/tab-content-2-2.png" alt="">
                <p class="text-md">Watch instantly or download for later</p>
                <p class="text-dark">Available on phone and tablet, wherever you go.</p>
            </div>
            <div>
                <img src="../../assets/tab-content-2-3.png" alt="">
                <p class="text-md">Use any computer</p>
                <p class="text-dark">Watch right on Netflix.com</p>
            </div>
        </div>
    </div>

    <!-- Tab 3 Content -->
    <div id="tab-3-content" class="tab-content-item">
        <div class="text-center">
            <p class="text-lg">Choose one plan and watch everything on Netflix</p>
            <a href="#" class="btn btn-lg">Watch Free For 30 Days</a>
        </div>
        <table class="table">
            <thead>
                <tr>
                    <th></th>
                    <th>Basic</th>
                    <th>Standard</th>
                    <th>Premium</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Monthly price after free month ends on 6/19/20</td>
                    <td>$8.99</td>
                    <td>$12.99</td>
                    <td>$15.99</td>
                </tr>
                <tr>
                    <td>HD Available</td>
                    <td><i class="fas fa-times"></i></td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
                <tr>
                    <td>Ultra HD Available</td>
                    <td><i class="fas fa-times"></i></td>
                    <td><i class="fas fa-times"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
                <tr>
                    <td>Screens you can watch on at the same time</td>
                    <td>1</td>
                    <td>2</td>
                    <td>4</td>
                </tr>
                <tr>
                    <td>Watch on your laptop, TV, phone and tablet</td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
                <tr>
                    <td>Unlimited movies and TV shows</td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
                <tr>
                    <td>Cancel anytime</td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
                <tr>
                    <td>First month free</td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                    <td><i class="fas fa-check"></i></td>
                </tr>
            </tbody>
        </table>
    </div>
</div>
</section>

<footer class="footer">
<p>Questions? Call 1-866-576-7172</p>
<div class="footer-cols">
    <ul>
        <li><a href="#">FAQ</a></li>
        <li><a href="#">Investor Relations</a></li>
        <li><a href="#">Ways To Watch</a></li>
        <li><a href="#">Corporate Information</a></li>
        <li><a href="#">Netflix Originals</a></li>
    </ul>
    <ul>
        <li><a href="#">Help Center</a></li>
        <li><a href="#">Jobs</a></li>
        <li><a href="#">Terms Of Use</a></li>
        <li><a href="#">Contact Us</a></li>
    </ul>
    <ul>
        <li><a href="#">Account</a></li>
        <li><a href="#">Redeem Gift Cards</a></li>
        <li><a href="#">Privacy</a></li>
        <li><a href="#">Speed Test</a></li>
    </ul>
    <ul>
        <li><a href="#">Media Center</a></li>
        <li><a href="#">Buy Gift Cards</a></li>
        <li><a href="#">Cookie Preferences</a></li>
        <li><a href="#">Legal Notices</a></li>
    </ul>
 </div>
</footer>

loading.component.css

.showcase{
width: 100% !important;
height: 93vh !important;
position: relative !important;
background: url('../../assets/background.jpg') no-repeat center center/cover !important;
}

.showcase::after{
content: '' !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 1 !important;
background: rgba(0,0,0,0.6) !important;
box-shadow: inset 120px 100px 250px #000000, inset -120px -100px 250px #000000 !important;
}

.showcase-top{
position: relative !important;
z-index: 2 !important;
height: 90px !important;
}

.showcase-top img{
width: 170px !important;
position: absolute !important;
top: 50% !important;
left: 50% !important;
transform: translate(-50%, -50%) !important;
}

.showcase-top a{
position: absolute !important;
top: 50% !important;
right: 0 !important;
transform: translate(-50%, -50%) !important;
}

.showcase-content{
position: relative !important;
z-index: 2 !important;
margin: auto !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
text-align: center !important;
margin-top: 9rem !important;
}

.showcase-content h1{
font-weight: 700 !important;
font-size: 5.2rem !important;
line-height: 1.1 !important;
margin: 0 0 2rem !important;
}

.showcase-content p{
text-transform: uppercase !important;
color: #fff !important;
font-weight: 400 !important;
font-size: 1.9rem !important;
line-height: 1.25 !important;
margin: 0 0 2rem !important;
}

/* Tabs */
.tabs{
background: var(--dark-color) !important;
padding-top: 1rem !important;
border-bottom: 3px solid #3d3d3d !important;
}

.tabs .container-fluid{
display: grid !important;
grid-template-columns: repeat(3, 1fr) !important;
grid-gap: 1rem !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
}

.tabs p{
font-size: 1.2rem !important;
padding-top: 0.5rem !important;
}

.tabs .container-fluid > div{
padding: 1.5rem 0 !important;
}

.tabs .container-fluid > div:hover{
color: #fff !important;
cursor: pointer !important;
}

.tab-border{
border-bottom: var(--primary-color) 4px solid !important;
}

/* Tab Content */
.tab-content{
padding: 3rem 0 !important;
background: #000 !important;
color: #fff !important;
}

/* Hide Content Initially */
#tab-1-content,
#tab-2-content,
#tab-3-content{
display: none !important;
}

.tab-content-item .show{
display: block !important;
}

#tab-1-content .tab-1-content-inner{
display: grid !important;
grid-template-columns: repeat(2, 1fr) !important;
grid-gap: 2rem !important;
align-items: center !important;
justify-content: center !important;
}

#tab-2-content .tab-2-content-top{
display: grid !important;
grid-template-columns: 2fr 1fr !important;
grid-gap: 1rem !important;
justify-content: center !important;
align-items: center !important;
}

#tab-2-content .tab-2-content-bottom{
margin-top: 2rem !important;
display: grid !important;
grid-template-columns: repeat(3, 1fr) !important;
grid-gap: 2rem !important;
justify-content: center !important;
align-items: center !important;
text-align: center !important;
}

.table{
width: 100% !important;
margin-top: 2rem !important;
border-collapse: collapse !important;
border-spacing: 0 !important;
}

.table thead th{
text-transform: uppercase !important;
padding: 0.8rem !important;
color: #fff !important;
border: none !important;
}

.table tbody tr td{
color: #999 !important;
padding: 0.8rem 1.2rem !important;
text-align: center !important;
border: none !important;
}

.table tbody tr td:first-child{
text-align: left !important;
}

.table tbody tr:nth-child(odd){
background: #222 !important;
}

/* Footer */
.footer{
max-width: 75% !important;
margin: 1rem auto !important;
overflow: auto !important;
}

.footer, .footer a{
color: #999 !important;
font-size: 0.9rem !important;
}

.footer p{
margin-bottom: 1.5rem !important;
}

.footer .footer-cols{
display: grid !important;
grid-template-columns: repeat(4, 1fr) !important;
grid-gap: 2rem !important;
}

.footer li{
line-height: 1.9 !important;
}

/* Container */
.container-fluid{
max-width: 70% !important;
margin: auto !important;
overflow: hidden !important;
padding: 0 2rem !important;
}

/* Text Styles */
.text-xl{
font-size: 2rem !important;
margin-bottom: 1rem !important;
}

.text-lg{
font-size: 1.8rem !important;
margin-bottom: 1rem !important;
}

.text-md{
font-size: 1.5rem !important;
margin-bottom: 1rem !important;
}

.text-center{
text-align: center !important;
}

.text-dark{
color: #999 !important;
}

/* Buttons */
.btn{
display: inline-block !important;
background: var(--primary-color) !important;
color: #fff !important;
padding: 0.4rem 1.3rem !important;
font-size: 1rem !important;
text-align: center !important;
border: none !important;
cursor: pointer !important;
margin-right: 0.5rem !important;
outline: none !important;
box-shadow: 0 1px 0 rgba(0,0,0,0.45) !important;
border-radius: 2px !important;
}

.btn:hover{
opacity: 0.9 !important;
}

.btn-rounded{
border-radius: 5px !important;
}

.btn-xl{
font-size: 2rem !important;
padding: 1.5rem 2.1rem !important;
text-transform: uppercase !important;
}

.btn-lg{
font-size: 1rem !important;
padding: 0.8rem 1.3rem !important;
text-transform: uppercase !important;
}


@media(max-width: 960px){
.showcase{
    height: 70vh !important;
}

.hide-sm{
    display: none !important;
}

.showcase-top img{
    top: 30% !important;
    left: 5% !important;
    transform: translate(0) !important;
}

.showcase-content h1{
    font-size: 3.7rem !important;
    line-height: 1 !important;
}

.showcase-content p{
    font-size: 1.5rem !important;
}

.footer .footer-cols{
    grid-template-columns: repeat(2, 1fr) !important;
}

.btn-xl{
    font-size: 1.5rem !important;
    padding: 1.4rem 2rem !important;
}

.text-xl{
    font-size: 1.5rem !important;
}

.text-lg{
    font-size: 1.3rem !important;
}

.text-md{
    font-size: 1rem !important;
}
}

@media(max-width: 700px){
.showcase::after{
    box-shadow: inset 80px 80px 250px #000000, inset -80px -80px 250px #000000 !important;
}

#tab-1-content .tab-1-content-inner{
    grid-template-columns: 1fr !important;
    text-align: center !important;        
}

#tab-2-content .tab-2-content-top{
    display: block !important;
    text-align: center !important;
}

#tab-2-content .tab-2-content-bottom{
    grid-template-columns: 1fr !important;
}
}

landing.component.ts (I am getting the error in this file)

import { Component, OnInit } from '@angular/core';

const tabItems = document.querySelectorAll('.tab-item');
const tabContentItems = document.querySelectorAll('.tab-content-item');

@Component({
  selector: 'app-landing',
  templateUrl: './landing.component.html',
  styleUrls: ['./landing.component.css']
})

export class LandingComponent implements OnInit {

constructor() {}

ngOnInit() {}

// Select tab content item
function selectItem(){
removeBorder();
// Add border to current tab
this.classList.add('tab-border');
}

function removeBorder(){
tabItems.forEach(item => item.classList.remove('tab-border'));
}

// Listen for tab click
tabItems.forEach(item => item.addEventListener('click', selectItem));

}

main.js (This is the code I want in landing.component.ts)

const tabItems = document.querySelectorAll('.tab-item');
const tabContentItems = document.querySelectorAll('.tab-content-item');

// Select tab content item
function selectItem(e){
removeBorder();
// Add border to current tab
this.classList.add('tab-border');
}

function removeBorder(){
tabItems.forEach(item => item.classList.remove('tab-border'));
}

// Listen for tab click
tabItems.forEach(item => item.addEventListener('click', selectItem));

P.S. I have been following a tutorial series to make this. The link is: Build a Netflix Landing Page Clone with HTML, CSS & JS

The source code for the tutorial is in the link: Source Code

Please suggest the corrections to be made in the typescript file

2

There are 2 answers

0
qwerty On BEST ANSWER

You need to use the possibilities of angular,

Look how I did it your landing in angular

What I've done:

In app.component.ts add tabs array, variable activeTabId, and function selectTab():

tabs = [
  {id: 1, title: 'Cancel at any time'},
  {id: 2, title: 'Watch anywhere'},
  {id: 3, title: 'Pick your price'}
];
activeTabId = this.tabs[0].id;

selectTab(tab) {
  this.activeTabId = tab.id;
}

And change Template(HTML), adding tabs array dynamic, and add class, id dynamic.

<section class="tabs">
<div class="container">
    <div class="tab-item" *ngFor="let tab of tabs;" [attr.id]="'tab-'+tab?.id"
        [ngClass]="{'tab-border': activeTabId === tab?.id}" (click)="selectTab(tab)">
        <i class="fas fa-door-open fa-3x"></i>
        <p class="hide-sm">Cancel at any time</p>
    </div>
    <!--
            <div id="tab-2" class="tab-item">
                <i class="fas fa-tablet-alt fa-3x"></i>
                <p class="hide-sm">Watch anywhere</p>
            </div>
            <div id="tab-3" class="tab-item">
                <i class="fas fa-tags fa-3x"></i>
                <p class="hide-sm">Pick your price</p>
            </div>
    -->
</div>

And when clicked selectTab(), in template use NgSwitch, to switch between tabs:

<ng-container [ngSwitch]="activeTabId">
  <div *ngSwitchCase="1" id="tab-1-content">...</div>
  <div *ngSwitchCase="2" id="tab-2-content">...</div>
  <div *ngSwitchCase="3" id="tab-3-content">...</div>
</ng-container>

And the code link stackblitz.com

0
Padmapriya Vishnuvardhan On

There is no need to loop the items and add addEventListener kind of thing in angular. Add the click event in the tab item in html itself like below.

<div id="tab-1" class="tab-item tab-border" (click)="selectItem($event)">
   <i class="fas fa-door-open fa-3x"></i>
   <p class="hide-sm">Cancel Anytime</p>
</div>

And Remove the below lines from your ts file.

// Listen for tab click
tabItems.forEach(item => item.addEventListener('click', selectItem));