AngularJS (versions 1.x) is a JavaScript-based open source Framework. It is cross platform and used to develop Single Page Web Applications (SPWAs). AngularJS implements the MVC pattern to separate the logic, presentation, and data components. It also uses dependency injection to make use of server-side services in client side applications.

Angular (versions 2.x and up) is a Typescript-based open source framework to develop front-end Web applications. Angular has features like generics, static-typing and also some ES6 features.

We recommend learning Angular and using it for new projects. AngularJS is mainly used for legacy projects.

The best way to learn Angular is with freeCodeCamp's 6-hour Angular Tutorial on YouTube.

Other tutorials on Angular

Angular 1.x

General Pages

Videos

Courses

Angular 2.x+

General Pages

Specific-topic Pages

  • Directives - Excellent guide going into detail on Angular Directives (Part 1)

Courses

Blogs

Version History

Google released the initial version of AngularJS on October 20, 2010. The first stable release of AngularJS was on December 18, 2017 of version 1.6.8. Angular 2.0 release took place on September 22, 2014 at the ng-Europe conference. One of the features of Angular 2.0 is dynamic loading.

After some modifications, Angular 4.0 was released in December, 2016. Angular 4 is backward compatible with Angular 2.0. HttpClient library is one of the features of Angular 4.0. Angular 5 was released on November 1, 2017. Support for progressive web apps was one of the improvements in Angular 4.0. Angular 6 was released in May 2018. The latest stable version is 6.1.9

Install:

We can add Angular either by referencing the sources available or downloading the framework.

Link To Source:

AngularJS: We can add AngularJS (Angular 1.x versions) by referencing the Content Delivery Network from Google.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> 

Download/install: We can download the framework with npm, Bower or composer.

Angular 1.x:

npm

npm install angular

Then add a <script> to your index.html:

<script src="/node_modules/angular/angular.js"></script>

bower

bower install angular

Then add a <script> to your index.html:

<script src="/bower_components/angular/angular.js"></script>

For more information regarding the documentation, refer to the official site of AngularJS.

You can install Angular 2.x and other versions by following the steps from the official documentation of Angular.

Components

Motivation

Angular contains many schematics for building applications. Components are one such schematic. They encompass a single unit of logic concerned with a single part of the application. Components often partner with other schematics to operate more effectively.

Among all schematics, components tend to consume more than they provide. While other schematics like directives, pipes, and services offer utility, components utilize. They are responsible for the application interface so it makes sense why they consume utility.

Components simplify the application. Funneling logic into a single section of the visible interface is their primary goal. To build applications step-by-step, you must build component-by-component. Components act as Angular’s building blocks, after all.

Components Introduction

As mentioned, components consume utility (services/resources). They stand between business logic and presentation to produce a cohesive unit. Angular attaches various mechanisms to each component. These attachments identify a class as a component and define its standard capabilities.

Angular must recognize components when it comes across them. To do this, @Component must decorate every class intended to be a component. Decorators indicate to Angular what the class is.

In the case of a component, it must know how to interact with its injector, connect with a template, pull from a list of styles, encapsulate its styles, and so on. Angular takes care of most of the low-level requirements. Developers still need to configure a component’s behavior, import its dependencies, and extend its logic.

For all such things, we have the component’s class. The class keeps everything relatively uniform. It encapsulates the component’s business logic.

Component Class and Metadata

Go ahead and install the Angular command-line interface (CLI). You can learn more about it from this article. The CLI command ng generate component [name-of-component] yields the following.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {
  constructor() { }

  ngOnInit() { }
}

This is the basic skeleton from which all great components originate. The @Component decorator is the most important part. Without it, the above example becomes a generic class. Angular relies on decorators to discern a class’s schematic type.

@Component receives metadata as a single object. Decorators are just JavaScript functions under the hood. They take in arguments as with the metadata object. The metadata object configures a component’s basic dependencies. Each fields plays a role.

  • selector: tells Angular to associate the component with a certain element in the application’s template HTML.
  • templateUrl: accepts the file location of the component’s template HTML (this is where data gets displayed to).
  • styleUrls: accepts an array of style-sheet file locations (strings). These style-sheets target the component’s assigned template.

Think of metadata as a big blob of configuration. The decorator takes it so that it can generate the data specific to the component. The decorator decorates the underlying class with data necessary for its class’s behavior. A component class that is.

The class’s signature exports by default so that the component can be imported. ngOnInit also gets implemented. implements tells the class to define certain methods per the interface’s definition. ngOnInit is a lifecycle hook.

Component Lifecycle and Change Detection

Components use all sorts of tools, services, and features. One key feature available to components is lifecycle hooks. An explanation for each hook exists in this article.

There are eight in total and they all serve as timing functions. They execute conditionally as the component transitions from state-to-state via change detection. This process happens constantly across the component tree. It searches for changes in data which merit a re-rendering of the template.

