Code on github https://github.com/kendarorg/Angular101
Let's start showing the list of addresses
ng generate component Addresses
And four new files are now created, describing the new component, adding them to the main app.module.ts
Let's start the ng serve in backround. This will listen to file system changes and recompile everything accordingly showing errors too!
I assume that the first page will be the one showing all the addresses. But the default routing should point to the addresses component.
I need to modify the app-routing.module. Let's dissect it. First there is the import for the core of angular js, with a "node_modules" based path, denoted via the @ sign. It means, seek for the module core under the current angular version directory, and from the core angular stuffs import NgModule. The same for router
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
Then an empty list of routes is exposed (that will be filled afterwards)
const routes: Routes = [];
Finally the main application is initialized, exporting are initialized NgModule and AppRoutingModule
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
This will be used inside the app.module.ts file to start the application
First adding the import for the new component to the list of imports
import { AddressesComponent } from './addresses/addresses.component';
Then adding the new default route to the list of routes:
const routes: Routes = [
{path: "", component: AddressesComponent},
];
Now ,refreshing the page will return a catching text: addresses works!
It is then possible to expose some data. We create a simple service
ng generate service AddressesData
Generating two files
Something special for this example is a clone method to consume and produce only cloned items. This way the content of the data storage will be disconnected from the ui
private clone<T>(a: T): T {
return JSON.parse(JSON.stringify(a));
}
Now we can fill the latter with some fake data inside the class declaration. Note the type declaration, array of AddressElement
addresses: AddressElement[] = [
{id: 1, name: "Contact A", address: "A road", email: "a@b.com"},
{id: 2, name: "Contact B", address: "B road", email: "b@c.com"},
{id: 3, name: "Contact C", address: "C road", email: "c@d.com"},
{id: 4, name: "Contact D", address: "D road", email: "d@e.com"},
{id: 5, name: "Contact E", address: "A road", email: "e@b.com"},
{id: 6, name: "Contact F", address: "B road", email: "f@c.com"},
{id: 7, name: "Contact G", address: "C road", email: "g@d.com"},
{id: 8, name: "Contact H", address: "D road", email: "h@e.com"}
];
public getAddresses():Array<AddressElement>{
var result= [] as AddressElement[];
for(var i=0;i< this.addresses.length;i++){
result.push(this.clone(this.addresses[i]));
}
return result;
}
Let's examine a bit more. Before the class declaration there is an annotation. This is needed by all the services. It means that the service will be "stored" inside the root dependency injection context.
@Injectable({
providedIn: 'root'
})
Additionally the definition of the data is added
export interface AddressElement {
name: string;
id: number;
address: string;
email: string;
}
First we need to import the data service. Notice the "../" part. We are setting a relative path for the import. The definition of AddressElement is imported too
import { AddressesDataService, AddressElement } from '../addresses-data.service';
Then the constructor must be changed to include the data service just imported and will be changed to the following. Creating a variable data service, initialized with the instance just imported.
constructor(public dataService: AddressesDataService) { }
We can now add the initialization with the onInit method and a function to select the...selected address, with the relative fields.
addresses: Array<AddressElement>;
ngOnInit(): void {
this.addresses = this.dataService.getAddresses();
}
Finally a variable containing the the columns to show is added
displayedColumns: string[] = ['name', 'address', 'email'];
We are using the "material" library for our application. Specifically we use the MatTableModule. It must first be imported inside the app.module.ts
import { MatTableModule } from '@angular/material/table';
And added into the @NgModule
@NgModule({
...
imports: [
...
MatTableModule,
],
Now all the application will have access to this module!
The template of the addesses component, inside addresses.component.html, must now show the list! I add too the id cell of the object that will be useful in further explanations.
A "mat-table" is created using a "[dataSource]" NOTE THE SQUARE BRACKETS. Inside it are defined all the possible columns inside the ng-container.
The content cell use the standard Angular syntax. {{property}}. Angular automatically understand that one item of the addresses array should take the name "element"
At the end
mat-row: template for a data row
<mat-table [dataSource]="addresses" class="mat-elevation-z1" >
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef> Id</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.id}} </mat-cell>
</ng-container>
...
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
Finally to add some style, inside the addresses.component.less set the width to 100%
table {
width: 100%;
}
Now the result should be something like this: