Angular Components Tutorial
In this Angular tutorial we learn about one of the most important parts of an Angular app, components.
We learn about the app-root component as well as how to create, use and delete custom components.
Lastly we take a look at how to inline HTML and CSS directly inside the component's model.
What are components
Components are small, reusable units of HTML, CSS and Javascript that are combined with each other to create a full application or webpage.
Let’s consider a search bar as an example. The search bar pulls data from a JSON file to show autocomplete suggestions as the user types.
Because the search bar is a standalone component, we can use it in the header and on a dedicated search page without needing to repeat any code.
This allows us to simplify the creation, maintenance and testing of big, complex apps and websites.
A component is typically made up of the following.
- An HTML file that defines the structure of the component.
- A CSS file that defines the style for the component.
- A TypeScript file that defines the Javascript functionality and logic for the component.
- A decorator to tell Angular that we want the class to be a component. The decorator also configures the component.
- A test file that we use to test the component with Jasmin.
- Registration in the decorator of the module where we want the component to live.
- An import of the component to make it available to the decorator.
The list above may seem complicated right now, but it’s actually very easy and we will go through the whole process step-by-step.
The app-root component
Our Angular application is built by composing it from custom components that we create.
The ‘app-root’ component is the component that basically holds our entire application. It’s the main component that we use to later add (nest) our own custom components.
On the one hand, it’s a normal Angular component, but on the other hand it’s also special, because Angular uses it to bootstrap the application.
The other components we create will not be added to the index HTML file like the ‘app-root’ component.
For example, the index HTML looks like the following.
...
<body>
<app-root></app-root>
</body>
...
Let’s say we create a custom component called ‘search’. We don’t add this component as a tag in the HTML code.
...
<body>
<app-root></app-root>
<search></search>
</body>
...
Instead, we add our custom ‘search’ component to the ‘app-root’ component by registering it in a module and adding it to another component.
More on that later, for now, let’s create a component.
How to manually create a custom component
Typically, we don’t manually create components. But, to understand how the system works, we will do it here.
1. Let’s start off by creating a folder for the component files to live in. We don’t technically have to do this, but it’s good practice to keep things separated and tidy.
Inside the app folder of our project, create a new folder called ‘search’.
In Visual Studio Code you can right-click on the ‘app’ folder in the explorer and select New folder from the flyout menu. You can also click on the ‘app folder to select it and click on the New folder button on the project toolbar.
2. Next, let’s create our TypeScript component file.
Our component is called ‘search’ so that’s what we will name our component files. Create a new file called ‘search.component.ts’ in the search folder and double-click it to open it up in the Editor window.
In Visual Studio Code you can right-click on the ‘app’ folder in the explorer and select New file from the flyout menu. You can also click on the ‘app’ folder to select it and either click on the New file button on the project toolbar or use the Ctrl + N keyboard shortcut.
A good naming convention is to add .component to the name. Angular is made up of many different types of things and this will help us to easily identify component files at a glance.
3. Next, we will create the TypeScript component class.
A component is simply a TypeScript class that Angular uses to instantiate component objects from. So let’s create a class called ‘SearchComponent’.
class SearchComponent {}
The naming convention is the same as the file name to help avoid name clashes throughout the application.
We will also export the class so that we can use it outside of this file. To do this we simply add the export keyword in front of the class definition.
export class SearchComponent {}
4. Next, we will add the Component decorator.
At the moment, our class is just a normal TypeScript class. Angular doesn’t have all the information it needs, so we can’t use it as a component yet.
We need to tell Angular that we want this class to be component by adding a special decorator that sets up and configures the component.
Decorators are a TypeScript feature that allow us to enhance our classes (or other elements).
Decorators are always prefixed with an @ symbol and include parentheses for any arguments it might need. They are written before, or more accurately above, whatever we want to decorate.
@decorator_name ()
The decorator we want to use is the @Component decorator that’s built into Angular.
@Component()
export class SearchComponent {}
Because the @Component decorator is an Angular feature, we need to import it so that TypeScript can use it.
To do this we import Component from the '@angular/core' package.
Angular ships with multiple packages that groups functionality. The core package includes the Component decorator functionality.
import { Component } from '@angular/core';
@Component()
export class SearchComponent {}
The import command specifies packages as a list between curly braces because we can import multiple items from a single package.
5. Next, we will set up and configure our component.
Now that we have the Component decorator available, we can set up and configure it with a Javascript object.
The first important field is the selector field. This is basically the HTML tag that we use later in our other component templates.
We can set up any name that we want, but we should ensure that the name is unique so that it doesn’t conflict with default HTML tags. Typically, we use the naming convention that prefixes the tag with ‘app-’.
We will call this one ‘app-search’ because it’s a search component.
import { Component } from '@angular/core';
@Component({
selector: 'app-search'
})
export class SearchComponent {}
The next important field we need is the HTML template.
We can either inline the HTML code or use a reference to an HTML file. For now we will reference a template file.
The file doesn’t exist yet so let’s create a file called ‘search.component.html’ in the search folder. We can add some simple HTML code in there just as demonstration.
<input class="search-field" name="query" id="query" type="search" aria-label="Search field" placeholder="Search">
Back in the configuration file we have to add the reference to the new HTML file in the decorator with the templateUrl property.
We specify a path relative to the search.component.ts file for when webpack bundles it in the end. The ./ part of the path means “The current directory”.
import { Component } from '@angular/core';
@Component({
selector: 'app-search',
templateUrl: './search.component.html'
})
export class SearchComponent {}
That’s all that is required to create a component.
6. Next, let’s register the component.
Before we can use the component, we need to register it first so that Angular knows it exists and where to find it.
We register the component in the app.module.ts file in the app folder so open it up in the Editor.
It should look something like the following.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Essentially, Angular uses modules to group the components that make up an application.
Angular gives us the default AppModule to group our components in. Big projects may require more than one module but for the majority of projects, this default AppModule will be enough.
If we look at the app.module.ts file we can see that the AppModule is just an empty class like our component. Like our component, it has a decorator above it, in this case the @NgModule decorator.
We have four fields in the decorator, but only two are important at this point.
- bootstrap is where we specify which component is the main component embedded in the index.html file that will run when the application starts.
- declarations is where we register our custom component.
We can see that the default AppComponent is already registered in the array of the declarations property. Even though it’s registered as the bootstrap component, it’s still a component and needs to be declared.
To register our custom component, we simply add the class name to the declarations array to register it.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent,
SearchComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
If we add the component and save the file, the compilation will fail and Angular will raise an error.
Cannot find name 'SearchComponent'.
That’s because we have to import the component so that TypeScript knows about it and can use it.
So, we simply add an import to the search.component.ts file at the top of the document.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { SearchComponent } from './search/search.component';
@NgModule({
declarations: [
AppComponent,
SearchComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Similar to Sass , we don’t specify the extension when we import a file. Webpack is smart enough to know that we mean the .ts file.
How to use a custom component
To use a custom component, we add its tag inside the HTML file of another component.
This can be done in a custom component like our ‘search’ component, or the default bootstrap ‘app’ component that’s created when we set up an Angular project.
If we want our component to be available when the application starts, we put it in the ‘app’ component.
At the moment, we have two components.
- The ‘app’ component.
- The ‘search’ component.
Let’s add our ‘search’ component to the ‘app’ component. Open both HTML files of both.
In the search.component.html file, add an H3 tag with the name of the component.
<h3>I'm the custom search component</h3>
<input class="search-field" name="query" id="query" type="search" aria-label="Search field" placeholder="Search">
In the app.component.html file, change the H1 text and add a horizontal rule.
This is also where we add the ‘search’ component. Remember that we use the name specified in the selector property of the component’s decorator in its .ts file. In our case, the name was ‘app-search’.
<h1>I'm the default App component</h1>
<hr>
<app-search></app-search>
If we save and check the browser, we can see that the ‘search’ component shows up underneath the horizontal rule.
That’s it, all we do to use a component is include its tag in the HTML file of another component we want to use it in.
For example, if we had a ‘header’ component, we could add ‘logo’, ‘search’ and ‘menu’ components to it. Then we could add the ‘header’ component to the default ‘app’ component so that it shows up when the application starts.
How to automatically create a custom component with the CLI
We don’t have to go through the whole process of creating folders, files, classes, imports and registration each time we want to add a component.
We can do it all in a single step with the CLI with the ng generate component command.
With this command we add the name of the component we want and the CLI will generate everything for us.
ng generate component name
As an example, let’s create a new component called ‘logo’.
Open a new terminal/command prompt and navigate into the project folder.
If you’re using Visual Studio Code, you can simply click on the + button to the right of the terminal panel to add a second one.
Now run the following CLI command to create a new component.
ng generate component logo
The terminal will show the following output.
CREATE src/app/logo/logo.component.html (19 bytes)
CREATE src/app/logo/logo.component.spec.ts (612 bytes)
CREATE src/app/logo/logo.component.ts (267 bytes)
CREATE src/app/logo/logo.component.css (0 bytes)
UPDATE src/app/app.module.ts (470 bytes)
We can also see in the Explorer that a new ‘logo’ folder was created in the ‘app’ folder with all the files needed for a component.
If we open the app.module.ts file, we will see that the component has also been registered. All that’s required from us is to create the structure, style and functionality of the component, and of course include it.
So, let’s create a simple text logo in the HTML with some styling in the CSS file.
<p>logo works!</p>
p { color: dodgerblue }
Now let’s also include that in the app.component.html file.
Remember the convention of writing the component name with a prefix of ‘app-’. The CLI also uses this convention so we can be sure that if we create a component called ‘logo’, its selector will be called ‘app-logo’.
<h1>I'm the default App component</h1>
<hr>
<app-logo></app-logo>
<app-search></app-search>
If we switch over to the browser, we can see that the new logo text is shown, and in the blue we styled it with.
How to inline HTML and CSS in the component script
Angular makes it possible for us to write our HTML and CSS directly in the component.ts file’s decorator.
At the moment we have links to the external HTML and CSS files in the templateUrl and styleUrls properties.
...
@Component({
selector: 'app-logo',
templateUrl: './logo.component.html',
styleUrls: ['./logo.component.css']
})
...
If we want to inline our template and styles, we have to use different fields.
- Instead of templateUrl , we use template for the HTML.
- Instead of styleUrls , we use styles for the CSS.
For both we also replace the quotes with backticks so that there’s no confliction in the code we write.
The backtick ` is above the TAB key and to the left of the 1 key on a standard US keyboard layout.
Backticks also allow us to break our inline code into multiple lines. Let’s try this out in our ‘logo’ component.
@Component({
selector: 'app-logo',
template: `<h3>Logo Text</h3>`,
styles: [`
h3 {
padding: 1rem;
font-size: 2.2rem;
color: #fafafa;
background: #121212;
}
`]
// Reference to external component files
// templateUrl: './logo.component.html',
// styleUrls: ['./logo.component.css']
})
The styles property always takes an array of styles or links to external files, it cannot be a single string like the template.
Also, inline styling will be added after any global or external component style and will, because of the cascade, override them.
So which should you use?
In most cases, we want a separation of concerns. That means we want to separate our templates, styles and functionality into different files.
Having everything inside a single file, like above, can become messy when there’s a lot of code.
It’s good practice to use the external files. That said, you should do what feels comfortable to you. The important thing is to stay consistent.
We will use the external files throughout this course.
How to delete a component
At the moment, there is no CLI command to automatically delete a component so we will have to do it manually.
To delete a component, we have to delete all of its files and the references to the files.
We have two components, ‘logo’ and ‘search’. These components consist of the following.
- The folder where the component files are stored inside src/app/.
- A reference in the decorator of the module that contained our components. By default, this is the app.module.ts file.
- The tags in the component we embedded our custom components in.
So let’s delete both components so that we’re only left with the default ‘app’ component.
1. Start off by deleting the two folders ‘logo’ and ‘search’ in the ‘app’ directory.
2. Next, open the app.module.ts file. It should look something like this.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { SearchComponent } from './search/search.component';
import { LogoComponent } from './logo/logo.component';
@NgModule({
declarations: [
AppComponent,
SearchComponent,
LogoComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
In the declarations property of the decorator, delete the SearchComponent and LogoComponent elements from the array.
We also have to remember to delete the component imports at the top so that our module now looks as follows.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
3. Now we have to find where we embedded our components and delete the tags.
In our case, we embedded the components in the default app.component.html file.
<h1>I'm the default App component</h1>
<hr>
<app-logo></app-logo>
<app-search></app-search>
We can simply delete them from the code.
While we’re editing this file, we can bring back the dynamic title from app.component.ts that it had in the beginning.
<h1>{{ title }}</h1>
<hr>
In bigger projects where a component may be embedded in many places, we can use our IDE’s Find, Find in files, or Find in project functions to find and then delete the tags.