I'd like to be able to pass some data\propagate events from a plugin on the page to my Angular 4 app.
More specifically, in my case data\events are generated inside a Silverlight plugin app that is next to the Angular app on the page.
I have the following solution in my mind:
- Create a global JS function which gets called from Silverlight (since this seems to be the simplest way to get data out from Silverlight) when there is a need to talk to Angular side.
- The function, in turn, calls some Angular class method passing data collected from Silverlight.
As an illustration to that (excluding the Silverlight part), we could have the following.
A method as an entry point on the Angular side:
export class SomeAngularClass {
public method(data: any): void {
...
}
}
And somewhere outside the Angular realm, we add a global plain JavaScript function (to be called by Silverlight):
window.somePlainJsFunction = function (data) {
// How to consume SomeAngularClass.method() from here?
}
The question is: how can we call the Angular class methods from a plain JavaScript function?
I'd like to be able to pass some data\propagate events from a plugin on the page to my Angular 4 app.
More specifically, in my case data\events are generated inside a Silverlight plugin app that is next to the Angular app on the page.
I have the following solution in my mind:
- Create a global JS function which gets called from Silverlight (since this seems to be the simplest way to get data out from Silverlight) when there is a need to talk to Angular side.
- The function, in turn, calls some Angular class method passing data collected from Silverlight.
As an illustration to that (excluding the Silverlight part), we could have the following.
A method as an entry point on the Angular side:
export class SomeAngularClass {
public method(data: any): void {
...
}
}
And somewhere outside the Angular realm, we add a global plain JavaScript function (to be called by Silverlight):
window.somePlainJsFunction = function (data) {
// How to consume SomeAngularClass.method() from here?
}
The question is: how can we call the Angular class methods from a plain JavaScript function?
Share Improve this question edited Sep 8, 2017 at 20:18 Alexander Abakumov asked Sep 8, 2017 at 16:25 Alexander AbakumovAlexander Abakumov 14.5k16 gold badges96 silver badges133 bronze badges 19- One way of doing this could be having your JavaScript send a event and then your service (or a angular directive) listen for that event. – Dumpen Commented Sep 8, 2017 at 16:43
- 1 I know that Angular exposes its API through a global JavaScript object - it doesn't. AngularJS did. The actual solution depends on what somePlainJsFunction is and where it's used. Unless there are really good reasons to keep it global, somePlainJsFunction should be defined and called inside Angular application, not in the opposite way. – Estus Flask Commented Sep 8, 2017 at 17:48
- Possible duplicate of How to share service between two modules - @NgModule in angular2? – Aniruddha Das Commented Sep 8, 2017 at 18:47
- @estus: Actually, it does. See, for instance here. – Alexander Abakumov Commented Sep 8, 2017 at 19:02
- 1 I'm aware of this. This happens when Angular is loaded as UMD module in <script>. It won't happen under normal circumstances when an app is written with Typescript and modules. – Estus Flask Commented Sep 8, 2017 at 19:05
4 Answers
Reset to default 11As pointed by @Dumpen, you can use @HostListener to get the custom event dispatched from javascript outside of Angular. If you also want to send parameters, then you can send them by adding them as detail object.
In Javascript:
function dispatch(email, password) {
var event = new CustomEvent('onLogin', {
detail: {
email: email,
password: password
}
})
window.dispatchEvent(event);
}
Then you can call this method on button click.
Now to listen to this dispatched event in Angular, you can create function in Angular component and add @HostListener to it like below:
@HostListener('window:onLogin', ['$event.detail'])
onLogin(detail) {
console.log('login', detail);
}
This code you can add in any component. I have added it to my root component - AppComponent
You can use a events, so you have the JavaScript send an event that you are listening for in your service.
The CustomEvent is a new feature so you might need to polyfill it: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
JavaScript:
var event = new CustomEvent("CallAngularService");
window.dispatchEvent(event);
Angular:
@HostListener("window:CallAngularService")
onCallAngularService() {
// Run your service call here
}
I think this is what you are looking for service out side angular
You can create function/class outside Angular and provide as a value in the angular. in this way you can handle both angular and non angular stuffs together:
class SomePlainClass {
...
}
window.somePlainJsFunction = new SomePlainClass();
@NgModule({
providers: [{provide: SomePlainClass, useValue: window.somePlainJsFunction}],
...
})
class AppModule1 {}
@NgModule({
providers: [{provide: SomePlainClass, useValue: window.somePlainJsFunction}],
...
})
class AppModule2 {}
class MyComponent {
constructor(private zone:NgZone, private SomePlainClass:SharedService) {
SomePlainClass.someObservable.subscribe(data => this.zone.run(() => {
// event handler code here
}));
}
}
The way it should be done depends on particular case, especially on the precedence.
If Silverlight aplication is initialized before Angular application, and window.somePlainJsFunction
is called before finishing Angular application initialization, this will result in race condition. Even if there was an acceptable way to get Angular provider instance externally, the instance wouldn't exist during somePlainJsFunction
call.
If window.somePlainJsFunction
callback is called after Angular bootstrap, window.somePlainJsFunction
should be assigned inside Angular application, where SomeAngularClass
provider instance is reachable:
window.somePlainJsFunction = function (data) {
SomeAngularClass.method();
}
If window.somePlainJsFunction
callback is called before Angular bootstrap, it should provide global data for Angular application to pick up:
window.somePlainJsFunction = function (data) {
window.angularGlobalData = data;
}
Then window.angularGlobalData
can be used inside Angular, either directly or as a provider.
Working Example