Hey Guys!
Every developer wants to build fast and robust Angular applications. But to be able to, you need to dive into the Angular internal structure and obtain comprehensive understanding how it works and sometimes it is not that easy from the first try.
In this article, I'll try to give you a superficial idea of how Angular works under the hood not going in too much of detail.
The main concept of the Angular internals that we need to discuss is Change Detection - process that checks if data has been changed and re-renders components’ templates.
Let's break it into the following topics:
- The internal representation of Angular applications
- (Who triggers change detection)
- What change detection does
- How Angular updates DOM
- Why we need ExpressionChangedAfterItHasBeenCheckedError
Internal representation
When you build an Angular application you start from AppComponent, then you create more and more components, combine them in modules and use these components here and there. Thus, we can imagine Angular application as a tree of components, but it only scratches the surface. Let's figure out what the Angular application actually consists of.
If you create a simple component like this:
and build your application in aot mode, you'll be able to find component factory generated by the Angular compiler. It will look like a simplified factory:
Component factory describes the structure of the component view and is used when instantiating ViewDefinition.
ViewDefinition is like a template which is used when instantiating components. For each component, Angular instantiates ViewData that contains component instance, its state, children, parent and bounded properties.
As we can see now, the Angular application is not just a tree of components but a tree of ViewData instances and our components are just fields of that view data instances. Moreover, Angular runs change detection process over ViewData, not over components itself.
Who triggers change detection?
Ok, now we know how angular represents our applications and what instances are used to perform change detection’s tasks.
Before digging into change detection process I want to tell you what actions and events are responsible for triggering this process:
- Developer through ChangeDetectorRef
- Output events of the components
- Async browser APIs (XHR, setTimeout, click, etc.) with help of Zone.js.
More details you can find by the links above but let's focus on Zone.js now.
Zone.js
I don't want to be too specific about Zone but in few words, you can think about it as a tool that provides you with a capability to hook into your code execution process and track when a part of your code has started or finished execution. For example in the case below we use afterTask hook that will be run when a code in the run method finished its execution, including asynchronous tasks. So this hook will be executed only when setTimeout is completed:
And that’s a point. Zone is an execution context that persists across async tasks. Angular has Zone wrapper called NgZone that gives a capability to do something similar to the code below, meaning, subscribe to events fired by zone and run change detection loop:
Can I run something outside change detection?
Angular subscribes to the most of the browser events and runs change detection as a reaction but if you want to run some process that doesn't require DOM updates you can run it outside change detection within runOutsideAngular method of the NgZone. This may be useful for sending analytics to the server from time to time because we don't need to update application UI during this process.
Change detection flow
It's time to investigate what change detection exactly does. If it’s been triggered it starts from the root component, checks it and proceeds to the children. As you can see in the picture below change detection can be triggered on any component and always starts from the application root.
During the change detection on a component angular does the following steps:
- Update input properties for child components
- Call ngOnChanges, ngOnInit and ngDoCheck hooks on all child components
- Update DOM for the current component
- Run change detection for all child components
- Call ngAfterViewInit lifecycle hook for all child components
Let's imagine that we have three components:
Change Detection flow for these components will be the following:
- Checking A component:
- update B input bindings
- call ngOnChanges, ngOnInit and ngDoCheck on the B component
- update DOM for component A
- Checking B component:
- update C input bindings
- call ngOnChanges, ngOnInit and ngDoCheck on the C component
- update DOM for component B
- Checking C component:
- update DOM for component C
OnPush Strategy
As we can see, calling ngOnChanges and ngDoCheck hooks doesn't mean component has been checked. These hooks are called when change detection process is focused on the component parent, so ngDoCheck of the B component will be called when change detection is checking A component.
This may lead your application to the strange behavior when you're using OnPush strategy.
I mean, if we make changeDetectionStrategy of B component OnPush and don't change input props B component will not be checked but ngDoCheck hook will be triggered.
- Checking A component:
- update B input bindings
- call ngDoCheck on the B component
- update DOM interpolations for component A
- if (bindings changed) -> Checking B component
OnPush Strategy Emulation
For a better understanding how OnPush strategy works, let's see how we can emulate it. Using ChangeDetectorRef of the component we can detach it when instantiating and stop detecting changes on it. Anyway, as we know from examples above ngOnChanges hook will be called on this component even though it's detached because it'll be called when change detection checks its parent.
ngOnChanges will be called only if property binding has been changed. Sounds similar to the OnPush strategy, right? So, if input bindings have changed we have to reattach component and allow change detection process it. And then detach it again asynchronously.
DOM updates
I think it's time to discuss the most important step of change detection - updating DOM representation of the checked component.
Do you remember this simple component from the first part of the article?
Let's look closer to another part of the component factory that wasn't mentioned previously:
The purpose of this function is to check and update component DOM representation if bindings are changed.
Update renderer function receives checkAndUpdate function and ViewData instance that contains current component. It calls checkAndUpdate for each binding in the component template. If you have multiple bindings in template like these:
Update renderer will perform multiple calls of the checkAndUpdate:
checkAndUpdate function is just a router that chooses specific checkAndUpdate* function depends on binding type:
I think the simplest checkAndUpdate function is checkAndUpdateText and its code looks like the snippet below. It just checks that rendered values and new ones that aren't the same and then updates component DOM:
This means that each property of component template will be checked and updated separately, and if you changed only one text node of the component only this text node will be re-rendered, not all the template. This behavior helps angular reach high-speed rendering.
Why we need ExpressionChangedAfterItHasBeenChecked Error?
Angular has another important underlying concept that helps us to keep view and model of an application consistent. Let's look at this example:
According to the change detection steps for this example:
- Update DOM for the current component
- Call ngAfterViewInit lifecycle hook for all child components
ngAfterViewInit of the ChildComponent will be called after updating the DOM of the ParentComponent. However, ngAfterViewInit changes parents name property which rendered in the parent template. Do you see that? Something goes wrong... Change detection has rerendered ParentComponent and then its child changes its name property.
And after that, we have inconsistency - rendered name property of the ParentComponent isn't equal actual name property because it has been changed after rendering.
Great, we’ve defined the problem, so has Angular. This is the reason why angular runs second change detection loop in the development mode for verification purpose. This verification loop checks that actual properties in components equal rendered and bounded properties and if they do not, then angular throws ExpressionChangedAfterItHasBeenCheckedError.
Let's check another example which reveals property binding issue:
We have a quite similar example to the previous one but with two differences:
1) ParentComponent passes input property for its ChildComponent
2) ChildComponent changes ParentComponent.text property in its ngOnInit hook
This code leads us to the similar error as mentioned above, but why?
It changes input bindings between parent and itself. As you remember from Change Detection Flow part, the order of change detection operations is the following for this example:
- Update input properties for child components
- Call ngOnChanges, ngOnInit and ngDoCheck hooks on all child components
But in the snippet, we change parent input binding in ngOnInit hook - after binding has been updated. Verification loop checks this inconsistency and throws the exception.
If you have this error it means you're doing something wrong with updating component properties when it had already been rendered or bounded.
To avoid such error, you have to remember about change detection operations order and update your data in the right lifecycle hooks.
Hopefully, you've found this topic useful. Keep reading our blog and see you on our meet-ups!
Retool Dashboards with HubSpot Integration
Our client needed a centralized tool to aggregate account and contact activity, improving visibility and decision-making for the sales team.
The solution
We built a Retool application integrated with HubSpot, QuickMail, and Clay.com. The app features dashboards for sorting, filtering, and detailed views of companies, contacts, and deals, along with real-time notifications and bidirectional data syncing.
The result
- MVP in 50 hours: Delivered a functional application in just 50 hours.
- Smarter decisions: Enabled data-driven insights for strategic planning.
- Streamlined operations: Reduced manual tasks with automation and real-time updates.
Lead Generation Tool to Reduce Manual Work
Our client, Afore Capital, a venture capital firm focused on pre-seed investments, aimed to automate their lead generation processes but struggled with existing out-of-the-box solutions. To tackle this challenge, they sought assistance from our team of Akveo Retool experts.
The scope of work
The client needed a tailored solution to log and track inbound deals effectively. They required an application that could facilitate the addition, viewing, and editing of company and founder information, ensuring data integrity and preventing duplicates. Additionally, Afore Capital aimed to integrate external tools like PhantomBuster and LinkedIn to streamline data collection.
The result
By developing a custom Retool application, we streamlined the lead generation process, significantly reducing manual data entry. The application enabled employees to manage inbound deals efficiently while automated workflows for email parsing, notifications, and dynamic reporting enhanced operational efficiency. This allowed Afore Capital's team to focus more on building relationships with potential founders rather than on administrative tasks.
Learn more about the case
Retool CMS Application for EdTech Startup
Our client, CutTime, a leading fine arts education management platform, needed a scalable CMS application to improve vendor product management and user experience.
The scope of work
We developed a Retool application that allows vendors to easily upload and manage product listings, handle inventory, and set shipping options. The challenge was to integrate the app with the client’s system, enabling smooth authentication and product management for program directors.
The result
Our solution streamlined product management, reducing manual work for vendors, and significantly improving operational efficiency.
Building Reconciliation Tool for e-commerce company
Our client was in need of streamlining and simplifying its monthly accounting reconciliation process – preferably automatically. But with a lack of time and low budget for a custom build, development of a comprehensive software wasn’t in the picture. After going through the case and customer’s needs, we decided to implement Retool. And that was the right choice.
The scope of work
Our team developed a custom reconciliation tool designed specifically for the needs of high-volume transaction environments. It automated the processes and provided a comprehensive dashboard for monitoring discrepancies and anomalies in real-time.
The implementation of Retool significantly reduced manual effort, as well as fostered a more efficient and time-saving reconciliation process.
Creating Retool Mobile App for a Wine Seller
A leading spirits and wine seller in Europe required the development of an internal mobile app for private client managers and administrators. The project was supposed to be done in 1,5 months. Considering urgency and the scope of work, our developers decided to use Retool for swift and effective development.
The scope of work
Our developers built a mobile application tailored to the needs of the company's sales force: with a comprehensive overview of client interactions, facilitated order processing, and enabled access to sales history and performance metrics. It was user-friendly, with real-time updates, seamlessly integrated with existing customer databases.
The result? Increase in productivity of the sales team and improved decision-making process. But most importantly, positive feedback from the customers themselves.
Developing PoC with Low Code for a Tour Operator
To efficiently gather, centralize, and manage data is a challenge for any tour operator. Our client was not an exception. The company was seeking to get an internal software that will source information from third-party APIs and automate the travel itinerary creation process. Preferably, cost- and user-friendly tool.
The scope of work
Our experts ensured the client that all the requirements could be covered by Retool. And just in 40 hours a new software was launched. The tool had a flexible and easy-to-use interface with user authentication and an access management system panel – all the company needed. At the end, Retool was considered the main tool to replace the existing system.
Testing New Generation of Lead Management Tool with Retool
Our client, a venture fund, had challenges with managing lead generation and client acquisition. As the company grew, it aimed to attract more clients and scale faster, as well as automate the processes to save time, improve efficiency and minimize human error. The idea was to craft an internal lead generation tool that will cover all the needs. We’ve agreed that Retool will be a perfect tool for this.
The scope of work
The project initially began as a proof of concept, but soon enough, with each new feature delivered, the company experienced increased engagement and value.
We developed a web tool that integrates seamlessly with Phantombuster for data extraction and LinkedIn for social outreach. Now, the company has a platform that elevates the efficiency of their lead generation activities and provides deep insights into potential client bases.
Building an Advanced Admin Portal for Streamlined Operations
Confronted with the need for more sophisticated internal tools, an owner of IP Licensing marketplace turned to Retool to utilize its administrative functions. The primary goal was to construct an advanced admin portal that could support complex, multi-layered processes efficiently.
The scope of work
Our client needed help with updating filters and tables for its internal platform. In just 30 hours we've been able to update and create about 6 pages. Following features were introduced: add complex filtering and search, delete records, styling application with custom CSS.
Together, we have increased performance on most heavy pages and fixed circular dependency issues.
Creating MVP Dashboard for Google Cloud Users
Facing the challenge of unoptimized cloud resource management, a technology firm working with Google Cloud users was looking for a solution to make its operations more efficient. The main idea of the project was to create an MVP for e-commerce shops to test some client hypotheses. Traditional cloud management tools fell short.
The scope of work
Determined to break through limitations, our team of developers turned Retool. We decided to craft an MVP Dashboard specifically for Google Cloud users. This wasn't just about bringing data into view; but about reshaping how teams interact with their cloud environment.
We designed a dashboard that turned complex cloud data into a clear, strategic asset thanks to comprehensive analytics, tailored metrics, and an intuitive interface, that Retool provides. As the results, an increase in operational efficiency, significant improvement in cost management and resource optimization.
Elevating CRM with Custom HubSpot Sales Dashboard
Our other client, a SaaS startup, that offers collaborative tools for design and engineering teams, was on a quest to supercharge their sales efforts. Traditional CRM systems were limited and not customizable enough. The company sought a solution that could tailor HubSpot to their workflow and analytics needs.
The scope of work
Charged with the task of going beyond standard CRM functions, our team turned to Retool. We wanted to redefine how sales teams interact with their CRM.
By integrating advanced analytics, custom metrics, and a user-friendly interface, our developers provided a solution that transformed data into a strategic asset.
In 40 hours, three informative dashboards were developed, containing the most sensitive data related to sales activities. These dashboards enable our customer to analyze sales and lead generation performance from a different perspective and establish the appropriate KPIs.
Building a PDF Editor with Low-Code
Our client, a leading digital credential IT startup, needed a lot of internal processes to be optimized. But the experience with low-code tools wasn’t sufficient. That’s why the company decided to hire professionals. And our team of developers joined the project.
The scope of work
The client has a program that designs and prints custom badges for customers. The badges need to be “mail-merged” with a person’s info and turned into a PDF to print. But what is the best way to do it?
Our developers decided to use Retool as a core tool. Using custom components and JavaScript, we developed a program that reduced employees' time for designing, putting the data, verifying, and printing PDF badges in one application.
As a result, the new approach significantly reduces the time required by the internal team to organize all the necessary staff for the conference, including badge creation.