Problem referencing two JavaScript files within Angular component - javascript

I have two Javascript files like below, a parent which defines a method and a child which calls the method from the parent:
parent.js
function HelloWorld() {
alert('HelloWorld');
}
child.js
HelloWorld();
In my Angular component I am referencing the script like so:
import { Component } from '#angular/core';
import 'src/app/parent.js';
import 'src/app/child.js';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'my-dream-app';
}
When I run the application, I receive an error in the console stating:
Uncaught ReferenceError: HelloWorld is not defined
If I call HelloWorld() from within Parent.js it works fine; but it doesn't seem like Angular likes have two separate JS files. When I do this in just a pure HTML file and include both scripts in the this works just fine. What am I missing about my Angular component that would prevent what I am trying to do?

That's because typescript is compiling everything to closed annonymous functions. So your parent.js will be compiled to
(function(module, exports) {
function helloWorld () {
console.log('hello')
}
/***/ }),
And you can't have access to that scope.
But if you do a export function helloWorld() {...} and then import it into child.js like:
child.js
import {helloWorld} from '../path/to/child.js'
helloWorld()
OR
import * as parent from './parent.js';
parent.helloWorld()
then child will have access to that function.

Related

Import js script to Angular from URL

i am building an app with angular but found a problem I don't know how to solve.
I need to import a js script and it has to be imported from the internet. (because these are their rules, so that they can do hotfixes)
The problem is, when I import the script into my index.html I can only use it in js files not in the typescript files. How can i use the libary in my ts files?
I can't install it via npm and i also can't download the file and add it to my project folder.
The libary is the airconsole API (https://developers.airconsole.com/#!/api)
Thanks for your help
it's only add in your component declare var AirConsole to use it, a fool Component
import { Component, VERSION } from '#angular/core';
declare var AirConsole //<--this is the "magic"
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
airConsole=new AirConsole() //<--now you can use airConsole in your component
}
Update Well, generally we can use a service to mannage the airConsole, this allow us that all components that inject the service can use the functions,variables,...
Disclamer: I don't know about "AirConsole", so I imagine control it like we can control others .js like Cordova)
As we need that Angular know when a function is executed in .js, our service can be like
import { Injectable,NgZone } from '#angular/core';
declare var AirConsole;
#Injectable({
providedIn: 'root',
})
export class AirConsoleService implements OnInit {
airConsole=new AirConsole()
message:Subject=new Subject<any>();
constructor(private ngZone: NgZone) { }
ngOnInit(){
this.airconsole.onMessage = (from, data)=>{
this.ngZone.run(() => {
this.message.next({from:from,data:data})
});
})
}
message(device:any,message:any){
this.ngZone.run(() => {
this.airConsole.message(device,message);
});
}
}
So, e.g. you can subscribe to airConsoleService.message

External .js file in an Angular 8 project

I'm trying to call a function in a .js file from an Angular component, but I get the error "ERROR ReferenceError: myTest is not defined at TechnologiesComponent.onClick".
I have followed the steps described here, so I have created a file called custom.js in my src folder.
The file contains the following:
function myTest() {
alert('Welcome to custom js');
}
$(function() {
alert('Hello, custom js');
});
I have added the script in the scripts array in my angular.json, like so:
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": ["src/custom.js"]
},
The .ts file where I want to use the .js file looks like this:
import { Component } from '#angular/core';
declare const myTest: any;
#Component({
selector: 'app-technologies',
templateUrl: './technologies.component.html',
styleUrls: ['./technologies.component.css']
})
export class TechnologiesComponent {
onClick() {
myTest();
}
}
A button is added to my template:
Click Me
When the button is pressed, the error "ERROR ReferenceError: myTest is not defined at TechnologiesComponent.onClick" is thrown. Why?
declare your function as a variable (in JS both are same)
custom.js
myTest = function(){
alert('Welcome to custom js');
}
also, verify if the script is getting imported in the final build
you may need to re-build if you are using ng serve
If you want to use code from .js files in .ts files you should use export and import.
Example with your project:
custom.js
export function myTest() {
alert('Welcome to custom js');
}
app.component.ts
import {Component} from '#angular/core';
import * as custom from 'src/custom.js';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
onClick() {
custom.myTest();
}
}
take note of line import * as custom from 'src/custom.js';
It's one of the best ways to import smth from non-ts files.
Structure:
I am using angular 10 and trying to access plane js file and It's not allow to change js file
i.e. can't able to add export in it
add your js files in angular.json
I want to access print() function in angular from myJs.js and which is like
// MyJS.js
function print(a){
cosole.log(a +" Code from JS");
}
app.component.ts
import {Component} from '#angular/core';
// following variable name and function name in js file should be same
declare var print: any;
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
onClick() {
print('Yes');
}
}
and fire ng serve again
( If still not work for you then try to put your js file in assets folder and change the path in angular.json)

Angular 5 - Loading Script After View Is Loaded

