I want to be able to watch and update when a variable outside of angular2 changes. So let's say I have this in an external javascript file:
var test = 1;
How can I bind this variable to a property in a component?
@Component({
...
})
export class MyComponent {
watchy = window.test;
}
Apparently this should just work, according to this answer.
But it doesn't. If I change the variable in the console, the variable does not update displayed in a template. Am I missing something?
Angular only runs change detection when an async executed function completes. The function needs to be run inside Angulars zone for angular to recognize the async operation.
Because your variable is changed from outside Angulars zone. Angular doesn't run change detection.
You need to invoke change detection manually for Angular to recognize the changed variable. See also Triggering Angular2 change detection manually
If you for example can dispatch an event instead of just setting a variable, you can listen to the event.
window.dispatchEvent(new CustomEvent('test', {detail: 'newValue'}));
@Component({
...
})
export class MyComponent {
@HostListener('window:test', ['$event'])
testListener(event) {
this.watchy = event.detail;
}
}
Invoked event handlers automatically invoke Angulars change detection, therefore there is nothing more to do.
Apparently this should just work, according to this answer.
I'm not sure how you jumped to that conclusion, but no matter, there is a bigger issue with the code. This line of code
watchy = window.test;
Will create a component property that is a primitive type. When that line of code executes, watchy
will be assigned the value 1
. watchy
, since it is a primitive, has no relationship with window.test
after the assignment is made – it simply gets a copy of the window.test
value for the assignment. So, if you then change the value of window.test
, JavaScript won't update watchy
, so Angular change detection isn't even a factor here.
If you want the component property to be linked to the global variable, you could wrap your primitive type inside an object:
var myObj = { test: 1}
export class MyComponent {
watchy = window.myObj;
}
Now, watchy
is a reference type, and it refers to the myObj
object – it does not get a copy of the object, it just "points" to it. So, if you then change myObj.test
, then watchy will "see" the new value, since it is still pointing to the myObj.test
object. But Angular change detection won't notice if you change the value outside the Angular zone.
If you are displaying the value of test
in a component template, you will need to change test
inside the Angular zone in order for change detection to run and notice the change. Instead of repeating a bunch of code here, see Angular 2 How to get Angular to detect changes made outside Angular?
Günter's answer is another approach: set up an event listener inside Angular (hence inside the Angular zone), then fire that event whenever test
changes.
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