66

I'm going to import this d3gauge.js file into one of my angular2 component, memmon.component.ts file.

import '../../../../js/d3gauge.js';
export class MemMonComponent {
    createMemGauge() {
        new drawGauge(this.opt);  //drawGauge() is a function inside d3gauge.js
    }
}

and in the corresponding template file, add

<script src="../../../../js/d3gauge.js"></script>

But it doesn't work, drawGaugecan't be found.

So,

  1. what're correct steps to import an external js file to angular2?
  2. since I'm using webpack, is it possible to do it in webpack? I refer to this question , the webpack solution there doesn't work for me as a result of .ensure can't be resolved.
Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
Bing Lu
  • 3,232
  • 7
  • 30
  • 38

9 Answers9

81

Ideally you need to have .d.ts file for typings to let Linting work.

But It seems that d3gauge doesn't have one, you can Ask the developers to provide and hope they will listen.


Alternatively, you can solve this specific issue by doing this

declare var drawGauge: any;

import '../../../../js/d3gauge.js';
export class MemMonComponent {
    createMemGauge() {
        new drawGauge(this.opt);  //drawGauge() is a function inside d3gauge.js
    }
}

If you use it in multiple files, you can create a d3gauage.d.ts file with the content below

declare var drawGauge: any;

and reference it in your boot.ts (bootstrap) file at the top, like this

///<reference path="../path/to/d3gauage.d.ts"/>
Ankit Singh
  • 24,525
  • 11
  • 66
  • 89
  • 1
    Thanks. One more question, when will the `declare var drawGauge: any;` be referenced, at the moment of transpile this ts file? Or, put it in another way, when `new drawGauge(this.opt)` , how does the compiler know the `drawGauge()` is actually in `d3gauge.js`? – Bing Lu May 07 '16 at 04:56
  • Yes, on transpile, it has to know that there is/ or will be something named `d3gauge`. In second question, it doesn't, `d3gauge.js` assigns it to a `global` variable in the `dom` and that is from where it's being called on runtime. – Ankit Singh May 07 '16 at 05:05
  • I got `ReferenceError: drawGauge is not defined`. Is it because I'm using webpack? – Bing Lu May 07 '16 at 15:08
  • 1
    just put `` in your `index.html` only, nowhere else, webpack solution probably doesn't work because of wrong path, but i don't know anything about `webpack` – Ankit Singh May 07 '16 at 16:00
  • 1
    @BingLu Hey man, did you get the solution working for you? I still got the `EXCEPTION: Uncaught (in promise): Error: Error in someComponent` saying that the declared variable `is not defined` and could not find a solution so far. – Mr.Moe Sep 26 '16 at 10:18
  • do you need to declare a variable for every function that you use in a particular js file? that can get crazy when there are a lot of functions. – Subbu Jun 01 '20 at 08:09
  • what is boot.ts did you mean app.component.ts also i don't how to add /// in app.component.ts – Mohammed Nov 04 '21 at 04:31
56

After wasting a lot of time in finding its solution, I've found one. For your convenience I've used the complete code that you can replace your whole file with.

This is a general answer. Let's say you want to import a file named testjs.js into your angular 2 component. Create testjs.js in your assets folder:

assets > testjs.js

function test(){
    alert('TestingFunction')
}

include testjs.js in your index.html

index.html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Project1</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">

  <script src="./assets/testjs.js"></script>

</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

In your app.component.ts or in any component.ts file where you want to call this js declare a variable and call the function like below:

app.component.ts

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

declare var test: any;


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

export class AppComponent {
  title = 'app works!';


  f(){
    new test();
  }
}

Finally in your app.component.html test the function

app.component.html

<h1>
  <button (click)='f()'>Test</button>
</h1>
Muhammad Rehan Qadri
  • 6,824
  • 1
  • 17
  • 18
  • 1
    do we need to declare the function name on component, what if i have many functions do I need to declare all? Also its not working i am getting these errors "ERROR ReferenceError: test is not defined" and "Refused to execute script from 'http://localhost:4200/assets/custom.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled." – Sunil Chaudhary May 25 '18 at 05:37
15

Instead of including your js file extension in index.html, you can include it in .angular-cli-json file.

These are the steps I followed to get this working:

  1. First include your external js file in assets/js
  2. In .angular-cli.json - add the file path under scripts: [../app/assets/js/test.js]
  3. In the component where you want to use the functions of the js file.

Declare at the top where you want to import the files as

declare const Test:any;

After this you can access its functions as for example Test.add()

Howdy
  • 557
  • 7
  • 12
Sitaram
  • 428
  • 9
  • 12
  • Hi, can you tell me where to put the part "Declare const Test:any;" ? Inside the component? I tried to put it inside the export class, and also before the "export class...." but it didn't work. – Vladimir Despotovic Aug 07 '18 at 13:21
  • In your app.component.ts or in any component.ts file where you want to call the method of Test, just add "Declare const Test:any" at the top where you import other dependencies of that component. – Sitaram Aug 09 '18 at 07:05
  • `declare` not `Declare` – Jnr May 15 '19 at 17:17