I have a legacy script that I need to include in my angular application.
The thing about this script is that it relates to a specific component, and it has to be loaded only after the view of the component is loaded.
As for today, I succeeded to include it on OnInit function but sometimes (not always for some reason) the CLI throws an error about it.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-player-page',
templateUrl: './player-page.component.html',
styleUrls: ['./player-page.component.scss']
})
export class PlayerPageComponent implements OnInit {
public itemId: string;
constructor() {}
ngOnInit() {
//We loading the player srcript on after view is loaded
require('assets/scripts/player/player.js');
}
}
The script assumes that elements in the UI exists and it searches them by the id.
When adding it on top of the page, it doesn't work.
What is the best way to achieve the desired behavior?
There are multiple solutions to this issue.
declare the require const on top of your component
declare const require: any;
import { Component, OnInit } from '#angular/core';
#Component({})
...
use the dynamic import() function from typescript
ngAfterViewInit() {
//We loading the player script on after view is loaded
import('assets/scripts/player/player.js');
}
change the library to only start running after you call a function from the component, this way you can add it to the scripts array of your angular.json

Angular4/5 dependency injection docs not working

https://angular.io/guide/architecture#services
I'm following the docs on angular.io to inject dependencies like services, etc. I did everything they said and when I try to run it, the console keeps telling me:
Uncaught ReferenceError: LedgerService is not defined
I am doing nothing crazy except creating a simple component with a service where both constructors have console.log commands (constructors in both the component and service). I've done everything Angular says to do in their 2 paragraphs that details this feature of Angular.
The component itself is being injected into the main app module (with the service being injected into the component) and both the component and service were created with the Angular CLI. So there isn't much I've even done at all minus trying to inject the service. So I'm not sure where it is going wrong but it is definitely not working and just shows a blank page (when it previously had basic content by default).
I created both units, tried to specify providers in both the app.module and the component.ts file and neither works and yields the same error--when Angular claims either could work. I've also specified it as a private service within the constructor of the component.ts file.
Everything I've seen relating to this is always for Angular 1 or 2. Neither of which are even remotely similar to Angular 4/5.
If you really want to see this code, fine but it's literally just framework and nothing else:
bookkeeper.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-bookkeeper',
templateUrl: './bookkeeper.component.html',
styleUrls: ['./bookkeeper.component.css'],
providers: [LedgerServiceService]
})
export class BookkeeperComponent implements OnInit {
constructor(private service: LedgerServiceService) { }
ngOnInit() {
console.log("Ledger component works!");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { InterfaceComponent } from './interface/interface.component';
import { BookkeeperComponent } from './bookkeeper/bookkeeper.component';
#NgModule({
declarations: [
AppComponent,
InterfaceComponent,
BookkeeperComponent
],
imports: [
BrowserModule
],
providers: [
LedgerServiceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
ledger-service.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LedgerServiceService {
constructor() {
console.log("wtf");
}
}
LedgerService is actually called LedgerServiceService because I initially created LedgerService manually and then tried to use the AngularCLI to generate a service and named it LedgerService and it created a service called LedgerServiceService. Naming is not what is wrong. I only initially called it simply LedgerService because I figured it would be confusing.
Your examples are missing the import.
Anywhere we use a custom type, we also need to import that type.
For that reason, in both the module and component you will need to add:
import { LedgerServiceService } from './your-path-here'
You can see this in the examples they give on https://angular.io/guide/dependency-injection

How to load script file from component html?

Basically I wanted to load component html specific script file, so that script I'm going to put script file reference inside component html itself, I'm seeing that inner script file has been ignored while rendering component html on page.
Component
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: 'test.html'
})
export class AppComponent { }
test.html
<div>
<h1>My First Angular 2 App</h1>
</div>
<script src="test.js"></script>
Above is my code what I tried & I already have test.js there in place.
Plunkr Here
Is there any way to load component specific javascript file with component OR with its html?
Working Plunker
Security
It looks like Angular takes out script tags from Html templates.
From the Angular Docs:
It removes the <script> tag but keeps safe content, such as the text content of the <script> tag
Angular provides methods to bypass security, but for your use case it looks like a service would be helpful.
Services
The preferred way to include your own custom script in your component from a separate dedicated file would be to create a service.
I took the code from your Plunker's script.js file and put it into a service like this:
// File: app/test.service.ts
import { Injectable } from '#angular/core';
#Injectable()
export class TestService {
testFunction() {
console.log('Test');
}
}
Then I imported the service and called the custom code like this:
// File: app/app.component.ts
import { Component, OnInit } from '#angular/core';
import { TestService } from './test.service';
#Component({
selector: 'my-app',
templateUrl: 'test.html',
providers: [TestService]
})
export class AppComponent implements OnInit {
constructor(private testService: TestService) {}
ngOnInit() {
this.testService.testFunction();
}
}
Lifecycle hooks
If you want to call your service's custom code at a specific point you can take advantage of lifecycle hooks. For example you can call your code using the ngAfterViewInit() instead of ngOnInit() if you want to wait until the view has loaded.

Categories