In Angular 1.x , we can use angular.element(appElement).scope()
to get $scope
, and then use the $apply()
, so that the native javascript can directly call angular functions or two-way binding. While with Angular 4, how could we call angular functions or two-way binding by native javascript or the android native.
For example :
The web is developed by angular 4, and it will be used in the android webview, so it needs an interaction with android, how can i handle the interaction?
I can think of many ways, but have never read anything in the manuals which clarifies as to the most Angular way.
You have to keep in mind that Angular uses zones and a change detection tree at the core of it's engine. So any outside access needs to happen in that context.
You have to run external code in the Angular zone:
zone.run(() => {
// do work here
});
If you make changes to any data that will directly or indirectly effect a template expression you run the risk of a change detection error. So a component needs to inject ChangeDetectorRef
and call markForCheck
.
So if you code runs inside a component but from outside of Angular. You need to do this:
zone.run(() => {
// do work here.
this.ChangeDetectorRef.markForCheck();
});
Still, that raises the question. How do I get to the component?
You have to bootstrap your Angular application so that it can be accessed.
When you bootstrap your Angular application the browser service returns a promise to the main module. That main module contains the injector and from there you can access any exported services.
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then((modRef: NgModuleRef<AppModule>) => {
window.myGlobalService = modRef.injector.get(MyServiceClass);
});
That would place a service class as a global variable. You would have to create an API that forwards to Angular's zones.
@Injectable()
export class MyServiceClass {
public dataEmitter: Subject<any> = new Subject();
public constructor(private zone: NgZone) {}
public fooBar(data: any): any {
return this.zone.run(()=>{
// do work here
this.dataEmitter.next(data);
return "My response";
});
}
}
You can return a result from zone.run
out of the service. The key is that Angular code is run in the correct zone.
The easiest solution for one-way data binding is to just use the Event module for the DOM.
@Component({....})
export class MyComponent {
@HostListener('example',['$event'])
public onExample(event: Event) {
console.log(event.fooBar);
}
}
// else where in external JavaScript
var elem; // the DOM element with the component
var event = new Event('example', {fooBar: 'Hello from JS!'});
elem.dispatchEvent(elem);
I prefer this approach since Angular handles the event listener as it would any other kind of event (i.e. click events)
You can also do this the other way around. Have the component emit DOM events on it's ElementRef
for external JavaScript to listen for. This makes the whole two-way communications more DOM standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With