suppose we want to create our first great web framework Ares (written in typescript).we have components in our library and the first thing we are trying to solve is sync state from component to view and vice versa. here’s how our library source looks like.
class Ares {
comps: any[] = [];
addComp(comp: any) {
this.comps.push(comp);
}
renderUi() {
let htmlToRender = "";
this.comps.forEach(c => (htmlToRender += c.render()));
document.querySelector("body").innerHTML = htmlToRender;
}
}
var ares = new Ares();
export default ares;
so our Ares has components and it has a magic function “renderUi()”, which internally calls components render function, combines HTML and sets them to the body (worst way to implement sync 🙂 ). okay, so far so good, let’s add a simple component to our application.
To get in-Depth knowledge on Angularjs you can enroll for a live demo on Angular Online Training
export class Root {
seconds = 0;
constructor() {
}
render() {
return `<div> ${this.seconds} </div>`;
}
}
and we have our “main.ts” file, where an application is started;
import { Root } from "./root";
import ares from "./ares";
let ro1 = new Root();
ares.addComp(ro1);
ares.renderUi();
here we just create component, adding to ares instance and call renderUi() method to sync state. so everytime something has changed inside component we have to call renderUi() method;
Take your career to new heights of success with Angularjs online course
import ares from "./ares";
export class Root {
seconds = 0;
constructor() {
this.fakeAsyncRequest();
}
//fake request that set's seconds to 50
// we call renderUi(); method to update changes;
private fakeAsyncRequest() {
setTimeout(() => {
this.seconds = 50;
ares.renderUi();
}, 3000);
}
render() {
return `<div> ${this.seconds} </div>`;
}
}
as it turns out whenever our framework consumer want’s to update state from component to view, he has to call renderUi() method. we don’t like that, we want our consumers to be happy and don’t worry about some internal stuff, so how can we call renderUi method whenever something changes. let’s think about a bit when does anything changes to a web application regardless of scale or size of it?. there are only 4 ways to make this happen
- Ajax request
- user events (click,focus,blur…)
- setTimeout
- setInterval
if none of this happened, then there is no way that any state has been changed. so if we somehow get notified that some of that operation has been completed then we can call our magic function and update state from component to view.
for the first glance, it’s really hard to figure out how can we be notified that’s something has happened, because browsers don’t have such kind of API.what browsers have is you can override almost every method or variable in browsers API. so what if we write something like that
To learn more about NgZone in Angular and other great features of AngularJS , you can enroll for a live demo on Angularjs Online Training
class Ares {
comps: any[] = [];
addComp(comp: any) {
this.comps.push(comp);
}
renderUi() {
let htmlToRender = "";
this.comps.forEach(c => (htmlToRender += c.render()));
document.querySelector("body").innerHTML = htmlToRender;
}
}
var ares = new Ares();
//we overite setInterval method
let oldTimeout = window.setTimeout;
window.setTimeout = (handler,time) => {
let rewritedHandler = () => {
handler();
ares.renderUi();
};
return oldTimeout(rewritedHandler,time);
};
export default ares;
we are overriding default setTiemout method, here’s what’s gonna happen, whenever someone calls setTimeout it will go to our cuatom setTimeout method, that calls our rewritedHandler method and internally calls passed handler function, and that’s the place where we will be notified whenever setTimeout fires and call renderUi() method, so if we remove renderUi() method, from root component inside setTimeout, the data will be synced anyway. really cool right?!, we can override also user events, setInterval ajax requests, and get notified whenever something happens. and that’s what is the amazing Zone.js library used for, Angular uses internally to detect that something happened inside an application, that’s why you don’t have to call some Angular’s internal function to update state ( like React setState method).
Zone.js does it the same way as we did here (of course muuuuch more sophisticated way, and adds much more features on it ).
NgZone is just wrapper class around zone, so you can use it inside in Angular. so whenever you have some async operation that you don’t want to trigger change detection, you can call it inside runOutsideAngular, of ngZone class and job is done, in the opposite if there’s some third party library, that doesn’t trigger change detection for example “TweenMax”, you can call any of it’s method inside NgZone’s run method, and it will triger change detection.