Developing applications in JavaScript is always a challenge. Due to its malleable nature and lack of type checking, building a decent-sized application in JavaScript is difficult. Moreover, we use JavaScript for all types of processes, such as user interface (UI) manipulation, client-server interaction, and business processing/validations. As a result, we end up with spaghetti code that is difficult to maintain and test.
Libraries, such as jQuery, do a great job of taking care of various browser quirks and providing constructs that can lead to an overall reduction in the lines of code. However, these libraries lack any structural guidance that can help us when the codebase grows.
In recent years, JavaScript frameworks have emerged to manage this complexity. Many of these frameworks, including earlier versions of Angular, use a design pattern called Model-View-Controller to separate the elements of the application into more manageable pieces. The success of these frameworks and their popularity in the developer community have established the value of using this pattern.
Web development, however, is constantly evolving and a lot has changed since Angular was first introduced in 2009. Technologies such as Web Components, the new version of JavaScript (ES2015), and TypeScript have all emerged. Taken together, they offer the opportunity to build a new, forward-looking framework. And with this new framework comes a new design patternâthe component pattern.
This chapter is dedicated to understanding the component pattern and how to put it into practice as we build a simple app using Angular.
The topics that we will cover in this chapter are as follows:
Angular basics: We will briefly talk about the component pattern that is used to build Angular applications
Building our first Angular app: We will build a small game, Guess the Number!, in Angular
An introduction to some Angular constructs: We will review some of the constructs that are used in Angular, such as interpolation, expressions, and the data binding syntax
Change detection: We will discuss how change detection is managed in an Angular app
App initialization: We will talk about the app initialization process in Angular; this is also known as bootstrapping
Tools and resources: Lastly, we will provide some resources and tools that will come in handy during Angular development and debugging
Let's get started by looking at how Angular implements the component pattern.
Angular applications use the component pattern. You may not have heard of this pattern, but it is all around us. It is used not only in software development but also in manufacturing, construction, and other fields. Put simply, it involves combining smaller, discrete building blocks into larger finished products. For example, a battery is a component of an automobile.
In software development, components are logical units that can be combined into larger applications. Components tend to have internal logic and properties that are shielded or hidden from the larger application. The larger application then consumes these building-blocks through specific gateways, called interfaces, whichÂ expose only what is needed to make use of the component. In this way, the component's internal logic can be modified without affecting the larger application, as long as the interfaces are not changed.
Getting back to our battery example, the car consumes the battery through a series of connectors. If the battery dies, however, it can be replaced by an entirely new battery, as long as that battery has the same connectors. This means that the builder of the car does not have to worry about the internals of the battery, which simplifies the process of building the car. Even more importantly, the car owner does not have to replace his or her car every time the battery dies.
To extend the analogy, manufacturers of batteries can market them for a range of different vehicles, for example, ATVs, boats, or snowmobiles. So the component pattern enables them to realize even greater economies of scale.
As web applications continue to become more sophisticated, the need to be able to construct them out of smaller and discrete components becomes more compelling. Components allow applications to be built in a way that prevents them from becoming messes of spaghetti code. Instead, component-based design allows us to reason about specific parts of the application in isolation from the other parts, and then we can stitch the application together into a finished, whole through agreed-upon points of connection.
Also, maintenance costs are less because each component's internal logic can be managed separately without affecting the other parts of the application. And putting applications together using self-describing components makes the application easier to understand at a higher level of abstraction.
If this idea makes so much sense, why was the component pattern not adopted in earlier versions of Angular? The answer is that the technologies that existed when Angular was first released did not fully support the implementation of this pattern in web applications.
Earlier versions of Angular, however, made substantial steps in the direction of enabling more intelligent web application design and organization. For example, they implemented the MVC pattern, which separates an application into a model, view, and controller (you will see the use of the MVC pattern continuing within the components that we will build in Angular).
With the MVC pattern, the model is the data, the view is a web page (or a mobile app screen or even a Flash page), and the controller populates the view with data from the model. In this way, separation of concerns is achieved. Following this pattern along with an intelligent use of directives will get you pretty close to components.
So, the earlier versions of Angular allowed applications to be designed and built more logically. However, this approach was limited by the fact that the technologies used were not truly isolated. Instead, they all ended up being rendered without any true separation from other elements on the screen.
By contrast, the newest version of Angular embraces recently emerging technologies, whichÂ make it possible to implement the component pattern more fully. These technologies include Web Components, ES2015 (the new version of JavaScript), and TypeScript. Let's discuss what each of these technologies brings to the mix that makes this possible.
Web Components is an umbrella term that actually covers four emerging standards for web browsers:
Custom elements
Shadow DOM
Templates
HTML imports
Note
More information on Web Components can be found at.
Let's now discuss each of these in detail:
Custom elements enable new types of element to be created other than the standard HTML tag names such as
<div>and
<p>. The ability to add custom tags provides a location on the screen that can be reserved for binding a component. In short, this is the first step towards separating a component from the rest of the page and making it possible to become truly self-contained.
Shadow DOM provides a hidden area on the page for scripts, CSS, and HTML. Markup and styles that are within this hidden area will not affect the rest of the page, and equally important they will not be affected by the markup and styles on other parts of the page. Our component can use this hidden area to render its display. So, this is the second step in making our component self-contained.
Templates are repeatable chunks of HTML that have tags that can be replaced with dynamic content at runtime using JavaScript. Many JavaScript frameworks already support some form of templating. Web Components standardize this templating and provide direct support for it in the browser. Templates can be used to make the HTML and CSS inside the Shadow DOM used by our component dynamic. So, this is the third step in making our component.
The final standard that makes up Web Components is HTML imports. They provide a way to load resources such as HTML, CSS, and JavaScript in a single bundle. Angular does not use HTML imports. Instead, it relies on JavaScript module loading, which we will discuss a little later in this chapter.
Web Components are not fully supported in current web browsers. For that reason, Angular components are not strictly Web Components. It is probably more accurate to say that Angular components implement the design principles behind Web Components. They also make it possible to build components that can run on today's browsers.
Note
At the time of writing this book, Angular supports evergreen browsers, such as Chrome, Firefox, Edge, as well as IE 7 and later. It also has mobile support for Android 4.1 and later. For a list of browsers supported by Angular, visit.
Therefore, throughout the rest of this book, we will focus on building Angular components and not Web Components. Despite this distinction, Angular components align closely with Web Components and can even interoperate with them. As browsers begin to support Web Components more fully, the differences between Angular components and Web Components will begin to disappear. So, if you want to begin adopting the Web Component standards of the future, Angular provides you with the opportunity to do so today.
You can develop components with ES5, but Angular enhances the ability to develop components by adding support for key features that are found in the latest languages, such as ES2015 and TypeScript.
ES2015 is the new version of JavaScript; it was approved in June 2015. It adds many improvements to the language, which we will see throughout this book, but the two that interest us the most at this point are the following:
Classes
Module loading
Classes did not previously exist in JavaScript. The key advantage of using them, now that they do exist, is that they provide a convenient container for the code in our component.
Note
To be clear, JavaScript classes do not introduce something that is completely new. The Mozilla Developer Network (MDN) describes them as
"syntactical sugar over JavaScript's existing prototype-based inheritance. . . [that] provide a much simpler and clearer syntax to create objects and deal with inheritance."
Â For more information visit.
We'll ecploreÂ these throughout the examples in this book.. Module loading allows us to select just what we need for our application from the modules that make up Angular and other components that we create or use.
Currently, a range of approaches and libraries exists to support module loading in JavaScript. ES2015 adds a new, consistent syntax for loading modules as part of the language. The syntax is straightforward and involves prefixing modules with the
export keyword (or using the default export) and then using
import to consume them elsewhere in our application.
ES 2015 module loading enables us to combine components into useful bundles or features that can be imported or exported within our applications. In fact, modules are at the core of Angular itself. We will see that modules are used extensively both in Angular itself and in the applications that we are building throughout this book.
Note
It is important to understand that, while Angular uses syntax that has similarities to ES2015 module-loading syntax, Angular modules (which we will discuss a little later in this chapter) are not the same as JavaScript modules. For further details on these differences see the Angular documentation atÂ. From this point on we will be focusing on Angular modules.
Because ES2015 is not fully supported by today's browsers, we will need to convert ES2015 into ES5 in order to use features such as classes and module loading in our applications. We do this through a process called transpilation.
Transpilation is like compilation, except that instead of converting our code into a machine language as compilation does, transpilation converts one type of source code to another type of source code. In this case, it converts ES2015 to ES5. There are several tools called transpilers that enable us to do that. Common transpilers include Traceur and Babel. TypeScript (which we will discuss next) is also a transpiler, and it is the one that we will use for the examples in this book.
Once ES2015 is transpiled to ES5, we can then use a module loader such as SystemJS to load our modules. SystemJS follows the ES2015 syntax for module loading and gives us the ability to do module loading in today's browsers.
TypeScript was created by Microsoft as a superset of JavaScript, which means that it contains the features of ES2015 (such as classes and module loading) and adds the following:
Types
Decorators
Types allow us to mark variables, properties, and parameters in our classes to indicate that they are numbers, strings, Booleans, or various structures such as arrays and objects. This enables us to perform type checking at design time to make sure that the proper types are being used in our application.
Decorators are simple annotations that we can add to our classes using the @ symbol along with a function. They provide instructions (called metadata) for the use of our classes. In the case of Angular, decorators allow us to identify our classes as Angular components. Decorators can specify modules to be used with a component and how to implement various bindings and directives, including attaching an HTML view to the component. We will cover much more about the use of decorators as we go through this book.
Decorators form a part of the ES2017 proposal and are not part of ES2015. They were added to TypeScript as part of a collaboration between Microsoft and Google. As mentioned earlier, TypeScript compiles into ES5, so we are able to use both types and decorators in browsers that do not fully support ES2015 or the proposed standard for decorators.
By following the Web Component standards and adding support for ES2015 and TypeScript, Angular gives us the ability to create web applications that implement the component design pattern. These components help realize the vision behind the standards of building large-scale applications through collections of self-describing and self-contained building blocks.
We hope you will see in the examples in this book that Angular enables components to be constructed in a straightforward and declarative way that makes it easier for developers to implement them. As we proceed through the examples in this book, we will highlight where each of these technologies is being used.
Components are the basic building block of an Angular application. But how do we then organize these building blocks into complete applications? Angular modules provide the answer to this question. They enable us to combine our components into reusable groups of functionality that can be exported and imported throughout our application. For example, in a more sophisticated application we would want to have modules for things such as authentication, common utilities, and external service calls. At the same time, modules enable us to group features within an application in a way that allows us to load them on demand. This is called lazy loading, a topic we will cover in Chapter 4, Building Personal Trainer.
Each Angular application will have one or more modules that contain its components. Angular has introduced
NgModule as a way to conveniently specify the components that make up a module. Every Angular application must have at least one of these modulesâthe root module.
To sum up: at a basic level, you will see that to develop applications in Angular, you will do the following:
Create components.
Bundle them into modules.
Bootstrap your application.
The best way to understand Angular and the component design pattern is by seeing it in action. Hence, we are going to build our first Hello World app in Angular. This app will help you become familiar with the Angular framework and see the component design pattern in action.
Let's get started doing that.
As our first exercise, we want to keep things simple but still showcase the framework's capabilities. Therefore, we are going to build a very simple game called Guess the Number!. The objective of the game is to guess a random computer-generated number in as few tries as possible.
This is how the game looks:
The development web server that we choose greatly depends on the platform we work on and the backend we support. However, since apps in this book target purely client-side development, any web server will do.
Our recommendation is to use
live-server, a simple HTTP server with live reload capability. You can install it using Node.js. Since Node.js is available cross-platform, you can install Node.js from.
Note
For this book, we are using Node.js version 4.4.2 and npm version 3.8.6. You can find more information about installing Node and updating npm to the latest version at.
Once Node.js is installed, installing the
live-server module and running the HTTP server is easy. Open the command line and type the following command:
npm install -g live-server
This installs
live-server at the global level.
To run the server, we just navigate to the folder where the app code resides, or open the folder from where we want to serve static files. Then type this:
live-server
And that's it!
We have an HTTP server running at. It can serve files from the current directory.
Note
The
live-server module does support some startup configurations. Check out the documentation at.
Depending on the platform we are on, we can also try Python's
SimpleHTTPServer module, Mongoose, or any such web server.
Let's now build Guess the Number!.
The standard practice while building user interfaces is to build them top-down. Start by designing the UI and then plug in the data and behavior according to your needs. With such an approach, the UI, data, and behavioral aspects of the app are all tightly coupled, which is a less than ideal situation!
With component-based design, we work differently. We start by looking at the UI and expected behavior, and then we encapsulate all of this into a building block that we call aÂ.
To determine what needs to go into our component, we will start by detailing the features that we want the app to support:
Generating random numbers (
original)
Providing input for a user to guess the value (
guess)
Tracking the number of guesses already made (
noOfTries)
Giving the user hints to improve their guess based on their input (
deviation)
Giving a success message if the user guesses the number correctly (
deviation)
Now that we have our features, we can determine what we need to display to the user and what data we need to track. For the preceding feature set, the elements in parentheses denote the properties that will support those features and will need to be included in our component.
Note
Designing the component is a very crucial process. If it is done right, we can logically organize our application in a way that makes it understandable and easy to maintain.
While building any app, we urge you to first think about the functionality you want to offer, and then the data and behavior that can support the functionality. Lastly, think about how to build a user interface for it. This is a good practice irrespective of the library or framework you use to build your app.
Let's start by creating files for our component. We'll start by creating a directory for our application. We'll name it
guessthenumber (but you can name it anything that suits you). We'll use that to add our files.
First, open your favorite editor and create an HTML page with the following
htmlÂ and
script tags:
<!DOCTYPE html> <html> <head> <title>Guess the Number!</title> <link href=" 3.1.1/css/bootstrap.min.css" rel="stylesheet"> <script src=""></script> <script src="[email protected]"></script> <script src="[email protected]?main=browser"></script> <script src="[email protected]/lib/typescript.js"> </script> <script src="[email protected]/dist/system.js"> </script> <script src="systemjs.config.js"></script> <script> System.import('app').catch(function(err){ console.error(err); }); </script> </head> <body> <my-app>Loading...</my-app> </body> </html>
Tip
Downloading the example code
The code in this book is available on GitHub at. It is organized in checkpoints that allow you to follow along step by step as we build our sample projects in this book. The branch to download for this chapter is GitHub's Branch: checkpoint1.1. Look in the
guessthenumber folder for the code we are covering here.Â If you are not using Git, download the snapshot of Checkpoint 1.1 (a ZIPÂ file) from the following GitHub location:. Refer to the
readme.md file in the
guessthenumber folder when setting up the snapshot for the first time.
There are several things to note in this file:
The first five
<script>tags reference the following:
shim: This provides ES2015 features for older browsers
reflect-metadata: This adds decorator support
zone.js: This manages change detection
typescript.js: This is the current version of TypeScript
system.js: This loads our modules
The next
<script>tag references a JavaScript file within our application:
systemjs.config.js. Be sure to add that file from the example code files. We will be discussing this file a little later. Essentially, it provides instructions to SystemJS as to which modules it should load and directs it to dynamically transpile our TypeScript files to ES5 at runtime.
The final
<script>tag calls SystemJS to import our component directory:
app.
We will discuss how the latter two script tags work together to enable module loading a little later in the chapter.
There is one more important tag on the page:
<my-app>Loading...</my-app>
This tag is a custom element. It instructs Angular where to inject the component that we will be building.
The rest of the app's HTML code is self-explanatory. We reference the Twitter Bootstrap CSS in the
<head> section and add a title, which is
Guess the Number!, for our page.
Now let's create a file for our component.
Add a subdirectory to our application called
app.
Then, using your editor, create a file with the name
guess-the-number.component.tsand place it in that subdirectory. The
.tsextension identifies our file as a TypeScript file that will be compiled into ES5 at runtime.
At the top of the page, place the following line:
import { Component }from '@angular/core';
This is an import statement. It tells us what modules we will be loading and using in our component. In this case, we are selecting one module that we need to load from Angular:
Component. Angular has many other modules, but we load only what we need.
You'll notice that the location from which we are importing is not identified as a path or directory within our application. Instead, it is identified as
@angular/core. Angular has been divided into barrel modules that are prefixed with
@angular.
These barrels combine several modules that are logically related. In this case, we are indicating that we want to import the
core barrel module, which in turn brings in the
Component module. This naming convention ties into the loading of our modules, which we will discuss in more detail later in this chapter.
Next, add the following block of script to your
guess-the-number.component.ts file:
@Component({ selector: 'my-app', template: ` <div class="container"> <h2>Guess the Number !</h2> <p class="well lead">Guess the computer generated random number between 1 and 1000.</p> <label>Your Guess: </label> <input type="number" [value]="guess" (input)="guess = $event.target.value" /> <button (click)="verifyGuess()" class="btn btn-primary btn-sm"> Verify</button> <button (click)="initializeGame()" class="btn btn-warning btn-sm"> Restart</button> > })
This is the decorator for our component and is placed directly above the class definition, which we will discuss soon. The
@ symbol is used to identify a decorator. The
@Component decorator has a property called selector, and you may not be surprised to see that it is set to the
<my-app> tag in our HTML page. This setting tells Angular to inject this component into that tag on the HTML page.
The decorator also has a property called template, and this property identifies the HTML markup for our component. Notice the use of back ticks (introduced by ES2015) for rendering the template string over multiple lines. Alternatively, we can set a
templateUrl property that would point to a separate file.
Now, add the following block of code to your
guess-the-number.component.ts file:
export class GuessTheNumberComponent { deviation: number; noOfTries: number; original: number; guess: number; constructor() { this.initializeGame(); } initializeGame() { this.noOfTries = 0; this.original = Math.floor((Math.random() * 1000) + 1); this.guess = null; this.deviation = null; } verifyGuess() { this.deviation = this.original - this.guess; this.noOfTries = this.noOfTries + 1; } }
If you have been developing in ES5, the version of JavaScript that is supported in all current browsers, you may not be familiar with the use of classes here. So, we will take a few moments to walk through what makes up aÂ class (for those of you who have developed using an object-oriented programming language, such as C# or Java, this should be familiar territory).. These set the type of the property. In this case, we are indicating that each of these four properties will be set to the number type, which means we are expecting the values of all of these properties to be numbers. The ability to specify types for our properties is provided by TypeScript and is not available in standard JavaScript.
As we move down, we will see three blocks of script that have names, followed by parentheses, and then curly braces with several lines of script inside them. These are the methods for our class, and they contain the operations that our component will support. They are a lot like standard JavaScript functions.
The first of these methods is
constructor(), which is a special method that will run when an instance of our component is first created. In our example, the constructor does only one thing when the class is created; it calls another method in our class, called
initializeGame().
The
initializeGame() method sets the starting values of the four properties in the class using the assignment operator
=. We set these values to
null or
zero, except for
original, in which we use a random number generator to create the number to be guessed.
The class holds one more method called
verifyGuess(), which updates the
deviation and
noOfTries properties. This method is not being called from within the component class; instead, it will be called from the view, as we will see when we examine the view more closely later. You'll also notice that our methods refer to properties in the same class by prepending
this to them.
As we mentioned earlier, every Angular component must be contained within an Angular module. This means that at a minimum we must add at least one Angular module file to the root of our application. We call this the root module. For a simple application like Guess the Number!, the root module may be the only module we will need. However, as an Angular application increases in size, it will often make sense to have multiple Angular module files broken down by features. We will cover that situation as we move into building more complex applications in later chapters in this book.
Let's go ahead and create our Angular module file. First, create a new file named
app.module.ts in the same directory as
guess-the-number.component.ts and add the following code to it:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { GuessTheNumberComponent } from './guess-the-number.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ GuessTheNumberComponent ], bootstrap: [ GuessTheNumberComponent ] }) export class AppModule { }
The first two statements import
NgModule and
BrowserModule. Notice that, while
NgModule is being imported from
@angular/core,
BrowserModule is being imported from a different module:
@angular/platform-browser. What's significant here is that the import is not coming from
@angular/core but from a separate module that is specific to browser-based applications. This is a reminder that Angular can support devices other than browsers, such as mobile devices, hence the need to place
BrowserModule into a separate module.
The other import in this file is our component
GuessTheNumberComponent, which we just built. If you go back to that component you will notice that we added
export in front of the class definition, which means we are using module loading within our own application.
We next define a new component
AppModule. This component looks different from
GuessTheNumberComponent, which we just defined. There is nothing in the class itself other than a few imports and a decorator:
@ngModule. We can use this decorator to configure the module in our application. We first add imports, which in this case include the
BrowserModule. As the name suggests, this module will provide the functionality needed to run our application in a browser. The next property is declarations and with that property we provide an array of the components that will be used in our application. In this case, we have just one component:
GuessTheNumberComponent.
Finally, we set the
bootstrap property. This indicates the first component that will be loaded when our application starts up. Again this is the
GuessTheNumberComponent.
With this configuration in place, we are now ready to bootstrap our component.
The class definition for
GuessTheNumberComponent operates as a blueprint for the component, but the script inside it does not run until we have created an instance of the component. In order to run our application then, we need something in our application that creates this instance. The process of doing that requires us to add code that bootstraps our component.
In the
app subdirectory, create another file named
main.ts and add the following code to it:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; const platform = platformBrowserDynamic(); platformÂ we have just defined.
Finally, we assign
platformBrowserDynamic(), which we just imported, to a constant: platform. Then we call its
bootstrapModule method with our
AppModule as a parameter. TheÂ
bootstrapModuleÂ method then creates a new instance of our
AppModule component, which in turn initializes our
GuessTheNumberComponent, which we have marked as the component to bootstrap. It does that by calling the component's constructor method and setting the starting values for our game.
We will discuss in greater detailÂ how this
bootstrap method fits into the entire process of app initialization a little later in this chapter.
Well, the app is complete and ready to be tested! Navigate to the directory where the file is located and type this:
live-server
The app should appear on your browser.
Note
If you are having trouble running the app, you can check out a working version available on GitHub at.Â If you are not using Git, download the snapshot of Checkpoint 1.1 (a ZIPÂ file) from the following GitHub location:. Refer to the
readme.md file in the
guessthenumber folder when setting up the snapshot for the first time.
If we glance at our component file now, we should be mightily impressed with what we have achieved with these 43 lines. We are not writing any code to update the UI when the application is running. Still, everything works perfectly.
To understand how this app functions in the Angular context, we need to delve a little deeper into our component. While the class definition in the component is pretty simple and straightforward, we need to look more closely at the HTML in the template that is inside the
@Component decorator to understand how Angular is working here. It looks like standard HTML with some new symbols, such as
[ ],
( ),
{{, and
}}.
In the Angular world, these symbols mean the following:
{{and
}}are interpolation symbols
[ ]represents property bindings
( )represents event bindings
Clearly, these symbols have some behavior attached to them and seem to be linking the view HTML and component code. Let's try to understand what these symbols actually do.
Look at this HTML fragment from the Guess the Number! code:
<p class="text-info">No of guesses : <span class="badge">{{noOfTries}}</span> </p>
The term
noOfTries is sandwiched between two interpolation symbols. Interpolation works by replacing the content of the interpolation markup with the value of the expression (
noOfTries) inside the interpolation symbol. In this case,
noOfTries is the name of a component property. So the value of the component property will be displayed as the contents inside the interpolation tags.
Interpolations are declared using this syntax:
{{expression}}. This expression looks similar to a JavaScript expression but is always evaluated in the context of the component. Notice that we did not do anything to pass the value of the property to the view. Instead, the interpolation tags read the value of the property directly from the component without any need for additional code.
Another interesting aspect of interpolation is that changes made to component properties are automatically synchronized with the view. Run the app and make some guesses; the
noOfTries value changes after every guess and so does the view content:
Interpolation is an excellent debugging tool in scenarios where we need to see the state of the model. With interpolation, we don't have to put a breakpoint in code just to know the value of a component property. Since interpolation can take an expression, we can pass a component's method call or a property and see its value.
Before going any further, we need to spend a few moments understanding what template expressions are in Angular.
Template expressions in Angular are nothing but pieces of plain JavaScript code that are evaluated in the context of the component instance associated with the template instance in which they are used. But as the documentation atÂ makes it clear, there are some differences:
Assignment is prohibited, except in event bindings
The new operator is prohibited
The bitwise operators
|and
&are not supported
Increment and decrement operators,
++and
--, aren't supported
Template expression operators, such as
|and
?.add new meanings
In the light of our discussion on component-based design, you probably won't be surprised to learn that the documentation also makes some more things clear; template expressions cannot:
Refer to anything in the global namespace
Refer to a window or document
Call
console.log
Instead, these expressions are confined to the expression context, which is typically the component instance supporting a particular template instance.
However, these limitations do not stop us from doing some nifty stuff with expressions. As we can see in the following examples, these all are valid expressions:
// outputs the value of a component property {{property}} // adds two values {{ 7 + 9 }} //outputs the result of boolean comparison. Ternary operator {{property1 >=0?'positive': 'negative'}} //call a component's testMethod and outputs the return value {{testMethod()}}
Note
Having looked into expressions, we strongly advise you to keep your expressions simple, thus keeping the HTML readable.
The
*ngIf="formHasErrors()" expression is always better than
*
ng-if="name==null || email==null || emailformatInValid(email) || age < 18".
So, when an expression starts to become complex, move it into a method in your component.
Before we move on there is one other expression that we should touch on: the Angular safe navigation operator (
?.). This operator provides a convenient way to check for null values in lengthy property paths like so:
{{customer?.firstName }}
If the safe navigation operator finds a null value (here the customer), it stops processing the path but lets the application continue running. Without it, the application will crash when it reaches anything after the first null (here the customer name) and the view will not display. The safe navigation operator is especially helpful in situations where you are loading data asynchronously and it might not be immediately available to the view. The safe navigation operator will prevent the application from crashing and then load the data when it is available.
Learning interpolation and expressions was easy; now let's look at another framework construct that is being used by our sample app-data binding. We will be covering data binding in far more detail in the upcoming chapters. At this point, we will just touch briefly on the bindings that are used in the sample app we are building.
If we look through the HTML for the view, we will see several places where square brackets
[ ] are used. These are property bindings.
Let's look at the first of the bindings that we created:
<input type="number" [value]="guess" (input)="guess = $event.target.value" />
This binding works by linking the value of the
guess property in our component class to theÂ
value of the input field in the view. The binding is dynamic; so, as the value of the
guess property changes, theÂ
value of the input field will be synchronized to the same value. And, we do not have to write any code to do that.
At the outset, when we initialize the game, this property is set to null in the initialization method of the component class, so we will not see anything in the input field. However, as the game progresses, this number will be updated with the value of the guess as it changes.
Looking again at the HTML view, we find several places where parentheses
( ) appear. These are event bindings.
Let's look at the HTML code line that we created for the first of these event bindings. It should be familiar since the event binding is on the same tag that we first looked at for property binding:Â the
input tag:
<input type="number" [value]="guess" (input)="guess = $event.target.value" />
In this case, the
input event of the input element is bound to an expression. The expression sets the
guess property in our component class to
$event.target:
<button (click)="verifyGuess()" class="btn btn-primary btn-sm">Verify</button> <button (click)="initializeGame()" class="btn btn-warning btn-sm">Restart</button>
These two event bindings tie the
click events for the buttons on the screen to methods in our component. So in this case, behind the scenes, Angular sets up event handlers that bind directly to the methods in our component. When the Verify button is clicked, the
verifyGuess method is called, and when the Restart button is clicked, the
initializeGame method is called.
As you work through the samples in this book, you will see many places where the
[] tags for property bindings are combined with the
() tags for events. In fact, this pairing is so common that, as we will see later, Angular has come up with a shorthand syntax to combine these tags into one.
Next, we'll examine something that looks similar to data binding but incorporates an Angular feature we have haven't seen before: structural directives:
<div> <p * Your guess is higher.</p> <p * Your guess is lower.</p> <p * Yes! That"s it.</p> </div>
*ngIf inside the
<p> tags is the
NgIf structural directive. Structural directives allow us to manipulate the structure of DOM elements. The
NgIf directive removes or adds DOM elements based on the result of an expression that is assigned to it.
Note
The asterisk
* in front of
ngIf is a simplified syntax that Angular, under the hood, expands into an HTML5
<template>. We'll be learning a lot more about this syntax and about structural directives in the next chapter.
In this case we are using
NgIf with a simple expression, similar to the types of expression we saw with interpolation. The expression resolves to either
true or
false based on the value of the guess being made and its relation (higher, lower, or equal) to the correct number. It then assigns that result to
NgIf, which will either add the DOM element if the result is
true or remove it if it is
false.
So now that we have looked more closely at what makes up our view, let's take another look at our app when it is up-andIfÂ directives and the expressions assigned to them from the paragraphs below the input box and refreshing the app in the browser.
Angular differs from other template frameworks, in that these bindings between a component and its view are live. Changes made to the properties of the component update the view. Angular never regenerates the HTML; it just works on the relevant part of the HTML and updates only the HTML elements that need to change as component properties change. This data binding capability makes Angular an exceptional view templating engine too.
If we go back and look at the code for our class, we will see that the properties and methods in the class do not directly reference the view. Instead, the methods simply operate on the properties in the class. As a consequence, the code for our class is more readable, hence more maintainable (and of course, testable).
So far, we have discussed how Angular updates the view based on changes in a component's properties. This is an important concept to understand as it can save us from countless hours of debugging and frustration. The next section is dedicated to learning about change detection and how these updates are managed.
First, let's look at how we maintain the state in our Angular application. Since Angular apps are dynamic and not static, we need to understand the mechanisms that are used to make sure that these dynamic values are kept up-to-date as the data in an application gets updated. For example, in our application, how does the number of guesses get updated on the screen? How does the application decide to display the correct message about whether the guess is correct based on the user input?
Since we have been emphasizing so far that Angular uses the component design pattern, you will probably not be surprised to know that the basic container for the application state is the component itself. This means that when we have a component instance, all the properties in the component and their values are available for the template instance that is referenced in the component. At a practical level, this means that we can use these values directly in expressions and bindings in the template without having to write any plumbing code to wire them up.
In the sample app, for example, to determine what message to display, we can use
deviation directly in the template expression. Angular will scan our component to find a property with that name and use its value. The same is true for
noOfTries; Angular will look for the value of this property within our component and then use it to set its value in the interpolation within the template. We don't have to write any other code:
template: ` ............. > `
So how does Angular keep track of changes in our component as it runs? So far, it appears as if this is all done by magic. We just set up our component properties and methods, and then we bind them to the view using interpolation along with property and event binding. Angular does the rest!
But this does not happen by magic, of course, and in order to make effective use of Angular, you need to understand how it updates these values as they change. This is called change detection, and Angular has a very different approach to doing this than what previously existed.
If you use the debugger tool in your browser to walk through the application, you will see how change detection works. Here, we are using Chrome's developer tools and setting a watch for the
noOfTries property. If you place a breakpoint at the end of the
verifyGuess() method, you will see that when you enter a guess, the
noOfTries property is first updated as soon as you hit the breakpoint, like this:
Once you move past the breakpoint, the display on the screen updates with the correct number of guesses, as seen in the following screenshot:
What is really going on under the hood is that Angular is reacting to events in the application and using change detectors, whichÂ go through every component to determine whether anything has changed that affects the view. In this case, the event is a button click. The event generated by the button click calls the
verifyGuess() method on the component that updates the
noOfTries property.
That event triggers the change detection cycle, which identifies that the
noOfTries property that is being used in the view has changed. As a result, Angular updates the element in the view that is bound to
noOfTries with the new value of that property.
As you can see, this is a multistep process where Angular first updates the components and domain objects in response to an event, then runs change detection, and finally rerenders elements in the view that have changed. And, it does this on every browser event (as well as other asynchronous events, such as XHR requests and timers). Change detection in Angular is reactive and one way.
This approach allows Angular to make just one pass through the change detection graph. It is called one-way data binding, and it vastly improves the performance of Angular.
Note
We'll be covering Angular change detection in depth in Chapter 8, Some Practical Scenarios. For a description of this process by the Angular team, visit.
We touched on app initialization earlier when we created the
app.module.ts and
main.ts files. The first file wraps our application in a module and the second file bootstraps that module. Now we will take a more detailed look at the initialization process.
Let's go back to the
index.html page again and take a look at the following script tags on this page:
<script src="[email protected]/dist/system.js"></script> <script src="systemjs.config.js"></script>
The first tag indicates that we will be using a JavaScript library called SystemJS in our application. The second tag references a file within our application that sets the configuration for SystemJS.
As we mentioned earlier, ES2015 introduced a new syntax for module loading. One attractive feature of ES2015 module loading syntax is that it allows for modules to be loaded selectively and asynchronously. We will be using module loading throughout our application.
TypeScript supports the ES2015 module loading syntax, and SystemJS allows us to add module loading to applications that run ES5. Putting the two together:
TypeScript will transpile (compile) our application's components to ES5
SystemJS will load them as ES5 modules
As part of this process, each of our TypeScript files will be compiled to a SystemJS module. SystemJS will then load all the related dependencies and when requested the module itself.
Note
Other module loaders exist, including Webpack, so you are not limited in your choice of module loaders to SystemJS. For more information on using Webpack with Angular refer to the following documentation on the Angular site:.
Open
systemjs.config.js. You will see that it contains mappings that indicate where SystemJS should look for the files that are needed in our application:
map : { 'app': 'app', 'rxjs': '[email protected]', '@angular/common': '[email protected]', '@angular/compiler': '[email protected]', '@angular/core': '[email protected]', '@angular/platform-browser': ' [email protected]', '@angular/platform-browser-dynamic': ' [email protected]' },
First, we map our own application, app, to the directory in which it resides. Then we add mappings for RxJS and several Angular modules. They are being downloaded from a content delivery network (CDN), the Node Package ManagerÂ () CDN. As you can see, we are using the
@ notation with the Angular modules. As we mentioned before, this means we will be importing Angular barrels containing multiple modules.
Note
The module bundles that Angular identifies as barrels are referred to as scoped packages in NPM. For a description of how Angular is using NPM scoped packages, visit.
Next, we identify the packages that we will be importing and their main entry points. In the case of our
app package, we indicate that
main.ts will be the entry point and
ts will be the default extension since we are using TypeScript for it. Then we identify the specific Angular
@barrels that we will be using in our application:
packages:{ 'app': { main: 'main.ts', defaultExtension: 'ts' }, '@angular/common': { main: 'bundles/common.umd.js', defaultExtension: 'js' }, '@angular/compiler': { main: 'bundles/compiler.umd.js', defaultExtension: 'js' }, '@angular/core': { main: 'bundles/core.umd.js', defaultExtension: 'js' }, '@angular/platform-browser': { main: 'bundles/platform-browser.umd.js', defaultExtension: 'js' }, '@angular/platform-browser-dynamic': { main: 'bundles/platform-browser-dynamic.umd.js', defaultExtension: 'js' }, },
These packages will be all we need to run our application. As you move to more sophisticated applications, more packages will be required. But you only need to add what is required to get the application running and this is what we are doing here. The flexibility to select just the packages that you need helps to minimize the size of the download, always a good thing for performance.
The file also contains the following script that directs SystemJS to transpile our TypeScript files:
transpiler: 'typescript', typescriptOptions: { emitDecoratorMetadata: true }
Note
This script will transpile our TypeScript files in the browser, which we would typically not do in a production app. Also, in order to keep the setup of our application as simple as possible, we are downloading the Angular modules and other libraries on-the-fly as the browser loads. In a production application, we would move both these steps into a build process that takes place before the application is launched in the browser. This will reduce the download size of the application and improve performance. We will be exploring setting up such a build process in Chapter 2, Building Our First App âÂ 7 Minute Workout.
We then implement the module loading for our app by adding the following script to our
index.html file:
system.import('app').catch(function(err){ console.error(err); });
The parameter being passed to our import statement
app is the location of our application, which in this case is the
app directory. Because we have indicated in
systemjs.config.js that
main.ts will be the entry point for our app, SystemJS will look for that file in the
app directory when the application first starts.
The next step in the initialization process is to bootstrap our application. As the entry point for our app,
main.ts does that by executing the following code:
platform.bootstrapModule(AppModule);
Not surprisingly, we are bootstrapping
AppModule. As we already know, bootstrapping instantiates
GuessTheNumberComponent because it has been assigned to the bootstrap property within
AppModule.
Note
This makes
GuessTheNumberComponent the root component for our application. While our app has only one component, every Angular application typically starts off with one root component.
We identify where this component will appear using the following syntax in our
index.html file:
<my-app>Loading...</my-app>
As you might recall, the
@Component decorator for our component identifies the component's selector:
@Component({ selector: 'my-app'
Taken together, these indicate to Angular that when our page is loaded, it needs to bind our component to the
my-app tag in
index.html. Note that here we are using a custom element based on the Web Components standard.
So, this starts the bootstrapping process, which continues as follows:
Angular scans our component definition and imports the modules that we have identified in the
importstatement of our component along with its related dependencies. These are the modules that we discussed earlier.
It compiles the HTML view, starting from where the
my-apptag is declared. In this compilation process, the framework traverses the template, looks for all interpolations, and sets up the binding between the view and our class.
Post compilation, it links the view and our component class where changes are synced across the model and viewed in real time as we interact with the app.
Tools make our lives easy, and we are going to share some tools that will help you with different aspects of Angular development, from code writing to debugging:
Augury ( ): This is a Chrome Dev Tools extension for debugging Angular applications. While the developers of the tool, rangle.io, indicate that it should be treated as a preview, it does support the Angular final release.
Browser developer console: All current browsers have excellent capabilities when it comes to JavaScript debugging. Since we are working with JavaScript, we can put in breakpoints, add a watch, and do everything that is otherwise possible with JavaScript. Remember that a lot of errors with code can be detected just by looking at the browser's console window.
JSFiddle and Plunker: JSFiddle () and Plunker () are excellent playgrounds for trying out HTML, CSS, and JavaScript code. These tools also have great versioning and sharing capabilities that can come in handy if we want someone's help.
IDE extensions: Many of the popular IDEs on the market have plugins/extensions that make Angular development easy for us. Examples include:
JetBrains WebStorm 2016:2.3:.
Angular2 Snippets for Sublime Text:.
Atom Angular 2 Snippets and Completions:.
Visual Studio Code: This is a brand new IDE that Microsoft has come up with (). It provides excellent IntelliSense and code completion support for Angular and TypeScript. Visual Studio 2015 () also includes support for Angular and TypeScript.
The Angular community is also developing CLI tools () with the goal of taking the developer from the initial project setup all the way to the final deployment. We'll cover using Angular CLI in Chapter 8, Some Practical Scenarios.
Component vendors are starting to offer support for Angular as well. For example, Telerik has released Kendo UI for Angular:.
Angular is a new framework, but already a vibrant community is starting to emerge around it. Together with this book, there are also blogs, articles, support forums, and plenty of help. Some of the prominent resources that will be useful are explained as follows:
Framework code and documentation: The Angular documentation can be found at. The documentation is a work-in-progress and not fully finalized. Then, there is always the Angular source code, a great source of learning. It can be found at.
The Angular team's blog: You can refer to the Angular team's blog for more information about Angular 2 at.
Awesome Angular: A curated list of awesome Angular resources: This is a new community resource at.
The Angular Slack channel ( ) and the gitter chat room ( ): These are other great resources. Also check out Angular on Reddit:.
The Angular Google group ( ) and the Stack Overflow channel ( ): Head over here if you have any questions or are stuck with some issue.
Built with Angular ( ): People have already created some amazing apps using Angular. This site showcases such apps, and most of them have source code available for us to take a look at.
That's it! The chapter is complete and it's time to summarize what you've learned.
The journey has started and we have reached the first milestone. Despite this chapter being named Getting Started, we have covered a lot of concepts that you will needÂ to know in order to understand the bigger picture. Your learning was derived from our Guess the Number! app, which we built and dissected throughout the chapter.
You learned how Angular implements the component design pattern using the emerging standards for Web Components, along with the latest versions of JavaScript and TypeScript. We also reviewed some of the constructs that are used in Angular, such as interpolation, expressions, and the data binding syntax. Finally, we took a look at change detection and app initialization.
The groundwork has been laid, and now we are ready for some serious app development on the Angular framework. In the next chapter, we will start working on a more complex exercise and expose ourselves to a number of new Angular constructs.