DotNetCurry Logo

Angular application – Architecture Overview

Posted by: Ravi Kiran , on 11/18/2017, in Category AngularJS
Views: 13577
Abstract: This article explains the high level architecture of an Angular application. Then it discusses the core concepts of the framework with some sample code snippets written in TypeScript.

Angular is a front-end framework created by Google to make the process of building modern web apps, easier.

The capabilities of the front-end web has improved over the last few years, and current gen users demand to see their business data with a rich UI. Angular comes with a number of features to address these needs.

The foundation of Angular is built around a set of core concepts that give strength to the features of the framework. In addition to bringing UI richness, Angular provides ways to structure the code of an application. The framework is designed to build applications using a number of code blocks separated into individual modules.

Are you keeping up with new developer technologies? Advance your IT career with our Free Developer magazines covering Angular, React, .NET Core, MVC, Azure and more. Subscribe to this magazine for FREE and download all previous, current and upcoming editions.

This approach helps the developers write clean and maintainable code.

In this article, we will understand the high level architecture of an Angular application and go through the core concepts on which the framework is built.

angular-architecture

Angular Application - High Level Architecture

An Angular application can be viewed as a tree of components.

The application bootstraps using a component and rest of the application is then rendered with help of a number of sub-components. The following diagram shows how a typical Angular application is divided into components:

angular-app-architecture

Figure 1 - Angular Architecture

A Component in Angular comprises of functionality, HTML template and the CSS styles that are used in its template.

As shown in the diagram, every component lives in a module and it is loaded from the module.

The component makes use of Services to fetch data and present it in a view or to run a piece of logic that can be reused across the application and doesn’t involve DOM.

Components receive the objects of services through Dependency Injection.

Directives are used in the template of the component in order to extend the behavior of HTML elements.

The data in the component is presented on the view using Data Binding. Any change in the data is handled by the Change Detection system built in Angular, and the UI gets updated to present the latest data.

Zones keep track of the events happening at the browser level to kick in the change detection when anything happens outside Angular’s context.

This is how the Angular framework uses its core concepts to handle the applications built on it.

The following figure shows how the different pieces of Angular work together:

angular-app-overview

