Angular Core Concepts: Understanding The Basics

0

Angular is a big framework and that can be a bit overwhelming when you just get started with it. The size and alleged steep learning curve of the framework is why a lot of people never get started with it, and that’s a shame since it’s such an elegant framework to work with. Luckily it turns out you don’t need to know everything about the framework to build a decent app with it. With a few of the Angular core concepts you can build almost any application. Once you know the core concepts of Angular you can always dive deeper into the framework to optimize your code with more elegant and advanced solutions.

These Angular core concepts will be discuss:

In this post I will give a shot explanation and example for each of these topics. For some topics I will write a more detailed post where we do a deep dive into the nitty-gritty. Now without any delay lets start to learn about the Angular core concepts.

 

Angular CLI

One of the Angular core concepts is the command line interface or CLI. The Angular CLI is a tool created by the Angular team to create, build and deploy Angular applications with ease. In almost any case you want to use the Angular CLI to create and build your application. It gives you a ton of options and is created to give you the most optimized creation and build flow. To use the Angular CLI you need Node.JS 10.9.0 or later, so make sure you have this installed on your machine.

Install the Angular CLI by opening your command prompt and executing this command:

npm install -g @angular/cli

The Angular CLI is now globally installed on your machine. Now that the CLI is installed you can use the ng command in your terminal window. The most commonly used commands are the following:

ng new my-app-name

ng new <app name> will create a new Angular application for you. When you run this command you will be prompted with a few questions about the app configuration. Personally I go for SCSS and install the application with the router already added. We will not dive any deeper into the router in this post, but you can find out more here.

ng new Angular core concepts

Once the CLI has created the application go ahead and open the created folder in your code editor. You should find something like this:

The next command to learn about is the ng serve command.

ng serve -o

You run this command in the root folder of your project. The ng serve command will start a development server for you on http://localhost:4200/. By adding the -o flag to this command a browser window automatically is opened with your running application. This development server is equipped with hot reloading to improve your developers experience.

Now that your application is created and served in the browser, we want to add some stuff. To add new components, services, pipes, directives and so on, the CLI offers you the ng generate command. You can type ng generate or ng g for short. Some of the most frequently used generate commands are:

ng g component <component name>
ng g service <service name>
ng g interface <interface name>
ng g module <module name>

The last CLI command we will discuss in this post is the ng build command.

ng build
ng build --prod

The ng build command explains itself. This command is used to build your Angular application. You can add the –prod flag to build your application in production mode. In the package.json file you can add configuration settings for your build strategies. You can also use the CLI to configure your build by adding supported flags in the command.

For more on the Angular CLI you can visit the official Angular documentation about the CLI.

 

Angular modules

We created our application with the CLI, now lets have a look at some of the files it created for us. First we will learn about Angular modules. Modules are the ‘biggest building blocks’ for our Angular application. Modules help us to split the application into smaller grouped chunks. This helps to improve maintainability, load times and reduces costs because we only load modules that gets visited.

Basically modules are nothing more then a record of everything you want to use, group and load together. That means if you are working on a component listed in module A, you cannot use a something listed in module B. You also cannot list something on more then one module (beside from other modules).

When you want to use something in more then one module, you need to created a shared module. This shared module will hold everything you want to use in multiple modules. A good example of something you place in a shared module is a pop-up component or pipes and directives. Something generic that will be used in more then one section of your application.

The application you created with the CLI has one module file named: app.module.ts.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Each module we create in Angular has the @NgModule decorator. The decorator lets the Angular compiler know to handle this class as a module. Inside the decorator is an object to configure the module.

  • Declarations array: here you add all your components, pipes and directives
  • Imports array: here you list other modules you want to import and use inside this module
  • Providers array: here you list injectables, better know as services or providers (But we will provide services in the root and do not touch on providers in this post)
  • Bootstrap: this lists the component used to bootstrap the application (This is only listed in your root module)

Adding and lazy loading modules with the Angular CLI

If you want to add more modules, I highly recommend you use the CLI. The CLI will automatically add your new module as a lazy loaded module and creates a routing module for it. When a module is lazy loaded, it will only be loaded when a user visits this part of your application. The CLI will also create a component for the new module. To create a lazy loaded module we run the following command:

ng generate module customers --route customer-list --module app.module

This command will create a new folder named costumers. Inside this folder you will find a costumers module and a costumers-routing module. You will also find a costumer-list folder with a costumer-list component inside. This newly created module will be added as a lazy loaded module in the app.module routing file. To add the it in an other module then your app.module, just change the last parameter of the CLI command.

 

Angular components

Something that cannot be left out when learning about the Angular core concepts are components. Components are reusable UI elements that are use to build the views of your Angular application. Good use of components will help to reuse code as much and efficient as possible. This will result in a more maintainable and DRY code-base. Each component generated with the Angular CLI has a HTML, CSS, spec and TypeScript file.

The HTML file will be the visual representation, the CSS file is used for styling, the spec file is for testing and the TypeScript file is used to add logic to the component. Personally I like to split my components into 2 main folders; Pages and Page elements. You can also add folders with the CLI command by adding a path as a component name. The last name will be used for the component and every folder that is not found will be created. So lets create a component and some folders:

ng g component components/page-elements/list-item

If you run this command in the root of your project, the CLI will create a components folder, a page-elements folder and then list-item component. In your app.module the CLI added the component to the declarations array for you. The TypeScript file of the generated component it will look like this:

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

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Every component has a component decorator. This lets the Angular compiler know to handle this file as a component. Inside the decorator we find an object to configure the component. The default configuration has a selector, templateUrl and a styleUrls property.  You can add more options in there, but for now we will leave it like the CLI generated it. Under the component decorator we find the class that is used for the component. It has an empty constructor and implements the OnInit lifecycle hook. The ngOnInit method is a lifecycle hook that will run when the component gets initiated. In this post we will not go into lifecycle hooks any deeper, but for more you can visit the Angular documentation.

Now lets go to our app.component.html and replace the code in there with the list component:

<app-list-item></app-item-list>

If you save the file and go to the browser, you will see that the application has reload on http://localhost:4200/ and now you see: list-item works!

 

String interpolation and template expressions

Now that we have a component lets learn some core concepts Angular offers us for developing them. First we will learn about string interpolation and template expressions. String interpolation is outputting a string variable from your TypeScript file directly in your HTML. Temple expressions are short TypeScript expressions you can place in your HTML that get evaluated in the template. Both of these tools offer you a lot of extra flexibility in your HTML templates and make it much easier to output values.

Let start with an example of string interpolation.

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

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  itemName = 'Some item name';

  constructor() { }

  ngOnInit() {
  }

}

We added a property to our component named itemName and assigned it a value of ‘Some item name’. With string interpolation we can output the value directly in our HTML template. When we want to use string interpolation we add double curly brackets and place the variable name inside.

<p>
  {{itemName}}
</p>

If you save these changes and go to the browser you will see: Some item name. Template expressions work basically the same as string interpolation. The only difference is that the code between the double curly brackets is an expression that needs to be evaluated.

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

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  amountOne = 10;
  amountTwo = 15;

  constructor() { }

  ngOnInit() {
  }

  getDate() {
    return new Date();
  }

}
<div>
  <p>
    {{getDate()}}
  </p>
  <p>
    {{'Totals: ' + (amountOne + amountTwo)}}
  </p>
</div>

In the TypeScript file we added a simple method that returns a new Date object. We also added two properties with a number assigned to them. In the HTML template, we can call this getDate method and directly output the return value.

The two amount properties are a bit different. Here we first added a string displaying: Totals. After that we added (amountOne + amountTwo). The two properties are between round brackets because we want this to be evaluated separately and not added to the string. If we leave out the round brackets here this will be the output: Totals: 1015 and we want Totals: 25.  This happens because we added a string in front of the sum. Angular will now output a string and will add amountOne and amountTwo as string values, not as numbers. By placing the variables between round brackets the values get evaluated separately from the string and thus handled as numbers.

  <p>
    {{amountOne + amountTwo}}
  </p>