Time to move on. Please refer to the aforementioned articles for more information on the component lifecycle. It deserves much more explanation.

Component Data

Data drives everything. Components are no exception. Components encapsulate all their data. To receive data externally, a component must explicitly declare it. This form of privacy keeps information from clashing across the component tree.

Data determines what gets displayed from the component class to its template. Any updates to the class’s data will (or at least should) update the template display.

Components will often initialize a set of members (or variables) that store data. They are used throughout the component class logic for convenience. This information fuels the logic resulting in the template and its behavior. See the following example.

// ./components/example/example.component.ts

import { Component, OnInit } from '@angular/core';
import { Post, DATA } from '../../data/posts.data';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html'
})
export class ExampleComponent implements OnInit {
  username: string;
  totalPosts: number;
  allPosts: Post[];

  deletePost(index: number): void {
    this.allPosts.splice(index, 1);
    this.totalPosts = this.allPosts.length;
  }

  ngOnInit(): void {
    this.username = DATA.author;
    this.totalPosts = DATA.thePosts.length;
    this.allPosts = DATA.thePosts;
  }
}
<!-- ./components/example/example.component.html -->

<h1>{{ username }}</h1>
<span>Change Name: </span><input [(ngModel)]="username">
<h3>Posts: {{ totalPosts }}</h3>
<ul>
<hr/>
<div *ngFor="let post of allPosts; let i=index">
  <button (click)="deletePost(i)">DELETE</button>
  <h6>{{ post.title }}</h6>
  <p>{{ post.body }}</p>
  <hr/>
</div>
</ul>

Note the ways the component interacts with its data. It first fetches it from ../../data/posts.data before it begins to forward it to the template for display.

The data shows up throughout the template. Inside the double curly braces, a variable’s value is mapped from the component class into the braces. The *ngFor loops across the allPosts class array. Clicking on the button removes a specific element from allPosts by its index. You can even change the topmost username by typing into the input box.

The above interactions alter the component class’s data which in turn updates the component’s template HTML. Components provide the backbone logic that facilitates the flow of data. The template HTML makes that data readable to the user.

Component Template

The previous example’s template HTML featured an interesting syntax. The syntax was not actual HTML. It was Angular’s template HTML. Some often refer to it as HTML Plus, recognizable only by Angular’s compiler. The compiler supports a syntax resulting in the dynamic manipulation of HTML. This article will often refer to it as ‘template HTML’ or ‘template’.

The syntax lets components inject data directly into the template HTML. The injection is dynamic. This means that data can iterate and display itself as HTML without needing external assistance. The Angular compiler compiles it into real HTML by the time it reaches the web browser.

To learn more about some of the ways data binds to the template, read about data binding in Angular. A few examples of data binding occurred in the previous example ({{ ... }}). For this article, it is enough to recognize data interactions were happening between the component class and its template.

Querying the Template

Data managing the state of the template imperatively works OK. Yet, pure data does not always fulfill an application’s intended design. Interacting more directly with the Document Object Model (DOM) may be required.

To do that, the component must have reference to the template elements. When the data changes, the component can manipulate the DOM explicitly. This is a more declarative approach.

Components can grab references using a web browser’s DOM application programming interface (API). Bad idea though. Angular prefers cross-platform compatibility. For a component to function outside of the web browser, it needs to use Angular’s API instead of the DOM’s.

Components can query their templates using the @ViewChild and ContentChild decorators. They grab references to template elements on behalf of the component class.

import { Component, ViewChild, ContentChild, ElementRef, Renderer2, AfterContentChecked, AfterViewChecked } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `
  <button (click)="toggleEnlarge()">Toggle Enlarge</button>
  <ng-content></ng-content>
  `
})
export class ChildComponent implements AfterContentChecked {
  @ContentChild("pReference", { read: ElementRef }) pElement: ElementRef;
  textEnlarge: boolean = false;

  constructor(private renderer: Renderer2) { }

  toggleEnlarge() {
    this.textEnlarge = !this.textEnlarge;
  }

  ngAfterContentChecked() {
    if (this.textEnlarge)
      this.renderer.setStyle(this.pElement.nativeElement, 'font-size', '25px');
      else
      this.renderer.setStyle(this.pElement.nativeElement, 'font-size', 'initial');
    }
}

@Component({
  selector: 'app-parent',
  template: `
  <button (click)="toggleHighlight()">Toggle Highlight</button>
  <h1 #hOneRefereance>View Child</h1>
  <app-child>
    <p #pReference>Content Child</p>
  </app-child>
  `
})
export class ParentComponent implements AfterViewChecked {
  @ViewChild("hOneRefereance", { read: ElementRef }) hOneElement: ElementRef;
  textHighlight: boolean = false;

