javascriptangulartypescriptdom-eventsexternal-js

Calling function triggered by event from an external JS file in angular component


I am trying to convert a webpage designed by JS, HTML, CSS into an angular project. I have included the JS file in index.html as given below

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Sample</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body class="">
<app-root></app-root>

<script type="text/javascript" src="assets/scripts/sample.js"></script>
</body>
</html>

sample.js

if (document.getElementById("fixedHeader")) {
    window.onscroll = function () { fixedHeader(); };
    var header = document.getElementById("fixedHeader");
    var fixed = header.offsetTop;
} 
function fixedHeader() {
    if (window.pageYOffset > fixed) {
        header.classList.add("fixed-active-lob");
        $('body').addClass("fixed-nav");
    } else {
        header.classList.remove("fixed-active-lob");
        $('body').removeClass("fixed-nav");
    }
}

current.component.html

<div class="gb-nav gn">
    <div id="fixedHeader" class="header">....
    </div>
</div>

sample.css File included in styles.css having

.gb-nav.gn .fixed-active-lob {
    position: fixed;
    top: 0;
    width: 100%;
    z-index: 999999;
    -webkit-box-shadow: 0px 10px 15px -1px rgba(0,0,0,0.45);
    -moz-box-shadow: 0px 10px 15px -1px rgba(0,0,0,0.45);
    box-shadow: 0px 10px 15px -1px rgba(0,0,0,0.45);
}
body.fixed-nav{
    padding-top:56px
}

I was not able to trigger the function from sample.js in angular component. However I was able to reap the desired result by defining the same function again in the

current.component.ts as:

@HostListener('window:scroll', ['$event'])
    scrollHandler(event: any) {
    console.log("Scroll event", event);
    this.fixedHeader();
    }
fixedHeader() {
    var header = document.getElementById("fixedHeader");
    var fixed: number = 0;
    if (header?.offsetTop != undefined) {
      fixed = header?.offsetTop;
    } else {
      fixed = 0;
    }
    if (window.pageYOffset > fixed) {
        header?.classList.add("fixed-active-lob");
        $('body').addClass("fixed-nav");
    } else {
        header?.classList.remove("fixed-active-lob");
        $('body').removeClass("fixed-nav");
    }
}

But I would like to use the function from the JS file instead of redoing it in the ts file, please help.


Solution

  • First, modify sample.js such that it exports fixedHeader like so

    if (document.getElementById("fixedHeader")) {
      window.onscroll = function () { fixedHeader(); };
      var header = document.getElementById("fixedHeader");
      var fixed = header.offsetTop;
    }  
    
    export function fixedHeader() {
      if (window.pageYOffset > fixed) {
        header.classList.add("fixed-active-lob");
        $('body').addClass("fixed-nav");
      } else {
        header.classList.remove("fixed-active-lob");
        $('body').removeClass("fixed-nav");
      }
    } 
    

    With this adjustment, we've made sample.js into a module, with a single export named fixedHeader, and have thus enabled other modules, such as our current.component.ts, to consume it via the standard, explicit, and canonical method for sharing code in JavaScript: Modules.

    Next, set "allowJs": true in your project's tsconfig.json, to inform TypeScript that our project includes a mix of both TypeScript and JavaScript source files.

    Finally, import the fixedHeader function we've exported from sample.js directly into current.component.ts, remove the now redundant method from the Angular component class, and call the imported function as follows

     import {Component, HostListener} from '@angular/core';
    
     import {fixedHeader} from '../assets/scripts/sample.js';
    
     @Component({
       // Angular boilerplate and ceremony
     })
     export class CurrentComponent { // or whatever it is actually called
       @HostListener('window:scroll', ['$event'])
       scrollHandler(event: Event) {
         console.log("Scroll event", event);
      
         fixedHeader();
      }
    }
    

    Finally, remove the script tag that originally loaded sample.js from index.html.

    Note: adjust import path above as needed based on the actual location of the files relative to one another.