That will also output 25 and not 1015. Because there is no string added in front Angular will evaluate the variables as numbers and just output 25.

 

If statements in HTML templates

Another Angular core concept are structural directives. That might sound a bit scary, but structural directives are real easy and extremely powerful to use. A structural directive is an attribute you add to a block of HTML to modify or transform it in some way of form. The most important directive in Angular are the NgIf en NgFor directives.

First I will explain the NgIf directive. This directive is placed on a block of HTML to remove or add it in the DOM based on an expression. The HTML will only be shown when the value of the NgIf evaluates to true. Lets go back to the list-item component and change the code in our HTML and TS file to use the NgIf directive.

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

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  showDescription = false;

  constructor() { }

  ngOnInit() {
  }

}

First we clear out everything we added in our TS file and give the list item a boolean named showDescription. This boolean has a default value of false.

<div>
  <h1>Item Title</h1>
  <p *ngIf="showDescription;">Item description</p>
  <button (click)='showDescription = !showDescription'>Toggle description</button>
</div>

Next we change the HTML. We give the list-item a title, description and a toggle button. The toggle button gets a simple click event. Within the quotes of this click event we toggle the value of our showDescription boolean. Because this is a simple action to preform we add the logic in the HTML template, if you want to execute a more complicated function you can make a function call to a method in the list item class.

The NgIf directive is added on the <p> tag, do not forget to add the * in front of the ngIf or it will not work. Within the quotes of the NgIf directive we place our showDescription boolean. If showDescription is true the description will be shown and when the value is false it will be removed from the DOM. Click the button to toggle the description.

Angular does not only give us the ability for if statements, we can also preform if else statements in our HTML templates.

<div>
  <h1>Item Title</h1>
  <p *ngIf="showDescription; else elseBlock">Item description</p>
  <ng-template #elseBlock>The description is hidden</ng-template>
  <button (click)='showDescription = !showDescription'>Toggle description</button>
</div>

First we add a semicolon after the showDescription property and after that we add our else statement. This else statement must always point to the #someName of a ng-template tag. This is a special HTML tag Angular gives us to create if else statements among other things. Within this ng-template you can place as much HTML as you want. The ng-template element itself will be removed from the DOM on run-time.

 

For loops in HTML templates

Now let’s create a for loop in the HTML template with a NgFor directive. NgFor basically works the same as the NgIf directive but the effect is different. You place the directive on a block of HTML and the HTML will be outputted an x amount of times.

First lets create a new component with the CLI named list by running this command in the root of your project:

ng g c components/page-elements/list

Now change the HTML of your app.component.html to show the list component:

<app-list></app-list>

Now let’s create our list component. First we need an array to use in the NgFor directive. So lets go to the TypeScript file and add a listItems array to list class.

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

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {

  listItems = [
    {title: 'Title 1', description: 'Some description'},
    {title: 'Title 2', description: 'Some description'},
    {title: 'Title 3', description: 'Some description'},
    {title: 'Title 4', description: 'Some description'}
  ];

  constructor() { }

  ngOnInit() {
  }

}

Now we will use this array to output our list of items with only one piece of HTML and the NgFor directive.

<div class="listContainer">
  <div class="listItem" *ngFor="let item of listItems">
    <h1>{{item.title}}</h1>
    <p>{{item.description}}</p>
  </div>
</div>

In the HTML file we have a div that will serve as our list container. Inside this div we have one HTML representation of a list item (next we will replace this with our list-item component). On that HTML block we place our NgFor directive so that we output one list item for every item in our listItems array.

The ‘item’ variable we created in the NgFor loop can be used inside of the HTML block the NgFor is placed on. With template expressions you can output the values of the array effortlessly. If you go back to the browser you find 4 items with a title and description, one for each object in the listItems array.

In some cases you may want to access the index of the current iteration. A use case for this, might be to add a unique Id to each list item. Angular has a simple option to get the current index of each iteration. Close the for statement with a semicolon and add let i = index behind it like this:

<div class="listContainer">
  <div class="listItem" *ngFor="let item of listItems; let i = index">
    <span>Item: {{i}}</span>
    <h1>{{item.title}}</h1>
    <p>{{item.description}}</p>
  </div>
