Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we call angular functions by native javascript in angular 4

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?

like image 378
dev Avatar asked Aug 31 '25 01:08

dev


1 Answers

I can think of many ways, but have never read anything in the manuals which clarifies as to the most Angular way.

Zones

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?

Accessing Angular

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.

Easy Component One-Way Binding

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.

like image 104
Reactgular Avatar answered Sep 02 '25 16:09

Reactgular