Angular2 – Introduction Notes

Angular CLI

  • Before install check latest nodejs version (>=v7.7.1)
  • npm install -g @angular/cli
  • Angular Command Line Interface for workflow commons tasks.
  • More info in https://github.com/angular/angular-cli/wiki
  • Create a new app skeleton:
  • ng new my-first-app
  • Init local development server:
  • ng serve

Integrating Bootstrap

  • Install bootstrap npm package
  • npm install --save bootstrap
  • Edit .angular-cli.json:
  •       "styles": [
            "../node_modules/bootstrap/dist/css/bootstrap.min.css",
            "styles.css"
          ],

How AngularJs is loaded and started

  • index.html
  • <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>MyFirstApp</title>
      <base href="/">
    
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root>Loading...</app-root>
    </body>
    </html>
  • main.ts
  • import { enableProdMode } from '@angular/core';
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    
    import { AppModule } from './app/app.module';
    import { environment } from './environments/environment';
    
    if (environment.production) {
      enableProdMode();
    }
    
    platformBrowserDynamic().bootstrapModule(AppModule);
  • app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        FormsModule,
        HttpModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  • app/app.component.ts
  • import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'Dicen que dicen los que dicen que dicen!';
      name = 'El nuevo marketing de Podemos es la trama';
    }

     

Creating a custom component

  • Will create a new ‘app-server’ component to be place into main ‘app-root’ component
  • app/server/server.component.ts
  • import { Component } from '@angular/core';
    
    @Component ({
      selector: 'app-server',
      templateUrl: './server.component.html'
    })
    export class ServerComponent {}
  • app/server/server.component.html
  • <h3>Server Component</h3>
  • app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    
    import { AppComponent } from './app.component';
    import { ServerComponent } from './server/server.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        ServerComponent
      ],
      imports: [
        BrowserModule,
        FormsModule,
        HttpModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  •  app/app.component.html
  • <input type="text" [(ngModel)]="name">
    <p>{{ name }}</p>
    <button type="button" class="btn btn-primary" name="button">Kaka de la vaca</button>
    <hr>
    <app-server></app-server>

Create a component with CLI

  • We can generate a new component from the terminal:
ng generate component servers
ng g c servers
  • it creates servers/servers.component.ts and related files

Databinding / String interpolation / Property binding

  • servers/servers.component.ts
  • import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-servers',
      templateUrl: './servers.component.html',
      styleUrls: ['./servers.component.css']
    })
    export class ServersComponent implements OnInit {
      allowNewServer = false;
      constructor() {
        setTimeout(() => {
          this.allowNewServer = true;
        },2000)
    
      }
    
      ngOnInit() {
      }
    
    }
  • servers/servers.component.html
  • <app-server></app-server>
    <app-server></app-server>
    <button type="button" class="btn btn-primary" [disabled]='!allowNewServer'>Add Server</button>
  • server.component.ts
  • import { Component } from '@angular/core';
    
    @Component ({
      selector: 'app-server',
      templateUrl: './server.component.html'
    })
    export class ServerComponent {
      serverId:number = 77;
      serverStatus:string = 'offline';
    
      getServerStatus() {
        return this.serverStatus;
      }
    }
  • server.component.html
  • <h3>Server {{serverId}} is {{getServerStatus()}}</h3>

Event Binding

  • servers/servers.component.html
  • <app-server></app-server>
    <app-server></app-server>
    <button
      type="button"
      class="btn btn-primary"
      [disabled]='!allowNewServer'
      (click)='onCreateServer()'>Add Server</button>
    {{createButtonClickedMessage}}
  • servers/servers.component.ts
  • import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-servers',
      templateUrl: './servers.component.html',
      styleUrls: ['./servers.component.css']
    })
    export class ServersComponent implements OnInit {
    
      allowNewServer = false;
      createButtonClickedMessage:string = 'No he pulsado el botón';
    
      constructor() {
        setTimeout(() => {
          this.allowNewServer = true;
        },2000)
    
      }
    
      onCreateServer() {
        this.createButtonClickedMessage = 'Ey , he pulsado el botón!'
      }
    
    
      ngOnInit() {
      }
    
    }

Built-in directives: ngIf, ngFor, ngStyle, ngClass

  • ngIf and ngFor are structural directives because changes the DOM, so will write them with asterisk: *:
  • app.component.html
  <button type="button" (click)="togglePassword()">Display Details</button>
  <p *ngIf="showPassword">Secret password: de danone</p>

  <div *ngFor="let log of logs">
    <p [ngStyle]="{backgroundColor: getColor(log.id)}" [ngClass]="{blanco: log.id > 4}">{{log.text}}</p>
  </div>
  • app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  // styleUrls: ['./app.component.css']
  styles: [`
    .blanco {
      color:#fff;
    }
  `]
})
export class AppComponent {
  logs=[];
  username='';
  usernameIsEmpty = true;
  resetUsername() {
    this.username = '';
  }
  showPassword=false;

  togglePassword() {
    this.showPassword=!this.showPassword;
    this.logs.push({
      text: 'clicked on ' + new Date().getTime(),
      id: this.logs.length
    });
  }

  getColor(id) {
    return (id < 5)? 'white':'blue';
  }

}
NOTE: All components , not depending of the nesting , are being referenced in the app.module.ts

Two ways of assigning a model value to a html property

  • Normal string interpolation
<img src="{{recipe.imagePath}}">
  • Property binding
<img [src]="recipe.imagePath"

A shorcut for defining models

export class Ingredient {
  constructor(public name:string, public amount:number) {}
}

this is equivalent to assign the parameters to the “this” attributes of the object.

Debugging

  • Typescript are not executed by the browser , it is compiled to regular javascript. But we can make debugging in the browser console:

Captura de pantalla 2017-04-15 a las 19.47.07

in the ‘Source’ tab we can inspect all the webpack items, including ts files. That is because of using sourcemaps.

  • There is a Chrome Extension called Augury ti inspect the angular app more in deep:

Captura de pantalla 2017-04-15 a las 19.56.06

Binding to custom properties: communication from parent component to child component / Input decorator

Child: Odd component

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-odd',
  templateUrl: './odd.component.html',
  styleUrls: ['./odd.component.css']
})
export class OddComponent implements OnInit {

  @Input() count: number;
  constructor() { }

  ngOnInit() {
  }

}

Parent : app.component

      <app-odd *ngFor="let odd of oddArray" [count]="odd"></app-odd>

Binding to custom events: communication from child component to parent component / Output decorator

Child component: game-control.component.ts

import { Component, OnInit,EventEmitter,Output } from '@angular/core';

@Component({
  selector: 'app-game-control',
  templateUrl: './game-control.component.html',
  styleUrls: ['./game-control.component.css']
})
export class GameControlComponent implements OnInit {
  intervalRef;
  count:number = 0;
  @Output() startGameEvent = new EventEmitter<{count: number}>();

  constructor() { }

  ngOnInit() {
  }

  onStartGame() {
    this.intervalRef = setInterval(() => {
      this.startGameEvent.emit({
        count: this.count++
      });
    },1000);
  }

  onStopGame() {
    clearInterval(this.intervalRef);
  }

}

Parent component: app.component

  <app-game-control (startGameEvent)="onStartGameClicked($event)"></app-game-control>

Understanding View Encapsulation

  • All components have their own css file and all the classes defined in that file only applies to that component and NOT are spread to their children.

Using local references in templates / ViewChild decorator

  • You can create local references in the templates to be only accesible for the component

https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ref-vars

Projecting content into components with ng-content

  • With <ng-content></ng-content> you can reference the html snippet included between the start tag and the end tag of the component declaration.

Lifecycle hooks

ngIf example with else to show ng-template

<div class="row">
  <div class="col-md-5">
    <app-recipe-list (selectRecipeEvent2)="onRecipeSelected($event)"></app-recipe-list>
  </div>
  <div class="col-md-7">
    <app-recipe-detail
    *ngIf="recipeSelected; else infoText"
    [recipe]="recipeSelected"></app-recipe-detail>
    <ng-template #infoText>
      <p>Please select a recipe:</p>
    </ng-template>
  </div>
</div>