</div>

Now you can access the i variable inside the HTML block just like the item variable.

 

Component communication with input and output

To make optimal use of a component based app structure we need to have interaction between components. In our example, we want to use our list-item component to output the list items inside our list. To do this the list item component needs to be able to receive a list item to display. Communication between parent and child components is done with the input – output system of Angular. Child components can have input properties that receive a values from the parent and an output property that emits an event with an event object to the parent.

Lets start with an input for our list item component. We want to receive 3 properties, a title, a description and a boolean to show or hide the description. We could receive this as one single object, but I will split it up in 3 different input properties for this example.

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

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  @Input() title: string;
  @Input() description: string;
  @Input() showItem: boolean;

  constructor() { }

  ngOnInit() {
  }

}

We changed the showDescription boolean into an input property and added one for the title and description. Now lets change the HTML of the list item to use these input properties.

<div>
  <h1>{{title}}</h1>
  <p *ngIf="showDescription; else elseBlock">{{description}}</p>
  <ng-template #elseBlock>Discription is hidden</ng-template>
  <button (click)='showDescription = !showDescription'>Toggle description</button>
</div>

We took out the title and description and replaced them with template expression referring to the input variables. For the NgIf we did not have to change anything. Next we change the list component to use the list item and pass down the input values.

<div class="listContainer">
  <app-list-item
    *ngFor="let item of listItems"
    [title]="item.title"
    [description]="item.description"
    [showDescription]="true"
    >
  </app-list-item>
</div>

We added the app-list-item html tag in the list container and placed the NgFor directive on this tag. Then added the input properties using square brackets and passing them the values of the item property exposed to us by the NgFor loop. The list item component will receive these values and use them in the HTML template.

Component output

There are also a lot of cases where you want to send data from your child component to the parent component. For example if our list item has a vote button on it we might want to delegate the saving functionality for this vote to and other more ‘higher ordered’ component. Our list-item component should not know what it displays and can be used to display different types of items some of which may not even have the vote button displayed. Normally the list component would also delegate this up to an other higher ordered component, but for now we stop at this list component.

Let’s change our list item slightly to contain a vote button that is shown conditionally. We also want to add an output property so we can send an event to the list component every time a vote button is clicked. We also will add an other input so that our list item can receive an ID. This ID will be send back to the list component so it know what item is voted on.

<div>
  <h1>{{title}}</h1>
  <p>{{description}}</p>
  <button *ngIf="canVote" (click)='voted.emit(id)'>Vote for this item</button>
</div>
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-list-item',
  templateUrl: './list-item.component.html',
  styleUrls: ['./list-item.component.scss']
})
export class ListItemComponent implements OnInit {

  @Input() title: string;
  @Input() description: string;
  @Input() id: number;
  @Input() canVote: boolean;

  @Output() voted = new EventEmitter<boolean>();

  constructor() { }

  ngOnInit() {
  }

}

In the HTML we not emit a new event every time someone clicks on the vote button. When using an output property you always emit an event. This can be done in the TypeScript file inside a function, ore directly in the HTML as shown above. We can pass this output emit event one attribute that will be used as the event object in the parent component. Similar to the event object of a regular click event, only containing the value you pass it along. In our case we only pass it the ID we received as input.

Next we want to edit the list component. We want to change the listItems array a bit and add an ID and can vote boolean to it. We also add a method that will console log the item we voted for every time a vote button is clicked and we need to change the HTML to contain the output event and the new inputs. Output events are handled the same as any other event in the parent component. Instead of click, or drag (and so on) you just add the name of your output property between the round brackets.

<div class="listContainer">
  <app-list-item
    *ngFor="let item of listItems"
    [title]="item.title"
    [description]="item.description"
    [canVote]="item.canVote"
    [id]="item.id"
    (voted)='votedOnItem($event)'
    >
  </app-list-item>
