Introduction to Angular - Basics
In this portion of the lesson we are going to start off light touching on a number of topics, some of which will be covered in more detail later (e.g. Components). You will need to have your Angular project up and running on the development server (ng serve from your project folder using the command line) and Visual Studio Code opened to your project.
If you are familiar with Visual Studio Code you may be wondering why we are using a separate command line for our development server instead of using the one inside Visual Studio Code.
It is a good idea to keep your Visual Studio Code command line available to run the Angular CLI commands needed to build your application. If you were running your development server through the VSCode command line and needed to add a new component, you would need to stop your server, add the component and then restart the server. By running your server in its own command line you can avoid this issue.
Introduction to app.component.ts
The app.component.ts file is the starting point for all the custom code in your Angular application. Any new components or functionality needed in your application must be initiated from this file. A good way to visualize this would be to imagine the app.component.ts as the trunk of a tree. Every branch stems from the trunk whether directly or from another branch that is connected to the trunk.
While it is technically possible to develop your entire application in the app.component files it is not recommended as you will lose all the reusable features that make Angular great. The app.component files should be used for initialization of other components and services and not contain significant program logic.
The initial app.component.ts only contains ten lines of code as shown below.
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'intro-to-angular'; }
The import statement on the first line adds the Angular "Component" functionality to our class. Without this line our app.component.ts would be nothing more than a basic TypeScript class. This import statement provides the functionality needed for the @Component decorator found on line 3.
The @Component decorator is Angular specific functionality that is responsible for turning our class into an Angular Component. Currently, the following features have been implemented in our component:
- The selector is set to 'app-root'. This will match the <app-root></app-root> element found in our index.html file. All components must have a selector to identify the component when being added to your HTML files.
- templateUrl represents the filename that contains the HTML portion of our component. The app.component (app-root element) has its HTML code stored in './app.component.html'. (Your HTML can be stored inside your class instead of a separate file by using the alternate template value instead of templateUrl. Simply delete templateUrl and add a template value with your HTML stored as a string.)
- styleUrls contains an array of SCSS stylesheet files you wish to use for your component. These styles are local to your component. If you do not wish to use a local style for any specific component you can remove the styleUrls value from the @Component decorator and delete the associated .scss file.
The export class AppComponent statement is responsible for any custom code declared in our component. Our component currently defines a public variable called title.
- If you haven't done so already, open the app.component.ts file in Visual Studio Code.
-
Remove the title variable from the class definition and edit your code so the class definition is as follows:
export class AppComponent { public name = 'John Simpson'; private _secret = 'Not for you'; }
- Open app.component.html and erase everything in the file.
-
Add the following content to app.component.html.
<h1>Hello {{ name }}</h1>
- Open your web browser to http://localhost:4200. You should see the text "Hello John Simpson" displayed in a large bold font.
Template Binding
Class variables can be bound to your HTML through template binding (e.g. {{ name }}), directive binding and property binding. The exercise we just completed uses template binding. Directive and property bindings will be discussed later as we continue the lesson.
Template binding inserts values into your HTML wherever you place your binding code. In our example we are simply displaying the content of the public name variable however any valid display functionality would have worked. For example {{ 4 + 4 }} would display the number 8 on screen.
Private vs. Public Variables
In our previous example we declared a public variable called "name" and a private variable called "_secret". If attempted to display the "_secret" variable in our HTML code we would see an error message indicating the Property '_secret' is private and only accessible within class 'AppComponent'.
The only place you can use a private variable (or private class) is inside the class that defines it. You can however create public methods to read and write to these variables from the HTML file.
-
Add the following line of code to your HTML directly below the "Hello {{ name }}" statement.
<p>The secret is {{ _secret }}</p>
You should see a red underline appear beneath the _secret variable in Visual Studio Code. TypeScript is great at showing you these types of errors inside your editor. Your dev server command prompt and web page will also display an error message. -
Modify the line you just created to remove the underscore and add another line to call a method called
"secretMethod()". Your completed HTML file should appear as follows:
<h1>Hello {{ name }}</h1> <p>The secret is {{ secret }}</p> <p>Using a standard method the secret is {{ secretMethod() }}</p>
Your editor will underline "secret" and "secretMethod()" as we have not yet created these methods. -
Return to your app.component.ts file and add the following code directly below your
declaration of the "_secret" variable.
// Return the secret as a standard method public secretMethod(): string { return this._secret; } // Return the secret as a get method public get secret(): string { return this._secret; }
Your web browser should have the following output.
Class Methods
The "secretMethod()" method we created is a standard class method. This method type allows you the ability to define incoming parameters as well as an output data type. In the "secretMethod()" example we have no parameters and a string output type.
Unlike standard JavaScript, the TypeScript language expects you to define the variable types for your incoming parameters and output type. Variable types can be any of the standard variable types or ones you create yourself.
The examples below demonstrate various methods that include parameters and output values. The value void indicates that no value will be returned.
// Has no parameters and no output public voided(): void { } // Two numbers as input, outputs the sum of the numbers public aPlusB(a: number, b: number): number { return a + b; } // Concatenate array of string values together and return as a string public csv(values: string[]): string { let csvValue = ''; values.forEach((value: string, index: number) => { csvValue += index === 0 ? value : ', ' + value }); return csvValue; }
The csv example above is much more advanced than anything we have discussed and uses the array specific forEach method, arrow functions ( () => {} ) and a TypeScript conditional operator. These topics will be covered in detail later.
Get/Set Methods
Get and Set methods give you the ability to treat a method like a variable. In our HTML, you may have noticed that our "secret" get method did not include parenthesis after the name where "secretMethod" did. This is because we decorated our "secret" method with the get prefix which indicates that a value must be returned and no input parameters are allowed.
If we wanted the ability to write to our private "_secret" variable, we would create a "set" method. The set method can accept a single input parameter and must not have an output. Values can then be assigned using our set method as if it were a variable.
-
Add the following line of code directly below your get secret method.
// Set the secret value public set secret(secret: string) { this._secret = secret; }
Variable Binding to Controls
Along with the template binding we have just discussed, Angular offers variable binding of HTML elements. These elements can be standard HTML elements such as the <input> control, or third party controls and ones you create yourself.
Variable binding of elements can either be one-way-in, one-way-out or two-way.
Variables being assigned to an HTML element are assigned inside square brackets [ ]. Some properties such as the title tag are write only and should be assigned with the square brackets when you want dynamic control of the content.
-
Change the content of your <p>The secret is {{ secret }}.</p> line to the following to see a message
when you hover over the secret paragraph
<p [title]="name + ' has a secret'">The secret is {{ secret }}.</p>
Some properties of your HTML elements are read-only and these output properties can be bound to variables and methods in your Angular application by wrapping parenthesis ( ) around the property. A great example of this is the (click) property which is emitted when an element is clicked by the user.
We are going to have a little fun with our last example by adding a click event to the paragraph showing the secret. If clicked the value of "_secret" is going to be cleared.
-
Change your secret line so it reads as follows:
<p [title]="name + ' has a secret'" (click)="secret = ''">The secret is {{ secret }}.</p>
- View your application in your web browser. When you click on the secret line you should see the secret disappear.
Two-Way Binding and ngModel
So far we have written values to an HTML element property and performed variable assignment during an outgoing response of the click element. Often however we would like to have a variable displayed and updated as activity happens on an element. For example, a text input element should be able to display the content of a variable and have the same variable updated as we type in new text. This is accomplished with two-way binding and ngModel.
ngModel is part of the Angular FormsModule and needs to be imported into app.module.ts before we can use it. Combined with two-way binding, we can simply assign a variable in the HTML to have it update as well as display the variable value.
-
Open your app.module.ts file and add an import line for the FormsModule included
in '@angular/forms'. This line can be put on line 3 of your file immediately after the BrowserModule import
line.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms';
-
Next, modify the imports section in app.module.ts to include FormsModule. This final
step will make the FormsModule available to all of our components in the application.
imports: [ BrowserModule, AppRoutingModule, FormsModule ],
-
Return to your app.component.html file and add the following line of code anywhere you
would like. I added it directly below the "Hello John Simpson" line.
<p>Enter a new Secret <input type="text" [(ngModel)]="secret"></p>
- Take a look at your running application. You will see a text box that you can use to enter a new secret. Go ahead and change the secret and you should see the two lines displaying your secret change to your new value.
[(ngModel)] does all the work needed to handle assignment and display of your variable. Any type of variable assignment is valid including assignment through get/set methods (what we did here), direct assignment to public variables, and assignment to arrays and objects.
info Stay Consistent
While the order of your import statements don't typically matter (there are some exceptions), it is a good idea to organize your app.module.ts file in a way that is consistent and easy to follow. I typically keep all external library code at the top of my imports and application specific imports at the bottom.
As you add new components and services to your application, the Angular CLI will place your new items at the bottom of the list.