  constructor(private renderer: Renderer2) { }

  toggleHighlight() {
    this.textHighlight = !this.textHighlight;
  }

  ngAfterViewChecked() {
    if (this.textHighlight)
      this.renderer.setStyle(this.hOneElement.nativeElement, 'background-color', 'yellow');
    else
      this.renderer.setStyle(this.hOneElement.nativeElement, 'background-color', 'initial');
  }
}

The above example contains two buttons that toggle a certain style for each element. Clicking the buttons toggles the true/false values unique to each component. These booleans determine if the custom styles apply. Instead of these values causing changes imperatively, the lifecycle hooks (ngAfterViewChecked and ngAfterContentChecked) declaratively alter the DOM.

The declarative approach explicitly changes the style through the element’s reference. In imperative programming, changes to the DOM based off data are implicit. Check out this article on imperative and declarative programming to learn more.

The main thing to notice is how these references get pulled from the template. In the example, there are two sections of the template queried using two decorators: @ViewChild and @ContentChild.

They differ in where they look for an element’s reference whether it be in the content DOM or view DOM. These two DOMs exist in ParentComponent’s template. Differentiating between them is important because they finish rendering at separate times.

This is why @ViewChild and @ContentChild both exist. They work together with their companion lifecycle hooks ngAfterViewChecked and ngAfterContentChecked. These lifecycle hooks wait for their respective queries to resolve before executing.

Once resolved, @ViewChild and @ContentChild provide references to two elements. Both exist in separate parts of the DOM. The boolean data still determines the outcome. How that outcome translates to the DOM is the key difference from before. The DOM updates viaRenderer2’s direct manipulation of it.

Content Projection

The content DOM exists in the innerHTML of ChildComponent’s <app-child></app-child> element. It is all positioned within ParentComponent’s template. The innerHTML of app-child projects onto ChildComponent’s template through <ng-content></ng-content>.

This exemplifies content projection. Displaying content from one component to another using the innerHTML of another’s tags in one’s template so that another component can pull that innerHTML into its own template via <ng-content></ng-content>. Thank you for reading that sentence.

Hence why ChildComponent references its <p></p> element using @ContentChild. Content contained within <app-child></app-child> in ParentComponent’s template makes up the content DOM. ChildComponent references the element with an @ContentChild query.

ParentComponent’s view DOM consists of everything accessible from within the component’s view. This does not necessarily include the entire template given the innerHTML of <app-child></app-child>. Again, this part of the DOM is queried from ChildComponent using @ContentChild. Everything else gets queried using @ViewChild from the ParentComponent class.

This is a great way for components to exchange content and query their own content regardless of their DOM type. Components can communicate with themselves and others using data binding as well. Read more about it from this article.

Component Styles

Styles are critical to a component’s readability and interactivity. Each component encapsulates its style-sheet dependencies. That way they only apply to the component’s template HTML. A special technique introduced by HTML’s shadow DOM makes this possible.

A shadow DOM branch may exist on any element. This part of the DOM cannot be seen from the HTML’s source code. Standard HTML elements leverage the shadow DOM to provide their trademark appearances. A shadow DOM branch must anchor itself to a visible component so that it can style and customize it.

The unique aspect about a shadow DOM branch is its encapsulation. Everything used to style a shadow DOM branch’s root element is private to it. No other element can access it.

Angular embraces this form of encapsulation with components. The style-sheet and template of a component encapsulate together. No other components have access to them. Style-sheet clashes cannot occur.

Angular does not use the shadow DOM by default. It uses an emulation system that mimics the behavior of the shadow DOM. This is a temporary measure since some web browsers do not yet support the shadow DOM API.

The @Component metadata contains the encapsulation field. This lets developers toggle in-between emulated shadow DOM, real shadow DOM, or neither. Here are the options in their respective order:

  • ViewEncapsulation.Emulated - fake shadow DOM (default)
  • ViewEncapsulation.Native - real shadow DOM (now deprecated since Angular 6.0.8)
  • ViewEncapsulation.None - neither

ViewEncapsulation.None means the component’s style-sheets elevate to the global scope. Not recommended considering components should form their own private unit (encapsulation). Angular still provides it as an escape hatch for extreme situations.

Conclusion

Components build applications. They are privately scoped and separately uniform of each other unless configured otherwise. Applications tend to begin from the root module. Past that, components form an elongated tree defining the rest of the application.

A component covers a designated unit of the application interface. This includes its styles, logic, and layout. Other schematics such as pipes, services, and directives see frequent use in component code. You can learn more about these interactions in some of the other Angular guide articles.

Do not forget that components must bootstrap. This can happen in the root module or the component’s metadata. This is so Angular recognizes the component wherever it appears in the application.

You can always learn more, as components carry far more depth than that what this article could convey.