Working With Arrays
In the previous lesson, the basic components we tried created a new UserItemComponent
, to say “Hello” to a user. What if we want to say “Hello” to a list user’s name? In Angular, we can loop a list of objects in the template by using the *ngFor
syntax. The idea here is that we are going to loop the same type to a collection of objects.
If you have worked with AngularJS 1.X before, then you probably used
ng-repeat
directive.NgFor
works the same way.
Now we will create a new component to render a list of users.
1 2 3 4 5 6 7 8 | $ ng generate component user-list CREATE src/app/user-list/user-list.component.css (0 bytes) CREATE src/app/user-list/user-list.component.html (28 bytes) CREATE src/app/user-list/user-list.component.spec.ts (643 bytes) CREATE src/app/user-list/user-list.component.ts (280 bytes) UPDATE src/app/app.module.ts (598 bytes) |
Now we will replace the <app-user-item>
tag with the <app-user-list>
app.component.html
in app.component.html
src / app / app.component.html
1 2 3 4 5 6 | <h1> {{title}} <app-hello-world></app-hello-world> <app-user-list></app-user-list> </h1> |
Just like how we added a property name
to UserItemComponent
, we will now add property names
to UserListComponent
.
However, instead of storing only a single string, we will store this type of property as an array of strings. An array is denoted by the [] character, and the specific code will look like this:
src / app / user-list / user-list.component.ts
1 2 3 4 5 6 7 8 9 10 | export class UserListComponent implements OnInit { names: string[]; constructor() { this.names = ['Ari', 'Carlos', 'Felipe', 'Nate']; } ngOnInit() { } } |
The first change is to specify a new string[]
property in our UserListComponent
class. This syntax means that names are typed as an array of strings
. Another way of writing it is Array<string>
We changed the constructor
to set the value of this.names
to ['Ari', 'Carlos', 'Felipe', 'Nate'].
Now we can update the template to render a list of names. To do this we will use *ngFor
as follows:
- Loop through a list of items
- Generte a new card for each item.
Our new template will look like this:
src / app / user-list / user-list.component.html
1 2 3 4 | > <ul> > <li *ngFor="let name of names">Hello {{name}}</li> </ul> |
We have updated the template with an ul
and an il
with an attribute of *ngFor="let name of names"
. At first, the *
character and let
syntax seem a bit confusing, so let’s find out:
The *ngFor
syntax says that we want to use NgFor directive on this attribute
. You can think of NgFor
as a for loop for.
The idea is that we will create a new DOM element for each item in the collection.
In the "let name of names"
command. It names
an array has been pointed out in UserListComponent
earlier. And let name
is called a reference
. When we write "let name of names"
it means we will iterate through each element in the names
and display each local variable called name.
NgFor
directive will render a li
tag for each elemt found in the array names
. And declare a local variable name
to hold the value of the current item being iterated over. And this variable will be replaced in the paragraph Hello {{ name }}
.
We do not necessarily have to name the variable
name
. We can write the following:
12 <li *ngFor="let foobar of names">Hello {{ foobar }}</li>Conversely, what if we write like this?
12 <li *ngFor="let name of foobar">Hello {{ name }}</li>The answer is an error because
foobar
not a property that exists in our component.
When reloading the browser, we will have a li
tag for each string in the array.
Using the User Item Component
Remember that we created the UserItemComponent
together UserItemComponent
?
Instead render out each name
in UserListComponent
we should use UserItemComponent as child component (Component child) – that is, instead of rendering directly text Hello
and name, we should UserItemComponent
specified template (and function ) for each item in the list.
To do this, we need to do 3 things:
- Configure
UserListComponent
to renderUserItemComponent
(In template). - Configure
UserItemComponent
to accept thename
variable as aninput
. - Configure
UserListComponent
template to passname
toUserItemComponent
Come on, let’s do it step by step!
Rendering the UserItemComponent
UserItemComponent
has an app-user-item
selector selector – Now, let’s try UserItemComponent
that tag to the template:
src / app / user-list / user-list.component.html
1 2 3 4 5 6 | <ul> <li *ngFor="let name of names"> <app-user-item></app-user-item> </li> </ul> |
Notice that I changed the text Hello
and name into an app-user-item
tag. Now reload your browser, to see what we see: It’s repetitive, but there’s something wrong here. With each name
are displayed as “Felipe”! We need a way to pass data into the child component
.
Fortunately, Angular provides a way to do this: @Input
decorator.
Accepting Inputs
Remember that in the UserItemComponent
, we have set this.name = 'Felipe'
in the constructor. Now we need to change a bit in this component so that it accepts a value for the property name.
And here is what we need to change:
src / app / user-item / user-item.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-user-item', templateUrl: './user-item.component.html', styleUrls: ['./user-item.component.css'] }) export class UserItemComponent implements OnInit { @Input() name: string // <-- added Input annotation constructor() { // removed setting name } ngOnInit() { } } |
Notice that I changed the name
property to have an additional @Input
decorator. We will talk more about Inputs
(and even Outputs
) in the next chapter, but for now we know that this syntax allows us to pass a value from the parent template
( parent template
).
To use Input
we must add it to the constant list in import
.
Finally, we will not set the default value for the variable name
, so we will delete that set in the constructor
. So now we have an name Input
. How to use it?
Passing an Input value
To pass a value to a component we use square brackets [] in the template, specifically as follows:
src / app / user-list / user-list.component.html
1 2 3 4 5 6 | <ul> <li *ngFor="let name of names"> <app-user-item [name]="name"></app-user-item> </li> </ul> |
Notice that, on the app-user-item
tag, I added a new attribute, which is: [name]="name"
. In Angular when we add an attribute in brackets like [foo]
– that is, we want to say, pass a value to the Input
named foo
in the component.
In this case, note that the name
on the right is from the let name...
in ngFor. If we write it like this:
1 2 3 4 | <li *ngFor="let individualUserName of names"> <app-user-item [name]="individualUserName"></app-user-item> </li> |
The [name]
is specifying the Input in the UserItemComponent
. Notice that we are not passing the string “individualUserName” here and we are passing the value of individualUserName
– That is the value of each element in the names
array.
We will talk more about Inputs and Outputs in the next chapter. Currently, what we have done is:
- Repeats elements in
names
- Create a new
UserItemComponent
for each element in thenames
UserItemComponent
a value ofname Input
contained inUserItemComponent
And now our list names are displayed. Congratulations! Together, we have built the first Angular application with components!
Of course, this application is quite simple, and I want us to build an application with more functions, such as voting application, capable of interacting with users … However before Starting to build a new app, we will learn together about Bootstrapping in Angular.
Bootstrapping Crash Course
Every app has a main entry point
.
This application is built with Angular CLI (it is built on a tool called Webpack). We run this application by calling:
ng serve
ng
will find the entry point for our application in the angular.json
file. Come, let’s also learn how ng
identify the component that we just created.
At a high level it will look like this:
angular.json
will specify a “main” file, in this casemain.ts
main.ts
is the entry-point of our app, and it willbootstraps
application.- The bootstrap process will start the Angular module.
- We use
AppModule
to bootstrap the application.AppModule
is specified insrc/app/app.module.ts
AppModule
will specify whichcomponent
will be used as top-level components. In that case, it isAppComponent
AppComponent
has<app-user-list>
in the template, and it renders the list of users.
Currently, what I want to focus on is the Angular module system: NgModule
.
Angular has a strong concept of modules
. When you launch an Angular app, you won’t start a component directly, instead you will create an NgModule
, which will point to the component you want to load.
Take a look at the code below:
src / app / app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @NgModule({ declarations: [ AppComponent, HelloWorldComponent, UserItemComponent, UserListComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
The first thing we see is an @NgModule
decorator. Like all decorators, this code @NgModule( ... )
will add a metadata to the class shortly after (in this case, AppModule
).
@NgModule
decorator has 4 keys: declarations, imports, providers, and bootstrap
declarations
declarations
indicate the components defined in this module.
And here is an important idea in Angular: “You must declare components in NgModule before you can use them in your templates.”
You can think of NgModule
as a “package” and declarations
will specify which components are owned by this module.
You may have noticed that when we use ng generate
, the tool automatically adds components to the declarations
list. The idea here is that whenever we create a new component, ng
tool assumes that we want it to belong to the current NgModule
.
imports
imports will describe the dependencies
that this module has. We are creating a browser app, so we will import BrowserModule
. If your module depends on other modules, you can list them here.
The difference between
import
andimports
You might be asking the question, is the difference between the class import at the beginning of the file and the imports in the module?
The short answer is that you will put something intoNgModule's imports
if you will use it in templates or withdependency injection
. We will talk aboutdependency injection
in the following sections.
providers
providers
are used for dependency injection. Therefore, to make a service ready to be injected into our app, we will add it here.
bootstrap
bootstrap
will tell Angular that when this module is used to bootstrap an app, it needs to load AppComponent
first.
Over. Invite you to refer to the next article
Source: https://www.ng-book.com/2/