Figure 2 – Overview of an Angular application (source: https://angular.io/guide/architecture)

The next section will detail these core concepts.

Angular Core Concepts

Directives

Directives are used to extend the HTML by creating custom HTML elements and extending the existing elements.

Angular supports three types of directives.

The directives used to create custom elements are called Components. The directives used to extend an HTML element through a new attribute are called Attribute Directives. And the directives that interact with the DOM and manipulate the target element are called Structural Directives.

The components are created using the @Component decorator. The attribute and structural directives are created using the @Directive decorator. The components accept a template, to present it in the custom element. The directives don't have a template, as they are going to act as an add-on to an element.

Components

Generally speaking, a component is a piece of a body, particularly within a machine or a software system.

An Angular application is comprised of different components with different responsibilities. As shown in Figure-1, an Angular application itself starts with a component and this component is used to load the other components.

A component can be anything starting from an element that starts the application, an element that loads content of a page, an element that loads a portion of a page, for example to render a chart to display the details of an item, or anything can be separated into an independent piece of the page.

Angular components are custom HTML elements, which make the application more declarative and the template of the application, more readable. This is because, most of the components have human readable names. If someone uses a bad name for a component, it won’t be clear to the reader.

For example, consider the following snippet:

<div active="active">
  <ul class="nav nav-tabs nav-justified">
    <li class="tab nav-item active" index="0" heading="Tab 1">
      <a href="" class="nav-link">Tab 1</a>
    </li>
    <li class="tab nav-item" index="1" heading="Tab 2">
      <a href="" class="nav-link">Tab 2</a>
    </li>
    <li class="tab nav-item" index="2" heading="Tab 3">
      <a href="" class="nav-link">Tab 3</a>
    </li>
  </ul>
  <div class="tab-pane">
    <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Deleniti, voluptate, sint odio accusamus excepturi ea doloribus possimus repellendus ut incidunt ad laborum facere est quae ex itaque expedita. Commodi, beatae.</span>
  </div>
  <div class="tab-pane">
    <span>Aliquid, sequi, deserunt, laboriosam sunt dolore corrupti dolorem possimus rerum ducimus vel minima porro quo nam. Aliquid, at, impedit, vitae, neque voluptate doloribus animi reprehenderit nostrum harum libero obcaecati facilis?</span>
  </div>
  <div class="tab-pane">
    <span>Mollitia, dolores sapiente laboriosam itaque facilis voluptate voluptas tenetur beatae consequuntur quos corporis harum quas tempore iusto eligendi! Nihil, est incidunt laborum illo repellat facilis doloribus. Expedita, libero quod laudantium?</span>
  </div>
</div>


This HTML produces a group of three tabs when rendered on a page. But understanding this by simply reading the HTML is difficult, as it consists of a lot of elements and a number of custom CSS style classes. Now imagine the same set of tabs represented as in the following snippet:

<tabs>
  <tab title="Tab 1" content="first-tab.html"></tab>
  <tab title="Tab 2" content="second-tab.html"></tab>
  <tab title="Tab 3" content="third-tab.html"></tab>
</tabs>

Without a doubt, one can say that this version is far more readable and easy to use!

The elements, tabs and tab are components, which abstract the custom CSS classes and the set of HTML elements to be rendered under the tabs. The JavaScript code required to handle interactions of the tabs is also defined in the component.

So, a component can be viewed as a combination of HTML, CSS and JavaScript which work together to perform a task.

In addition to making the application more readable, the components also help in scoping CSS styles.

The CSS styles added in a component stay isolated within the component and they don’t affect the rest of the page. This feature makes the view of any component more predictable and saves a lot of time for the developers, as they don’t need to take extra care to make names of the CSS classes unique.

Angular uses Shadow DOM or an emulator depending on the metadata of the component to keep these styles isolated in the components.

A component is defined in Angular using a TypeScript class with the Component decorator.

The decorator accepts metadata of the component, which defines the way a component has to be used in HTML, the component’s template and a few other properties. An object of the component class serves as the view model for the template of the component. All of the fields and methods in the component class are accessible in the template.

The following snippet shows the structure of a component:

@Component({
  selector: 'sample',
  template: '<div>Some content in the component</div>',
  styles: [`
    div {
      font-style: italic;
    }
  `]
})
class SampleComponent{
  //class definition
}

This directive can be used as:

<div [myDummy]="prop"></div>

The above snippet can be used in the template of a component. This snippet assumes that the component containing this template defines a field named prop. Angular comes with a set of predefined attribute directives to address most of the general purpose needs. They will be discussed in a future article.

Structural Directives

Structural directives modify the template of the element; they can add, remove or replace elements inside the template. Like attribute directives, the structural directives are classes with the Directive decorator. Usage of the structural directives differs from usage of attribute directives, they are prefixed with an asterisk in the HTML template.

<div *repeater="collection"></div>

Angular defines a couple of structural directives for common usage. ngIf is the structural directive that can be used to toggle a portion of an HTML template based on a value. The following snippet shows an example:

<table *ngIf="data.length > 0">
  <!-- HTML markup of table -->
</table>

The above snippet has an HTML table displaying a list of items. The table is added to the page if the variable data has records, otherwise it won’t be added to the DOM.

Data Binding

Most data driven applications have a visual interface that allows users to interact with the application by viewing, adding, editing, or deleting data (traditionally referred to as CRUD operations). In general, this visual interface is referred to as the view. For example, to work with your e-mail account, you use an e-mail client that –

  • shows you the list of mails in your inbox,
  • provides controls to mark them as read, unread, important or delete the mail,
  • opens up a mail composer to write a new mail and
  • a lot of other controls to perform other operations.

Here the mail client is the view, since the user will use it to view the data in his or her e-mail account.

Now imagine developing a system similar to the e-mail client. It performs a lot of operations with the data and yet displays the most recent data to the user. This cannot be done efficiently unless the framework used to develop the application, has a strong data binding system.

Angular comes with a built-in data binding system.

In an Angular application, data in a component can be used to bind in its view. As mentioned earlier, the methods and properties of a component are directly accessible in the component’s view, and the data binding system provides a way to access them.

Angular supports the following types of bindings:

Property binding: A property on an HTML element can be bound to the value of a field in the component’s class. Whenever value of the property in the component changes, it automatically updates value of the HTML property it is bound to. The following snippet shows a simple example of property binding:

<a [href]="url">Click here to visit the link</a>

Notice the square brackets around the HTML property in the above snippet. They indicate that this field is bound to data.

Event Binding: The events of any HTML element can be bound to public methods of its component class. The method is called whenever the event is triggered by a user’s action on the page. The following snippet shows an example of event binding:

<button (click)="close()">Close</button>


Two-way Binding: It is a derived binding that uses both property binding and the two-way binding under the hood. This binding is used to display a value and also to update the value when a new value is entered in the UI. ngModel is a built-in directive that supports two-way binding. The following snippet shows how it is used:

<input type="text" [(ngModel)]="name" />

As you see, the two-way bound directive is enclosed inside [()] (called banana-in-a-box). This notation is again a mix of both property and event bindings. The parentheses around the event name indicate that it is data bound.

Change Detection

A challenge for anyone building a rich data driven application is to keep the view and its data in sync.

For example, consider a web based e-mail client again.

The view of the inbox has to be updated as soon as the client application receives a notification of a new e-mail. If the application has to perform this task by itself, it needs to listen to the new e-mail notification, build the HTML for the portion of the page displaying the list of e-mails and replace the old HTML with the new one.

A similar set of operations has to be performed to update the count of unread e-mails against the folder names.

Performing these operations manually adds a lot of clutter to the code. It is hard to maintain such code for a longer duration.

The best possible solution to such cases is an automatic change detection system!

As the name suggests, the change system detects any change in the state of the objects. Angular comes with a flexible and efficient change detection system. Once it finds any change in the values of the objects used in the view, it asks the framework to run the data binding process and as a result of this, the view gets updated.

The change detection system in Angular knows when to run and the set of actions it has to perform. The change detection system understands three types of objects:

Plain JavaScript objects: The plain old JavaScript objects can be used to build view models in an Angular application. The framework checks for any change in value of the object bound to UI on every browser event and it updates the UI if it finds a change. This technique is called dirty checking.

Observable objects: Observables are the JavaScript objects with built-in mechanism to notify a change. When value of an observable object changes, it publishes an event. One can subscribe to this event and perform an action using the new value set to the object.

Angular understands this behavior and it updates the part of page using an observable only when a notification is received. It doesn’t manually check for changes to such an object on every browser event. Angular doesn’t provide a way to create observable objects. It internally uses the library RxJS to manage observables in the framework. But it is not limited to RxJS, it can understand any observable object.

Immutable objects: An immutable object is one that gets re-instantiated when any kind of change is made on the object. Angular catches the change made to such objects and updates the portion of the page when a change is available on the immutable object. The portion of the page using an immutable object is not considered for dirty checking.

Like observables, Angular doesn’t provide a way to create immutable objects. The most popular library to work with immutability in JavaScript at the time of this writing is immutable.js from Facebook. Any of these objects described here can be used, depending on the need.

The interesting part is, different types of objects can be used for different scenarios. An application need not be built using just one type of the object. Usage of observable objects and immutable objects in critical parts of the application boosts performance of the application, as it would have fewer conditions to check. Angular has to be made aware of the special objects when they are used for data binding.

It is done using the changeDetection metadata property of the components. The following snippet shows the usage:

@Component({
  selector: 'sample',
  template: '<div>Some content in the component</div>',
  changeDetection: ChangeDetectonStrategy.OnPush
})
class SampleComponent{
  //class definition
}

The component in the above snippet is applied with the OnPush strategy. This strategy tells Angular to not run change detection on this component unless it receives a notification of change on one of its input properties, which can be an observable or an immutable object.

Zones

Any rich JavaScript application has to deal with events like button click, end of timeout, end of an asynchronous XHR request or a WebSocket push.

All of these operations are handled asynchronously by the browser using the event loop.

The application’s data often changes when these operations complete and so the underlying framework has to know when the operation completes.

Zones provide an execution context.

Zones keep track of all the operations performed in the context. Zones can intercept the asynchronous operations. Hence, one can perform some operations before the event starts and after the event ends.

An Angular application runs inside a Zone. This zone is responsible for tracking all of the events happening in the application and to start the change detection process when an event completes.

Because of this, any changes happening on the objects of the application are immediately reflected on the page and the application need not kick in the change detection manually. The intercepting behavior of the zones also allows to correctly profile an asynchronous task and even a group of asynchronous tasks which start at the same time.

Services and Dependency Injection

Say a company is building a sales application and it needs to display a report in the form of a bar chart.

The chart control has to display the report of the sales of a product over the months of a given year. The chart takes the year as an input and it has to fetch the data and then display it on the chart. Being a UI component, the chart control should accept the data and display it. It shouldn’t be made responsible to fetch the data to be displayed.

Say, the logic of the fetching the data is handled by a class named SalesData. The chart component needs an object of the SalesData class to get the data and build the chart.

If the chart component create an object of the class SalesData by itself, it adds a few problems in the application. The chart control has to be modified every time the signature of the constructor of the SalesData class is modified. It becomes hard to test the chart control, as it depends on a given implementation of an object, which can’t be mocked.

This can be solved by the Dependency Injection pattern.

Dependency Injection (DI) is a design pattern that solves the problem of handling dependencies needed in a code block.

This pattern says that the dependencies required by a code block have to be created by an external agent and they have to be injected into the code block. As the logic of creating objects is stored in one place, it reduces possibilities of code repetition.

The code consuming an injected dependency doesn’t know how the object is created, the only thing it knows is the structure of the object. This means, the object can be easily swapped with any other object that has a similar structure.

We can create a TypeScript interface for the object and have different implementations of the interface for different environments. Say for example, a component uses an object to log messages to the server. If the code is still under development and the team doesn’t want to post junk messages on the server, the object responsible for logging the message can be easily swapped with an object that logs the messages to browser’s console with methods of similar signatures.

DI is quite popular among server side typed programming languages like C# and Java. AngularJS 1 brought this feature to JavaScript and Angular implements it in an improved way. Angular uses DI to inject services into components, directives, pipes and even in services.

An Angular service is a plain ES6 class that can be used to perform tasks like interacting with an HTTP API, business calculations or anything that doesn’t depend on the DOM. In general, the services don’t depend much on the block of code where they would be used, so the logic in the service can be used at any place in the application where there is a need of the logic written in the service.

The following snippet shows a service and how it is injected in a component:

@Injectable()
class DataService{
  //service definition
}

@Component({
  selector: 'sample',
  template: '<div>Some content in the component</div>'
})
class SampleComponent{
  constructor(private dataSvc: DataService){}
  //component definition
}

The decorator Injectable applied to the service class helps in injecting dependencies to the service.

Modules

A module in an Angular application is used to group a set of related directives, services and the other code blocks in a single unit.

We can say that a module is a collection of a set of blocks, which fulfills a piece of functionality. A module can import other modules and can expose its functionality to other modules.

Every Angular application should have at least one module.

Even to start an Angular application, the component to be used at the root has to be declared as the bootstrapping component in the module. The authors of external libraries can use modules to group all of the objects they want to export to the consumers.

A module is a TypeScript class with the decorator NgModule applied on it. The following snippet shows a sample module:

@NgModule({
  imports: [BrowserModule],  //Modules imported
  declarations: [AppComponent, ApplyStyleDirective, DateFormatPipe],  //Components, directives and pipes
  providers: [DataService],  //services
  bootstrap: [AppComponent],  //Components to be used to bootstrap application
  exports: [ApplyStyleDirective]  //Components and directives to be exported to other modules
})
class AppModule {}

The above snippet uses a pipe in the declarations property of the module metadata. Pipes are used to format the data before displaying them on the screen.

In addition to providing modularity, modules can also be lazily loaded when they are required in the application. This means the code of the module need not be loaded upfront, instead it can be loaded when the module is required in the application.

Note: Angular’s modules are different from the modules introduced in ES6. ES6 modules help in keeping the code files small and focused. On the other hand, Angular modules group a set of components, directives, pipes and services in a single unit.

Conclusion

Angular brings a number of promising features for building rich data driven applications. As discussed in this article, the framework is thoughtfully built using a set of core concepts. The architecture of the framework and the applications built using it depend on these core concepts.

Each of the core concept will be explained in detail with examples in future articles. So stay tuned!

This article was technically reviewed by Keerti Kotaru and Suprotim Agarwal.

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Rabi Kiran (a.k.a. Ravi Kiran) is a developer working on Microsoft Technologies at Hyderabad. These days, he is spending his time on JavaScript frameworks like AngularJS, latest updates to JavaScript in ES6 and ES7, Web Components, Node.js and also on several Microsoft technologies including ASP.NET 5, SignalR and C#. He is an active blogger, an author at SitePoint and at DotNetCurry. He is rewarded with Microsoft MVP (Visual Studio and Dev Tools) and DZone MVB awards for his contribution to the community


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!