The Complete Guide to Angular 7
ng serve
This command helps testing easily our app locally while developing. See more about the Angular CLI here.
Import "Typescript" form feature to store the input in into the "name" property by using this syntax below:
[(ngModel)]="name"
Install locally bootstrap and make clean start project:
npm install --save bootstrap@3
Generate new components:
ng generate component servers
After a bit changes, we get these html tag codes like that
<body>
<app-root>
...
<app-servers>
<app-server></app-server>
<app-server></app-server>
</app-servers>
</app-root>
...
</body
Two ways to use data binding:
- Using $event:
<input
type="text"
class="form-control"
(input)="onUpdateServerName($event)">
- And the main script:
onUpdateServerName(event: Event){
this.serverName = (<HTMLInputElement>event.target).value;
}
- Using ngModel:
- It should be the better method by it's simplicity. First, we need to add the FormsModule:
//app.module.ts
import { FormsModule } from '@angular/forms'
- Then, easy stuff is remaining like that:
<input
type="text"
class="form-control"
[(ngModel)]="serverName">
If-else statements:
<p *ngIf="serverCreatedFlag; else noServer">Server {{ serverName }} was created successfully!</p>
<ng-template #noServer>
<p>No server was created.</p>
</ng-template>
How to dinamically change style of element:
-
Using ngStyle:
This method allows us to dynamically assign a style itself.
<p [ngStyle]="{backgroundColor: getBackgroundColor()}"></p>
-
Using ngClass:
This method allows us to dynamically add or remove CSS-classes.
<p
...
[ngClass]="{online: getServerStatus() === 'online'}"
></p>
-
Using ngFor:
It would be nicer to have an array of service which adds them dynamically like that:
<app-server *ngFor="let server of servers"></app-server>
Recommend using Bootstrap 3+
- See more how navigation work here.
- Adding styles to gird our body after header
body {
min-height: 2000px;
padding-top: 70px;
}
.btn-space {
margin-right: 5px
}
-
Adding Models
- Recipe (name, description, imagePath)
- Ingredient (name, amount)
-
Using Augury to dive into our Angular Apps.
-
Assigning an Alias to custom properties:
@Input('srvElement') element : {type: string, name: string, content: string};
- Binding to custom events
<app-server
(serverCreated)="onServerAdded($event)"
(blueprintCreated)="onBlueprintAdded($event)">
</app-server>
- Now, let's see how to emit an object in Angular
import { EventEmitter, Output } from '@angular/core';
@Output() serverCreated = new EventEmitter<{serverName: string, serverContent: string}>();
newServerName = ''
newServerContent = ''
onServerAdded() {
this.serverCreated.emit({
serverName: this.newServerName,
serverContent: this.newServerContent
});
}
- Here, the method onServerAdded() is also declared in other script file (up/down level)
serverElements = [];
onServerAdded(serverData: {serverName: string, serverContent: string}) {
this.serverElements.push({
type: 'server',
name: serverData.serverName,
content: serverData.serverContent
});
}
- How to listen from outside?
@Output('bpCreated') blueprintCreated = new EventEmitter<{serverName: string, serverContent: string}>();
- Using Local References in Templates
<input
type="text"
class="form-control"
#addedServer>
<button
class="btn btn-primary"
(click)="onServerAdded(addedServer)">Add Server</button>
onServerAdded(addedServer: HTMLInputElement) {
this.serverCreated.emit({
serverName: addedServer.value,
serverContent: this.newServerContent
});
}
- Lifecycle
- ngOnChanges - called after a bound input property changes
- ngOnInit - called once the component is initialized
- ngDoCheck - called during every change detection run
- ngAfterContentInit - called after content (ng-content) has been projected into view
- ngAfterContentChecked - called every time the projected content has been checked
- ngAfterViewInit - called after the component's view (and child views) has been initialized
- ngAfterViewChecked - called every time (and child views) have been checked
- ngOnDestroy - Called once the component is about to be destroyed
- Setting up the Services
// recipe.service.ts
import { Recipe } from './recipe.model';
export class RecipeService {
private recipes: Recipe[] = [<recipes>]
getRecipes() {
return this.recipes.slice();
}
}
- Using a Service for Cross-Component Communication
export class RecipeListComponent implements OnInit {
recipes: Recipe[];
constructor(private serviceRecipe: RecipeService) { }
ngOnInit() {
this.recipes = this.serviceRecipe.getRecipes();
}
}
- Using Services for Push Notifications
//shopping-list.component.ts
ingredients: Ingredient[];
constructor(private serviceSL: ShoppingListService) { }
ngOnInit() {
this.ingredients = this.serviceSL.getIngredients();
this.serviceSL.ingredientChanged.subscribe(
(ingredients: Ingredient[]) => {
this.ingredients = ingredients;
}
);
}
- Passing Ingredients from Recipes to the Shopping List (via a Service)
//recipe.service.ts
import { Recipe } from './recipe.model';
import { EventEmitter, Injectable } from '@angular/core';
import { Ingredient } from '../shared/ingredient.model';
import { ShoppingListService } from '../shopping-list/shopping-list.service';
@Injectable()
export class RecipeService {
// ...
constructor(private serviceSL: ShoppingListService) {}
getRecipes() {
return this.recipes.slice();
}
addIngredientsToShoppingList(ingredients: Ingredient[]) {
this.serviceSL.addIngredients(ingredients);
}
}
Note: See all changes in two previous commits!
-
Introduction to Firebase: Store and sync data in real time
-
Tutorial: Angular 7|6 By Example: HTTP GET Requests with HttpClient (Services, async pipe and Observables)
-
Part of project
- Setting up HttpClient:
//app.module.ts
import { HttpClientModule } from '@angular/common/http';
imports: [
BrowserModule,
FormsModule,
AppRoutingModule,
ReactiveFormsModule,
HttpClientModule
],
- Sending PUT Requests to Save Data:
//data-storage.service.ts
import { Observable } from 'rxjs';
/** PUT: update the recipes on the server. Returns the updated recipes upon success. */
storeRecipes() : Observable<Recipe> {
return this.http.put<Recipe>(this.dbURL, this.recipeService.getRecipes());
}
- Fetching back our data from Firebase:
//data-storage.service.ts
/** GET: Fetch the recipes on the server. Returns the sync recipes upon success. */
getRecipes() {
this.http.get<Recipe[]>(this.dbURL)
.subscribe(
(response) => {
this.recipeService.setRecipes(response);
}
);
}
- Install firebase
npm cache clean --force
npm install --save firebase
- Setting up signin and signup routes
//app-routing.module.ts
{ path: 'signup', component: SignupComponent },
{ path: 'signin', component: SigninComponent },
-
Authencation
Let's see an example of sign in authencation
signinUser(email: string, password: string) {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(
response => {
this.router.navigate(['/']);
firebase.auth().currentUser.getIdToken()
.then(
(token: string) => this.token = token
)
}
)
.catch(
error => console.log(error)
);
}
- Authencation to Route protection
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.authService.isAuthenticated();
}
}
- Here, user can only be activated when they have their own token:
isAuthenticated() {
return this.token != null;
}
- Redirection and Wrap up
// For a test
Email: test@test.com
Password: 123123