</div>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {

  listItems = [
    {title: 'Title 1', description: 'Some description', canVote: true, id: 1},
    {title: 'Title 2', description: 'Some description', canVote: true, id: 2},
    {title: 'Title 3', description: 'Some description', canVote: false, id: 3},
    {title: 'Title 4', description: 'Some description', canVote: false, id: 4}
  ];

  constructor() { }

  ngOnInit() {
  }

  votedOnItem(idFromOutput) {
    console.log('Voted on ==>', this.listItems.find(item => item.id === idFromOutput));
  }

}

Now every time a button gets clicked, the voted event will be emitted by the list emit and received as an event by the list component. The parent component handles this event by calling a method votedOnItem that console logs the voted item. Now we have an input and output flow for our components. The parent can send data tot the child with input and the child can send data to the parent with output.

 

Angular Services and dependency injection

Services and dependency injection are the last topics of the Angular core concepts we will talk about in this post. They are one of the most powerful concepts Angular offers. Dependency injection is a mechanism that allows you to inject code into every part of your Angular application. One of the most common things to inject in Angular are services. An Angular service is nothing more than a TypeScript file with isolated functionality dedicated to one purpose that can be shared among all components, services and other Angular assets. Examples of this are services to make HTTP requests, or helper services with extra Array or Object functionalities and so on. But services are not the only thing that can be injected with dependency injection. It allow you to inject everything that is market with the injection decorator or has an injection token. This is to advanced for the scope of this article, we we will keep it to services.

In our example, lets create an array helper service. This service will hold a few methods the list component can use, but will be useful for many parts of your application. As with most things we will create this service with the Angular CLI.

ng g s services/array-helper
ng g s services/array-helper //<-- short version

This command will generate a services folder and within that an array-helper.service.ts file and a spec file for testing. The service we generated will look like this:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ArrayHelperService {

  constructor() { }
}

It has an injectable decorator letting the Angular compiler know to handle this as such and allow us to inject this class as a dependency and use it’s methods.  Inside this decorator we find a configuration object with the property providedIn and a value of root. This signifies that this services is provided in the root of our project and does not have to be added in any module file. If you remove this, you need to add the service in the module file where you want to make use of it. This can be useful to reduce the initially loaded bundle but is not necessary for most use cases.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ArrayHelperService {

  constructor() { }

  findByPropertyValue(array: any[], propertyToCheck: string, valueToFind: any) {
    return array.find(item => item[propertyToCheck] === valueToFind);
  }

  findIndexByPropertyValue(array: any[], propertyToCheck: string, valueToFind: any) {
    return array.findIndex(item => item[propertyToCheck] === valueToFind);
  }

  isFoundInArray(array: any[], propertyToCheck: string, valueToFind: any) {
    return array.findIndex(item => item[propertyToCheck] === valueToFind) >= 0;
  }
}

Now we have added some methods in the service lets inject it into the list component and make use of it. You inject dependencies in the constructor of a component. When you make them public you can use services in the HTML template and TypeScript file. If you inject a service as private they can only be used in the TypeScript file.

import { Component, OnInit } from '@angular/core';
import { ArrayHelperService } from 'src/app/services/array-helper.service';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {

  listItems = [
    {title: 'Title 1', description: 'Some description', canVote: true, id: 1},
    {title: 'Title 2', description: 'Some description', canVote: true, id: 2},
    {title: 'Title 3', description: 'Some description', canVote: false, id: 3},
    {title: 'Title 4', description: 'Some description', canVote: false, id: 4}
  ];

  constructor(private arrayHelper: ArrayHelperService) { }

  ngOnInit() {
  }

  votedOnItem(idFromOutput) {
    console.log('Voted on ==>', this.arrayHelper.findByPropertyValue(this.listItems, 'id', idFromOutput));
  }

}

We injected the service inside the constructor and replaced the functionality in our console.log. If you now go back to the app, everything should work the same only now the item is found by our service. Everywhere in you application you need to find something in an array by a property value, you can now inject this array-helper service and make use of this functionality.

I hope you found this post helpful and if you have any questions please leave a comment. I will get back to you as soon as possible. For more information and a deeper dive on some of these topics you can keep reading on our blog.

Share.

Leave A Reply