6

The following approach worked in Angular 5 CLI.

For sake of simplicity, I used similar d3gauge.js demo created and provided by oliverbinns - which you may easily find on Github.

So first, I simply created a new folder named externalJS on same level as the assets folder. I then copied the 2 following .js files.

  • d3.v3.min.js
  • d3gauge.js

I then made sure to declare both linked directives in main index.html

<script src="./externalJS/d3.v3.min.js"></script>
<script src="./externalJS/d3gauge.js"></script>

I then added a similar code in a gauge.component.ts component as followed:

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

declare var d3gauge:any; <----- !
declare var drawGauge: any; <-----!

@Component({
  selector: 'app-gauge',
  templateUrl: './gauge.component.html'
})

export class GaugeComponent implements OnInit {
   constructor() { }

   ngOnInit() {
      this.createD3Gauge();
   }

   createD3Gauge() { 
      let gauges = []
      document.addEventListener("DOMContentLoaded", function (event) {      
      let opt = {
         gaugeRadius: 160,
         minVal: 0,
         maxVal: 100,
         needleVal: Math.round(30),
         tickSpaceMinVal: 1,
         tickSpaceMajVal: 10,
         divID: "gaugeBox",
         gaugeUnits: "%"
    } 

    gauges[0] = new drawGauge(opt);
    });
 }

}

and finally, I simply added a div in corresponding gauge.component.html

<div id="gaugeBox"></div>

et voilà ! :)

enter image description here

PeteZaria
  • 302
  • 3
  • 9
4

Here is a simple way i did it in my project.

lets say you need to use clipboard.min.js and for the sake of the example lets say that inside clipboard.min.js there is a function that called test2().

in order to use test2() function you need:

  1. make a reference to the .js file inside you index.html.
  2. import clipboard.min.js to your component.
  3. declare a variable that will use you to call the function.

here are only the relevant parts from my project (see the comments):

index.html:

<!DOCTYPE html>
<html>
<head>
    <title>Angular QuickStart</title>
    <base href="/src/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfill(s) for older browsers -->
    <script src="/node_modules/core-js/client/shim.min.js"></script>


    <script src="/node_modules/zone.js/dist/zone.js"></script>
    <script src="/node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
        System.import('main.js').catch(function (err) { console.error(err); });
    </script>

    <!-- ************ HERE IS THE REFERENCE TO clipboard.min.js -->
    <script src="app/txtzone/clipboard.min.js"></script>
</head>

<body>
    <my-app>Loading AppComponent content here ...</my-app>
</body>
</html>

app.component.ts:

import '../txtzone/clipboard.min.js';
declare var test2: any; // variable as the name of the function inside clipboard.min.js

@Component({
    selector: 'txt-zone',
    templateUrl: 'app/txtzone/Txtzone.component.html',
    styleUrls: ['app/txtzone/TxtZone.css'],
})



export class TxtZoneComponent implements AfterViewInit {

    // call test2
    callTest2()
    {   
        new test2(); // the javascript function will execute
    }

}
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52
3

For .js files that expose more than one variable (unlike drawGauge), a better solution would be to set the Typescript compiler to process .js files.

In your tsconfig.json, set allowJs option to true:

"compilerOptions": {
     ...
    "allowJs": true,
     ...
}

Otherwise, you'll have to declare each and every variable in either your component.ts or d.ts.

noamyg
  • 2,747
  • 1
  • 23
  • 44
2

You can also try this:

import * as drawGauge from '../../../../js/d3gauge.js';

and just new drawGauge(this.opt); in your ts-code. This solution works in project with angular-cli embedded into laravel on which I currently working on. In my case I try to import poliglot library (btw: very good for translations) from node_modules:

import * as Polyglot from '../../../node_modules/node-polyglot/build/polyglot.min.js';
...
export class Lang 
{
    constructor() {

        this.polyglot = new Polyglot({ locale: 'en' });
        ...
    }
    ...
}

This solution is good because i don't need to COPY any files from node_modules :) .

UPDATE

You can also look on this LIST of ways how to include libs in angular.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
1

1) First Insert JS file path in an index.html file :

<script src="assets/video.js" type="text/javascript"></script>

2) Import JS file and declare the variable in component.ts :

  • import './../../../assets/video.js';
  • declare var RunPlayer: any;

    NOTE: Variable name should be same as the name of a function in js file

3) Call the js method in the component

ngAfterViewInit(){

    setTimeout(() => {
        new RunPlayer();
    });

}
Dmitriy Fialkovskiy
  • 3,065
  • 8
  • 32
  • 47
1

Let's say you have added a file "xyz.js" under assets/js folder in some Angular project in Visual-Studio, then the easiest way to include that file is to add it to .angular-cli.json

"scripts": [ "assets/js/xyz.js" ],

You should be able to use this JS file's functionality in your component or .ts files.

Stphane
  • 3,368
  • 5
  • 32
  • 47
Anuj Vohra
  • 11
  • 1
  • 3