I am trying to create a simple example project to test the angular 2 change detection mechanism: I create a pure javascript object in script tags on the main index page. it contains the following:
var Tryout = {};
Tryout.text = "Original text here";
Tryout.printme = function(){
console.log(Tryout.text);
}
Tryout.changeme = function(){
Tryout.text = "Change was made";
}
One function to console log it, and one to change the text property.
Now in Angular 2 the code looks like this:
import {Component} from "angular2/core"
@Component({
selector: 'my-app',
template: `
<h1>{{TryoutRef.text}}</h1>
<input type="text" [(ngModel)]="TryoutRef.text">
<button (click)="consoleLogMe()">Console Log</button>
<button (click)="changeMe()">Change me inside</button>
`
})
export class MyApp{
TryoutRef:any = Tryout;
constructor(){
}
changeMe(){
this.TryoutRef.changeme();
}
consoleLogMe(){
console.log(this.TryoutRef.text);
}
}
declare var Tryout:string;
What I am trying to do is this: When I call the function Tryout.printme() normally with onclick (Completely outside of angular) I want angular to detect the change and update the screen.
I succeeded to this point: When I call Tryout.printme() from the component (the changeme() function is calling Tryout.printme()), Angular detects the change and updates the UI which is fine. Also, when I change from outside angular and I call consoleLogMe() from Angular it is logging the changed text and updates the UI.
I guess I need to execute Tryout.changeme() in the same Zone that Angular is running in somehow. Any ideas? I have a big project which is done in pure javascript/jquery, and now I slowly need to rewrite the handlebar templates to angular2 components without touching the model (yet). For that I need to force the model to execute in the same zone as angular.
If I wanted to do something like this in Angular 1 I would just $scope.$apply it would work.
Here is a gif from the example:
Angular 2's change detection system is built on top of zone. js hooks. Once an asynchronous action completes, Angular 2 starts its change detection routine. This means traversing all of the nodes in the "component tree" always starting with the root node.
To run the change detector manually: Inject ChangeDetectorRef service in the component. Use markForCheck in the subscription method to instruct Angular to check the component the next time change detectors run. On the ngOnDestroy() life cycle hook, unsubscribe from the observable.
If you are mutating data outside of the angular context (i.e., externally), then angular will not know of the changes. You may have to use ChangeDetectorRef or NgZone in your component for making angular aware of external changes and thereby triggering change detection.
You can do this by exporting NgZone
inside your Angular app.
Usually, you should do all things inside Angular, but if you really want to execute your logic out of Angular, you need to get the right zone
, as you have said.
This trick is abusing Angular's dependency injection and hooking the injected zone
on window
object, as this issue shows. Declaring a dependency on NgZone
, and assigning it to window.zoneImpl
for exporting.
//our root app component
import {Component, NgZone} from 'angular2/core'
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
`,
})
export class App {
constructor(zone: NgZone) {
this.name = 'Angular2'
window.app = this
window.zoneImpl = zone
}
}
After Angular bootstrapping, you should have a zoneImpl
global variable. You can use the run
method to kick Angular off.
zoneImpl.run(() => window.app.name = "new name!")
Live demo.
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