Skip to content

Introduction to Components

Adarsh Kumar Maurya edited this page Dec 11, 2018 · 2 revisions

Introduction

In the last module we set up the infrastructure of our Angular application. Now we are ready to build our first component. Welcome back to Angular: Getting Started. We walk through building a very basic component with a focus on clearly defining the component's parts, their meaning, and their purpose.

We can think of our Angular application as a set of components. We create each component, then arrange them to form our application. If all goes well, those components work together in harmony to provide the user with a great experience.

- What is a Component?
- Creating the Component Class
- Defining the Metadata with a Decorator
- Importing What We Need
- Bootstrapping Our App Component

In this module we take a closer look at :

  • What an Angular component is and examine the code we need to build one.
  • We walk through how to create the component's class
  • And how and why we need to define metadata.
  • We look at how to import what we need from external module and
  • We discover how to Bootstrap the app component to bring our application to life.

We'll continue to add to this application throughout this tutorial.

                              Application Architecture


                               -> Welcome Component
                              |
 index.html -> App Component->|-> Product List Component ---
                              |           |                  | --> Star Component
                              |           V                  |  
                               -> Product Detail Component---
               Product Data
                 Service

Looking again at our application architecture that we defined in the first module, the Angular CLI created the index.html file and the App component. In this module we'll rebuild this app component. Let's get started.

What Is a Component?

Component = Template + Class{Properties:data, Methods:logic} + Metadata

Template
 - View Layout
 - Created with HTML
 - Includes binding and directives

Class
 - Code Supporting the View
 - Created with Type
 - Properties: data
 - Methods: logic

Metadata
 - Extra data for Angular
 - Defined with a decorator

An Angular component includes

  • a template which lays out the user interface fragment defining a view for the application. It is created with HTML and defines what is rendered on the page. We use Angular binding and directives in the HTML to power up the view. We'll cover binding and directives in a later module.
  • Add to that a class for the code associated with the view. The class is created with TypeScript. The class contains the properties or data elements available for use in the view. For example, if we want to display a title in the view, we define a class property for that title. The class also contains methods, which are the functions for the logic needed by the view. For example, if we want to show and hide an image we'd write the logic in a class method.
  • A component also has metadata, which provides additional information about the component to Angular. It is this metadata that defines this class as an Angular component. The metadata is defined with a decorator. -- A decorator is a function that adds metadata to a class, its members, or its method arguments.

So a component is a view defined in a template, its associated code defined with a class, and metadata defined with a decorator.

Want to see what a component looks like in TypeScript? Here is a simple component.

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

@Component({
  selector: 'pm-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Angular: Getting Started';
}

It might look complex at first so let's break this component into chunks, starting at the bottom.

export class AppComponent {
  pagetTitle:string = 'Angular: Getting Started';
}

Here is our class. It defines the properties and methods needed by our view.

Here is the component decorator that defines the metadata.

@Component({
  selector: 'pm-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

The metadata includes the template that lays out the view managed by this component.

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

And here we import the members that we need.

Let's examine each of these chunks in more detail, starting at the bottom with the class.

import { Component } from '@angular/core';    | -> Import
                                              |
@Component({                                  
  selector: 'pm-root',                        |
  templateUrl: './app.component.html',        | -> Metadata & Template
  styleUrls: ['./app.component.css']          |
})                                            |
export class AppComponent {        
  pageTitle:string = 'Angular: Getting Started';         | -> Class
}                                             |

Creating the Component Class

import { Component } from '@angular/core';
@Component({
  selector: 'pm-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

If you have done any object-oriented programming in languages such as C#, VB.NET, Java, or C++, this code should look familiar.

export class AppComponent {
  pageTitle:string = 'Angular: Getting Started';
}

A class is a construct that allows us to create a type with properties that define the data elements and methods that provide functionality. We define a class using the class keyword followed by the class name.

A common Angular convention is to name each component class with the feature name, then append the word component as the suffix.

Also by convention, the root component for an application is called AppComponent as shown here. This class name is used as the component name when the component is referenced in code.

The export keyword here at the front exports this class, thereby making it available for use by other components of the application.

And as we learned in the last tutorial module, since this file exports something, this file is now an ES module.

export class AppComponent {
  pageTitle: string = 'Angular: Getting Started';
}

Within the body of the class are the properties and methods. In this example, we only have one property and no methods.

  • A property defines a data element associated with a class. We start with the property name which by convention is a noun describing the data element and it is in CamelCase whereby the first letter of the name is lowercase. In this example it is the title of the page. Using TypeScript's strong tying, we follow the property name with a colon and its data type. In this example, the page title property is a string. We can optionally assign a default value to the property as shown in this example.

  • Methods are normally defined within the class body after all of the properties. Method names are often verbs that describe the action the method performs. Method names are also in CamelCase whereby the first letter of the name is lowercase. So that's it for the class, but a class alone is not enough to define a component.

We need to define the template associated with this component class. How do we provide this extra information to Angular? With metadata. Let's look at that next.

Defining the Metadata with a Decorator

A class becomes an Angular component when we give it component metadata. Angular needs that metadata to understand how to instantiate the component, construct the view, and interact with the component.

We define a component's metadata with the Angular component function. In TypeScript we attach that function to the class as a decorator. Decorator

  • A decorator is a function that adds metadata to a class, its members, or its method arguments.
  • A decorator is a JavaScript language feature that is implemented in TypeScript.
  • The scope of the decorator is limited to the feature that it decorates. A decorator is always prefixed with an @ sign.

Angular has several built-in decorators we use to provide additional information to Angular. We can also build our own decorators, but that is out of the scope of this tutorial.

We apply a decorator by positioning it immediately in front of the feature we are decorating. When decorating a class as in this example we define the decorator immediately above the class signature. Notice that there is no semicolon here.

@Component({
  selector: 'pm-root',
  template : `
   <div style="text-align:center">
    <h1>
       Welcome to {{pageTitle}}!!
    </h1>
  ... Starter Files ...
</div>
`
})

// export class AppComponent {
//   pageTitle: string = 'Angular: Getting Started';
// }

This syntax is similar to attributes used in other programming languages.

  • We use the @Component decorator to identify the class as a component.
  • Since the decorator is a function, we always add parentheses.
  • We pass an object to the component function as indicated with the curly braces. The object we pass in has many properties. We are only using two of them here.
  • If we plan to reference the component in any HTML, we specify a selector. The selector defines the component's directive name. A directive is simply a custom HTML tag. Whenever this director is used in the HTML, Angular renders this component's template. We'll see how this works in the upcoming demo.
  • A component should always have a template. Here we define the layout for the user interface fragment or view managed by this component. The double curly braces indicate data binding. We bind the h1 element value to the page title property of the class so when this HTML is rendered, the h1 element displays Angular: Getting Started. We'll see that in the upcoming demo as well and we'll cover more about binding in a later module. There is one more key task before our component is complete. Importing.

Importing What We Need

  • Before we can use an external function or class, we need to define where to find it.
  • We do that with an import statement.
  • The import statement is part of ES 2015 and implemented in TypeScript. It is conceptually similar to the import statement in Java or the C# using statement.
  • The import statement allows us to use exported members from external modules.

Remember how we just exported our class using the export keyword? That means that other modules in our application can import our exported class if needed.

We'll use the import statement throughout our code to import any third-party library, any of our own modules, or from Angular itself.

@angular/core
@angular/animate
@angular/http
@angular/router

We can import from Angular because Angular is modular. It is a collection of library modules. Each library is itself a module made up of several related feature modules. When we need something from Angular, we import it from an Angular library module just like we import from any other external module. Use this link if you want to view the list of available Angular library packages and their current versions.

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

@Component({
  selector: 'pm-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Angular: Getting Started';
}

In our component code we use the component decorator function from Angular to define our class as a component. We need to tell Angular where to find this function so we add an import statement and import component from Angular Core like this. We start with the import keyword. We identify the name of the member we need within curly braces. In this case we need the component decorator function and we define the path to the module containing that member. In this case the Angular Core library module. If we need multiple members from the same module, we can list them all in the imports list separated by commas. We'll see examples of that later in this tutorial. So this is a component. Now we're ready to build the first component for our sample application. Let's jump in.

Demo: Creating the App Component

In this demo we build our app component, which is the root component for our application. Here we are in the editor with the APM folder open. This is the folder we set up in the last module from the starter files I provided. Let's open the src folder and under that, the app folder. Since I used the Angular CLI to create the starter files, it created the root app component. It named the file app.component.ts.

The file naming convention that we'll follow throughout this tutorial is to start with the feature name. This is our root application component so by convention it's called app, then a dot, then the type of ES module defined in this file, in this case, component to identify this ES module as a component, another dot, and the extension. Since we are using TypeScript, we'll use ts as the extension. Let's open that file.

In VS Code I can click the Explorer icon to close the explorer and see more of the code. I can reopen the Explorer by clicking the icon again. Now I'll delete the starter code for this file so we can build the app component from scratch.

I like to start coding by building the class, but the order of these steps really doesn't matter. When we build a class, we first type in the export keyword to ensure that other parts of the application can use this class. Next we type in the class keyword, then the name of the class. Since this is our application component class, we'll follow conventions and name it AppComponent. Inside this class we'll define one property, the page Title. We type the property name followed by a colon and the property data type, which for the pageTitle is a string. Notice how IntelliSense helps us here.

export class AppComponent{
  pageTitle: string ='Softhinkers Product Management';
}

For this property we want to define a default value for the pageTitle.

Next we define the component decorator above the class. The component decorator always begins with an @ sign, then the name of the decorator and we're using the component decorator. The component decorator is a function so we type parentheses and we're going to pass in an object so we type in curly braces.

@Component({})
export class AppComponent{
  pageTitle: string ='Softhinkers Product Management';
}

Notice how TypeScript has underlined the component decorator and flagged it as an error. The error is, cannot find name component. Any guesses on what the problem is? If you said that we are missing the import statement, you are right. We need to import the component decorator from Angular Core. Now the error underline goes away and we can complete the metadata.

import {Component} from "@angular/core"
@Component({
selector: 'pm-root',
template: `
      <div><h1>{{pageTitle}}</h1>
            <div> My First Component </div>
       </div>
`
})
export class AppComponent{
  pageTitle: string ='Softhinkers Product Management';
}

In the component metadata we specify a selector for the name of this component when used as a directive in the HTML. Now that we've imported the appropriate module, we get IntelliSense for these properties. We set the selector to pm-root.

The current convention is to prefix each selector with something to identify it as part of our application so we selected pm for product management. We end with a name that represents this component so we used root since this is our root app component.

We'll see how to identify our desired selector prefix to the Angular CLI in the Building, Testing, and Deploying with the CLI module later in this tutorial.

Next we define the template. To specify another property here we enter a comma and then the name of the other property. We want to define the template. Any valid HTML can be specified in the template. We'll dive deeper into templates in a later module. So for this example, I'll just paste in the HTML and we're done. We have now created the first component for our application, yay! But how do we use it? How do we display its template?

Bootstrapping Our App Component

You may have heard the saying, pulling yourself up by your bootstraps, originally meaning to improve your situation by your own efforts.

Bootstrapping
 - Host the application
 - Defining the Angular module

In tech it has come to mean a self-starting process that loads and goes. We need to tell Angular to load our root component through a process that is called Bootstrapping.

  • We first set up the index.html file to host our application.
  • Then we define our root Angular module to Bootstrap our root component.

Single Page Application (SPA) Let's look at both of these steps. Most Angular applications have an index.html file that contains the main page for the application. This index.html file is often the one true web page of the application. Hence an application is often called a single-page application or SPA, but don't worry.

 - index.html contains the main page for the application
 - This is often the only Web page of the application
  - Hence an angular application is often called a Single Page Application (SPA)

It will look to the user like we have lots of pages as we saw in the demo at the beginning of this tutorial.

What we do is insert bits of HTML into the one HTML page defined in index.html.

Let's see how that works. Here again is our app component just shifted to the right.

import { Component } from "@angular/core";

@Component({
  selector: 'pm-root',
  template: `
    <div><h1>{{pageTitle}}</h1>
    <div>My First Component</div>
    </div>
  `

})
export class AppComponent {
  pageTitle: string = 'Softhinkers Product Management';
}

Recall that the selector is the name of the component when we use it as a directive in HTML and the template defines the HTML that we want to display.

<body>
 <pm-root></pm-root>
</body>

So in the index.html file we simply add the selector where we want our template displayed. Here in the template we call this a directive.

  • A directive is basically a custom element. As soon as the loading is complete, the HTML defined in the component template is inserted between the selector element tags and appears on the page, but how does the Angular compiler know about this custom HTML element?It looks in an Angular module.

Angular module

  • Angular modules help us organize our application into cohesive blocks of functionality and provide boundaries within our application.
  • They also provide a template resolution environment. What does that mean? -- When the Angular compiler sees a directive in a template, it looks to the Angular module for the definition so we declare the AppComponent in an Angular module so the compiler can find it. -- We also use the module to Bootstrap our startup component, which is our AppComponent and we want our application to work correctly in the browser so we add Angular's browser module to our Angular module's imports.
                                   /  Organization Boundaries
 BrowserModule ******> AppModule--|   
                         |   #     \   Template resolution environment
                         |   #
                         V   V
                     AppComponent

****> Imports
----> Bootstrap
####> Declarations


Okay, pictures are nice, but what does that look like in code?

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

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
  • Here is our application's root Angular module. As with most everything in Angular we define an Angular module using a class.
  • We identify the class as an Angular module by attaching the NgModule decorator and passing in metadata defining the details of this Angular module.
  • For the NgModule decorator, the properties are arrays.
    • In the declarations array we define which of our components belong to this module. By convention, our root application component, AppComponent, belongs to the application's root Angular module, AppModule, so we declare it here. We can add other components here as well. We'll cover best practices for organizing our application into Angular modules later in this tutorial. For now, all of our components will be declared here.
    • In the imports array we define the external modules that we want to have available to all of the components that belong to this Angular module. External modules could be modules provided by Angular, a third party, or our own Angular modules. Here we import BrowserModule, which every browser application must import.
    • Browser module register is important to application service providers such as error handling.
  • The Bootstrap array defines the startup component of the application, which is our AppComponent. The startup component should contain the selector we use in the index.html file, which in this case it does. Now let's check it out in this sample application.

Demo: Bootstrapping Our App Component

In this demo we'll set up index.html to host our application and examine the root Angular module that Bootstraps our AppComponent.

import { Component } from "@angular/core";

@Component({
  selector: 'pm-root',
  template: `
    <div><h1>{{pageTitle}}</h1>
    <div>My First Component</div>
    </div>
  `

})
export class AppComponent {
  pageTitle: string = 'Softhinkers Product Management';
}

Here we are back with our sample application exactly how we left it. Since I used the Angular CLI to create these starter files, the index.html file is already hosting our app component and the app.module.ts file already Bootstraps our app component. Let's take a look starting with the index.html file.

To host our application we use the component selector as a directive here within the body element. We can think of a directive as simply a custom HTML tag. Since I used the Angular CLI to create the starter files, the directive is already included here.

Now let's open the app.module.ts file.

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

import { AppComponent } from './app.component';

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

Here is the class and here is the NgModule decorator defining this class as an Angular module. The declarations array declares the AppComponent so that Angular can locate its selector. The imports array includes BrowserModule so the application runs correctly in the browser. The providers array is for services. We'll talk more about those later in this tutorial so it's empty here and the Bootstrap array lists our AppComponent as the starting component for our application. It looks like we are ready to run.

We saw in the last module how to start the application by typing npm start in a terminal or command window. When the root app component is loaded, the HTML from our component appears and the binding in that HTML is replaced with the value of our page title property. We now have a working, albeit very small, application.

Before closing the browser, let's take a moment and look at the browser developer tools. In Chrome I'll press F12. The exact tools you see here depend on the browser you are using. I'm using Chrome. Most modern browsers provide a console tab as part of the development tools. This is always the first place to look if the page does not appear as expected or doesn't appear at all. Errors, warnings, and other information is displayed here. Use the elements tab or DOM explorer to view the HTML displayed in the page. This is a depiction of the DOM or document object model. The document object model is a document model loaded into the browser and represents our HTML as a node tree where each node is a part of our HTML. Notice these scripts listed here. These aren't in our source index.html file. We'll talk about these bundles, what they are and how they got here in the Building, Testing, and Deploying with the CLI module later in this tutorial.

Here is our selector tag. Open the selector tag and we see the HTML that we defined in our component's template. This view is a great way to see the HTML for the rendered page. There is also a debugger option available here on the sources tab to view and debug our code. Since the Angular CLI uses Webpack, our TypeScript files are listed under the Webpack node here. And because the Angular CLI serve feature generates the map file, we can debug our TypeScript directly. We can set a break point, refresh the browser, and it hits that break point. We can step through and check the value of any of our properties. Click here to resume. Use these debugging features any time you need them. Now let's finish up this module with some checklists we can use as we build our own components.

Checklists and Summary

Angular is all about components so our first set of checklists are for building a component.

  • We create a class for the component with code to support the view.
  • We use a decorator to define the component metadata which includes the HTML for the component's template and - We import what we need from any third party library from our modules or from Angular itself.
  • When creating the component class, we give it a clear name. This is not only the name of the class, but the name of the component as well.
  • Be sure to watch the casing since JavaScript is case sensitive. By convention, using PascalCasing whereby every word of the name is capitalized.
  • It is common to append component to the end of the class name to make it clear that it is a component class. - Be sure to include the export keyword on the class signature.
    • Recall what the export keyword does? It makes the class accessible to be imported by other parts of the application.
  • If the component view displays data such as a title, the data element is defined as a property of the class.
  • To leverage TypeScript's strong typing, be sure to set the appropriate data type for each property and set a default value where appropriate. Use camelCase for property names with the first letter lowercase.
  • If the component view has functionality such as hiding and showing an image, the logic is defined as methods in the class. Use camelCase for method names with the first letter lowercase.
- Class -> Code
- Decorator -> Metadata
- Import what we need 

Class
 - Clear name (JavaScript is case-sensitive)
 - Use PascalCasing
 - Append "Component" to the name
 - export keyword 
Data in properties
 - Appropriate data type
 - Appropriate default value
 - camelCase with first letter lowercase
Logic in methods
 - camelCase with first letter lowercase

Metadata
- Component decorator
- Prefix with @; Suffix with ()
- selector: Component name in HTML
- Prefix for clarity
- template: View's HTML
- Correct HTML syntax
Import
- Defines where to find the members that this component needs
- import keyword
- Member name - correct spelling/casing
- Module path - Enclose in quotes, correct spelling/casing

How do we define the metadata for our component?

  • If you said a component decorator, you are right.
    • A class is not a component unless it has a component decorator. Be sure to prefix the decorator with an @. Since a decorator is a function, add parentheses and pass in the appropriate object properties. Use the selector property to define the name of the component when used as a directive in HTML. Be sure to prefix the selector for clarity. Note that the selector property is not needed if the component is not used in any HTML as we'll see later in this tutorial. Use the template property in the component metadata to define the view's HTML. Since we define the HTML in a string literal, we often get no IntelliSense or syntax checking, so take care to define correct HTML syntax. We'll see alternate ways to create the template for our component in the next module.
  • So why do we need to use import? The import statement tells Angular where to find the members that this component needs from any external modules. The import statement requires the import keyword followed by the member name and module path. Take care when defining the member name as it is case sensitive. The path to the module file must be enclosed in quotes and is also case sensitive, and remember that we don't need to specify the file extension.
  • So what do you do if you followed the steps but the sample application doesn't work for you? You follow the something's wrong checklist. First, press the F12 key in the browser to view the developer tools and check the console. The Angular error messages are often quite clear if you read past the initial line of technical details. Second, recheck your code. For any HTML, be sure the tags are all correctly closed and that all of the Angular directives are correctly spelled and cased. Angular directives are case sensitive. For the TypeScript code, be sure the braces are all properly closed and just like JavaScript, TypeScript is case sensitive so ensure everything has the appropriate case.

In this module we detailed what a component was and how to build one by creating a component class, defining the metadata, and importing what we need and we discovered how to Bootstrap the component we built to bring our application to life. Here again is our application architecture. In this module we rebuilt the app component and have the very basics of our application working. Next up, let's take a closer look at templates and how Angular can power them up with binding and directives as we start building the product list component.

Clone this wiki locally