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
Related
I´m using Angular 9 to build an application with many modules and components modularized. When I will building this application, I need to exclude one module or component that compilation. I say module or components because I don´t know what is the best way to exclude this functionality that compilation.
For example:
I have two components. comp1.component.ts contains three buttons:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-comp',
templateUrl: './comp1.component.html',
styleUrls: []
})
export class Comp1Component implements OnInit {
title = 'Loaded Component 1.';
constructor() { }
ngOnInit(): void {
}
}
comp2.component.ts contains two buttons:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-comp',
templateUrl: './comp2.component.html',
styleUrls: []
})
export class Comp2Component implements OnInit {
title = 'Loaded Component 2.';
constructor() { }
ngOnInit(): void {
}
}
And the .html is the same for both:
<p>{{title}}</p>
By other way, I have another component, where I want load one of these two components, depending on the environment where I load.
In the environment A, I need load comp1.component.ts and in the environment B, I need load comp2.component.ts. But if I load one of these components, the other component should not included in the build of this application but I don't have any idea to solve this....
Any idea to resolve this problem?
Thanks for watching.
you can do the same as environment file is changed between build targets
"configurations": {
"target-with-component2": {
"fileReplacements": [
{
"replace": "path/to/comp1.component.ts",
"with": "path/to/comp2.component.ts"
}
],
it will replace components just as required in the question
if you use angular-cli build project, you can modify tsconfig.app.json file add same configuration in root element
{
"exclude": [
"src/test.ts",
"src/**/*.spec.ts",
"src/xxx/xxxxx/**/*"
]
}
I want to use jquery and easypiechart js file's functions in typescript.
It doesn't work this way.
How to define these script what i specified in code as typescript ?
index.component.ts
import { Component, OnInit } from '#angular/core';
import * as $ from "../../../../../assets/plugins/jquery/jquery.min.js";
import { easyPieChart } from "../../../../../assets/plugins/easypiechart/jquery.easypiechart.min.js";
// these above 2 js files are defined in angular.json script section
#Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.scss']
})
export class IndexComponent implements OnInit {
constructor() {}
ngOnInit() {
//$(function(){
// $('.easypiechart').easyPieChart();
//});
// How to write this above script as typescript ?????????????????????
}
}
From the above question,it looks like jquery.easypiechart.min.js is the one that you need to use in your angular application as external js.
Put the js under assets folder say /assets/js/jquery.easypiechart.min.js
Goto your projects angular.json file and under scripts node of architect node put as an entry in the array.
"scripts": [
"./node_modules/jquery/dist/jquery.min.js",
"./src/assets/js/jquery.easypiechart.min.js" ]
Now you can refer the external js in any of your projects components
declare var $: any;// referencing jQuery library
#Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.scss']
})
export class IndexComponent implements OnInit {
constructor() {}
ngOnInit() {
$(document).ready(function () {
//accessing easypiechart.min.js.
$('.easypiechart').easyPieChart();
});
}
}
If you have included them in the scripts or index.html, you don't have to import them to the .TS file again
Use declare instead and it should work
What does 'declare' do in 'export declare class Actions'?
Instead of putting it in asset folder you should use it as node_modules dependency
For easy pie chart run this npm i easy-pie-chart --save & for jquery run npm i jquery
Normally you don't want to use jquery in Angular, because it usually implies to modify directly the DOM, which is a bad practice, but there is the way to do it: https://medium.com/all-is-web/angular-5-using-jquery-plugins-5edf4e642969
If you wanna plot a pie chart or other types of charts, you could use ng2-charts instead, it will allow you to use charts.js with Angular and Typescript.
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
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.
I have been using ng-include in angular 1 whenever I had to include a tamplate dynamically in the page.
Now how to acheive this in angular 2. I have tried searching and found these :
https://groups.google.com/forum/#!topic/angular/ROkKDHboWoA ,
https://github.com/angular/angular/issues/2753
can someone explain how to do this in angular2 as the link says ng-include is not included due some security reasons.
Or atleast how to use a veriable in templateUrl property so that the veriable value can be handled on server side to serve the template...
And as you can see in this issue on the Angular repo, most probably we won't get that directive. There has been a long discussion whether we need this directive or not, and if not provided how we can implement it by our self.
I tried to make a simple example of how it can be implemented.
#Component({
selector: 'my-ng-include',
template: '<div #myNgIncludeContent></div>'
})
export class MyNgInclude implements OnInit {
#Input('src')
private templateUrl: string;
#ViewChild('myNgIncludeContent', { read: ViewContainerRef })
protected contentTarget: ViewContainerRef;
constructor(private componentResolver: ComponentResolver) {}
ngOnInit() {
var dynamicComponent = this.createContentComponent(this.templateUrl);
this.componentResolver.resolveComponent(dynamicComponent)
.then((factory: any) => this.contentTarget.createComponent(factory));
}
createContentComponent(templateUrl) {
#Component({
selector: 'my-ng-include-content',
templateUrl: templateUrl,
directives: FORM_DIRECTIVES,
})
class MyNgIncludeContent {}
return MyNgIncludeContent ;
}
}
For a demo check this Plunker.
Actually angular 2 has not featured this in the current build. Also as per the links added, I don't think this feature will be included.
A piece of javascript to dynamically add template using ajax call may be used.
Or possibly in future a dynamic template loader library will be available for use.
As of alpha.46 (and with ES6 JS):
In the parent file import file you wanted to include:
#Component({
selector: 'account'
})
#View({
templateUrl: './folder/containing/template.html'
})
Easy as that.
If you meant to import a component, this is what you do in the parent file:
import ComponentClassName from './folder/with/componentName';
...
#View({
directives: [ComponentClassName]
})
And inside the imported file of the child/component:
Define your ComponentClassName (you may add templateUrlto the #View just as demonstrated at the top).
Don't forget to export default ComponentClassName; at the bottom of the file.
There are not many examples in the official Angular 2 docs, but you stumble across it every once in a while.
As #binariedMe accurately describes, ng-include is off in Angular 2 due to security considerations. The recommended method is to use a custom directive with slightly more programmatical overhead.
Additionally, to prepare your Angular code for 2.0:
myApp.directive('myInclude', function() {
return {
templateUrl: 'mytemplate.html'
};
});
And rather than using ng-include on an element, simply add my-include:
<div my-include></div>
Following #binariedMe and this blog post http://blog.lacolaco.net/post/dynamic-component-creation-in-angular-2/, I was able to construct a solution that may work for you. Using an AJAX call and creating the custom component dynamically from the returned html content should fix this problem in creating a new my-ng-include custom directive.
import {
Component,
Directive,
ComponentFactory,
ComponentMetadata,
ComponentResolver,
Input,
ReflectiveInjector,
ViewContainerRef
} from '#angular/core';
import { Http } from '#angular/http';
export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
return resolver.resolveComponent(decoratedCmp);
}
#Directive({
selector: 'my-ng-include'
})
export class MyNgInclude {
#Input() src: string;
constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver, private http: Http) {
}
ngOnChanges() {
if (!this.src) return;
this.http.get(this.src).toPromise().then((res) => {
const metadata = new ComponentMetadata({
selector: 'dynamic-html',
template: res.text(),
});
createComponentFactory(this.resolver, metadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
});
}
}
Just simply use it as follows:
<my-ng-include [src]="someChangingProperty"></my-ng-include>