Code on github https://github.com/kendarorg/Angular101
Now i would like to show a single item. First we setup the component stub inside the project root dir
ng generate component SingleAddress
This will generate a directory single-address with the stub for the new component
Inside the app.module.ts we add two new Material modules, the button, the icon and the form, importing them
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import {FormsModule} from '@angular/forms';
And using them inside the @NgModule
@NgModule({
...
imports: [
...
MatButtonModule,
MatIconModule,
FormsModule,
],
Inside the app.component.html a new css is included to get all the Material icons
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
This part is copy pasted directly from http://google.github.io no responsibility taken for this!
For those looking to self host the web font, some additional setup is necessary. Host the icon font in a location, for example https://example.com/material-icons.woff and add the following CSS rule:
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://example.com/MaterialIcons-Regular.eot); /* For IE6-8 */
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
}
In addition, the CSS rules for rendering the icon will need to be declared to render the font properly. These rules are normally served as part of the Google Web Font stylesheet, but will need to be included manually in your projects when self-hosting the font:
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}
First we need to be able to call the new component and we add therefore the component inside app-routing.module.ts
import { SingleAddressComponent } from './single-address/single-address.component';
And then two new routes, one for the list (to respect the REST standard) and one for the single resulting in the following code
const routes: Routes = [
{path: "", component: AddressesComponent},
{path: "address", component: AddressesComponent},
{path: "address/:id", component: SingleAddressComponent},
];
Noticed the :id this is to intend that the path will be in the form "address/123" to get exactly the required address
A new button is added to the table in addresses.component.html. This will follow the routerLink that we specified inside the routing. Note the slash in front of the address. This will make the address absolute!
<ng-container matColumnDef="view">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let element">
<button mat-icon-button routerLink="/address/{{element.id}}">
<mat-icon>details</mat-icon>
</button>
</mat-cell>
</ng-container>
Now clicking on the link you will be redirected to a fantastic "single-address works!"
Inside the SingleAddressComponent we need to retrieve the routed data, through the Activated Route service
import { ActivatedRoute } from '@angular/router';
That is injected inside the single-address.components.ts
addressId: number;
constructor(private activatedRoute: ActivatedRoute) {
this.addressId = this.activatedRoute.snapshot.params.id;
}
And used inside the onInit
ngOnInit(): void {
this.addressId = this.activatedRoute.snapshot.params.id;
}
At this point we can show it inside the single-address.component.html. The message now contains the id of the clicked element
<p>single-address {{addressId}} works!</p>
The service will have a new method getById with a number parameters
public getById(id:number){
for(var i=0;i< this.addresses.length;i++){
if(this.addresses[i].id==id){
return this.clone(this.addresses[i]);
}
}
return null;
}
We need then to import the data service and add it to the constructor,
import { AddressesDataService, AddressElement } from '../addresses-data.service';
...
address:AddressElement;
constructor(private activatedRoute: ActivatedRoute,
public dataService: AddressesDataService) {
}
And used inside the onInit
ngOnInit(): void {
this.addressId = this.activatedRoute.snapshot.params.id;
this.address = this.dataService.getById(this.addressId);
}
Loading the page will load a new address! And we can change the text, but nothing changes :D
<p>single-address {{address.id}} works!</p>
Now it's possible to show all item data
<h2>Selected Address</h2>
<label>Name
<input type="text" [(ngModel)]="address.name">
</label>
<label>Address
<input type="text" [(ngModel)]="address.address">
</label>
<label>Description
<input type="text" [(ngModel)]="address.email">
</label>
With a decent css
.products {
padding: 2rem;
}
label, input {
display: block;
}
label {
margin-bottom: 1rem;
}
Resulting in the following awesome screen