Wednesday, April 25, 2018

Angular - TypeScript Basic Syntax

Common Data Types

string
number
boolean
any - when we don't care what the type is

Using Data Types

export class MyClass {
      name: string = "Test";
}

Functions

export class MyClass {
      doSomething(name: string) : void {
      }
}

Interface

export interface IMyClass {
    name: string;
    code: string;
    doSomething(name: string) : void
}

Class Inheriting from Interface

import { IMyClass } from './myClass';
export class MyClass implements IMyClass {
    constructor(name: string, code: string) {
    }

    doSomething(name: string) : void { ... }
}

Angular - Interactive Nested Components

Now we want to extend our Display-Only nested component to take input from the user. If the user clicks the stars then notify the parent component.

In the Parent component

Using the nested component

We use it just as you would any component. To get data from the nested component we use the banana in the box [()] syntax.

<myApp-star [rating]='product.starRating' 
      [(notify)]='onRatingClicked($event)'></myApp-star>

$event passes along the appropriate information associated with the event.

Handle the event in the parent component

Add this to the parent component class (.ts file).

  onRatingClicked(message: string) : void {
        // do something with the data sent to us via the message parameter
    }

Implementing the Nested Component

star.component.ts

import { Component, OnChanges, Input } from "@angular/core";
import { Component, OnChanges, Input, Output, EventEmitter } from "@angular/core";

@Component({
    selector: 'pm-star',
    templateUrl: './star.component.html',
    styleUrls: ['./star.component.css']
})
export class StarComponent implements OnChanges {
    @Input() rating: number;

    starWidth: number;

    @Output() ratingClicked: EventEmitter<string> = new EventEmitter<string>();

    ngOnChanges(): void {
        this.starWidth = this.rating * 86/5;
    }

    onClick() : void {
        this.ratingClicked.emit('The rating ' + this.rating + ' was clicked');
    }    

}

Passing data from the nested container to the parent component

The only way to pass data to the parent component is using an event. It needs to be decorated with the @Output for this to work. In this example we are passing a type string, but it could be any object for more complex data. 

star.component.html

<div class="crop" 
    [style.width.px]="starWidth"
    [title]="rating"
    (click)='onClick()'>
    <div style="width: 86px">
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
    </div>
</div>

Notice that rating is a property in the star component and so is title




Angular - Display-Only Nested Components


Using the nested component

If we assume the source below is from some parent component html file it might look like this if we are showing a numeric value for the rating of a product.

{{product.startRating}}

If we then want to use a custom component (nested component) to show a nice graphical star rating instead of the numeric value we would use the syntax (property binding syntax) below assuming our component has a selector of myApp-star and has an input property called rating.

<myApp-star [rating]='product.starRating'></myApp-star>

Implementing the Nested Component

Typically nested components are kept in the shared directory of the project.
Use the component by adding it to the module as a declaration.
Input is sent from the parent component to the child (nested) component using a property on the nested component. 

star.component.ts

import { Component, OnChanges, Input } from "@angular/core";

@Component({

    selector: 'myApp-star',
    templateUrl: './star.component.html',
    styleUrls: ['./star.component.css']
})
export class StarComponent implements OnChanges {
    @Input() rating: number;

    starWidth: number;


    ngOnChanges(): void {

        this.starWidth = this.rating * 86/5;
    }
}

Passing data from parent to nested component

Notice the @Input decorator. It is required to expose a property to a parent component in the html file. The starWidth is recalculated whenever the rating property changes.

star.component.html

<div class="crop" 
    [style.width.px]="starWidth"
    [title]="rating">
    <div style="width: 86px">
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
        <span class="glyphicon glyphicon-star"></span>
    </div>
</div>

Notice that rating is a property in the star component and so is title

star.component.css

.crop {
    overflow: hidden;
}
div {
    cursor: pointer;
}

app module

Tell the module that contains the parent component where to find our star component be adding it to the declarations in the module. In the most basic of cases this is the app.modules.ts.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { StarComponent } from './shared/star.component';

@NgModule({
  declarations: [ AppComponent, StarComponent ],
  imports: [ BrowserModule, FormsModule ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Monday, April 23, 2018

Angular - Component Life Cycle Hooks

Common Lifecycle Hooks

OnInit

Perform component initialization and retrieve data

import { Component, OnInit } from '@angular/core';
export class MyComponent implements OnInit {
    ngOnInit(): void {
        console.log('In OnInit');
    }
}

OnChanges

Perform action after change to input properties

OnDestroy

Perform cleanup for the component


Thursday, April 19, 2018

Angular - Transforming Data with Pipes

Sometimes we need to transform bound properties before it is displayed. Such is the case with formatting dates, currency, decimals, etc. Pipes can be chained.

Built-in Pipes


  • date
  • number, decimal, percent, currency
  • json, slice, etc
The complete list and more information can be found here.

Examples (no parameters):

{{ product.productCode | lowercase }}
<img [src]='product.imageUrl' [title]='product.productName | uppercase'>
{{ product.price | currency | lowercase }}

Examples (with parameters)

NOTE: Parameters are separated by colons

{{ product.price | currency: 'USD' : true : '1.2-2' }}


Custom Pipe

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'myTransform'})
export class MyTransform implements PipeTransform {
     transform(value: string, customParam1: string): string { ... }
}

Add it to your module (i.e. app.module.ts) as shown here:

@NgModule({
imports: ...
declarations: [ AppComponent, MyTransform ],
bootstrap: ...
})

Use it just like the built in pipes

Angular - Property and Event Bindings

Binding with Interpolation

Use {{expression}} to pull (only one way binding) in content from the component class. The expression can have many forms.

For example:
{{propertyName}}
{{'ABC' + functionName()}}
{{'Answer is ' + 3*2}}
{{showImage ? 'Hide' : 'Show'}} Image

<img src={{product.imageUrl}}>

Notice that it does not use quotes!

Property Binding

Property Binding is one way just like interpolation.

We could use interpolation to set the src url for an image using:

<img src={{product.imageUrl}}>

or 

<img src='http://someUrl/{{product.imageUrl}}'>

We can use Property binding to do the first case, but not the second case.

<img [src]='product.imageUrl'>

The syntax for Property Binding has a two parts:
  • Binding Target - Is always in surrounded by []
  • Binding Source - Is Surrounded by '' (two single quotes).
Generally, Property Binding is preferred instead of interpolation.

Event Binding

When the user clicks something an event is generated. We can listen for these events using Event Binding. Here is the syntax.

<button (click)='doSomething()'>

The syntax for Property Binding has a two parts:
  • Target Event - Is always in surrounded by ()
  • Template Statement - Is Surrounded by '' (two single quotes).
In this example, when the button is clicked the doSomething() method in our component class is executed.


Two-way Binding

This is useful for having the component and dom in sync such as in the case of an input field on a form.

<input [(ngModel)]='someProperty'>

The Banana in a Box metaphor can be used to remember the order of the parenthesis. Imagine the [()] to have a banana as () in a box as [].

The class for the component would be something like this.
export class MyComponent {
    someProperty: string = 'abc';
}

ngModel is a keyword defined in the FormsModule. The FormsModule will need to be added to the AppModule. To do this open your app.module.ts and add to the top of the file the following:

import { FormsModule } from '@angular/forms';

Next, in the same app.module.ts file add FormsModule to the array of imports in the @NgModule().


Wednesday, April 18, 2018

Angular - Page Layout syntax

Built-in Structural Directives

*ngIf

This adds control flow to the page for hiding and showing content based on conditional logic.

<div *ngIf='someLogic()'>
      Some content to show
</div>

*ngFor

This adds control flow to the page for looping over content like a for loop.

<div *ngFor='let obj of objects'>
      <div>{{obj.PropertyHere}}</div>
</div>

Tuesday, April 17, 2018

Angular - Creating a Component in Angular

Component

A Component has 3 parts

  • Template
    • View layout
    • Created with HTML
    • Includes binding and directives
  • Class
    • Code supporting the view
    • Created with TypeScript (.ts file)
    • Properties for data
    • Methods for logic
  • CSS
    • A CSS file for the styling needed for the component
  • Metadata
    • Extra data for Angular
    • Defined with a decorator

Example

app.component.ts file


import { Component } from '@angular/core';

@Component({
  selector: 'myApp-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Hello World';
}

  • The import pulls in dependency references
  • @Component is the metadata / decorator that says the class is a component. This is similar to an [Attribute] in C#
  • export makes the class definition available for user elsewhere.
  • The selector is a unique value for this component in the application. It is suggested you prefix selectors with something that identifies it as part of your app. This is also what is used as a tag to use this component in another component. In this case it is <myApp-root><myApp-root>
  • It is common to append "Component" to the name name of the class so that it is clear that it is a component.

app.component.html

<div>
  <h1>
    Hello{{title}}!!
  </h1>
</div>

This is the HTML that defines the layout. Anything in {{...}} tags are binds to properties in the class associated with this component.

app.component.css

h1 { text-align:center }

This is a standard CSS file, except these styles will be unique to this component automatically. They will not affect other styles in the project.

Imports

Some common Angular Modules you may need to import are:
  • @angular/core (as we have done above)
  • @angular/animate
  • @angular/http
  • @angular/router

Using the Component

This is how you would use it in index.html for example:

<body>
<myApp-root></myApp-root>
</body>

Telling index.html about our Component

In app.module.ts you list what angular modules should be included in our application#

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Angular - Running Angular application using npm / Visual Studio Code

Assumptions

Using Visual Studio Code (on Windows)

Opening Integrated Terminal

View menu -> Integrated Terminal

Install packages

Open Integrated Terminal and type:
npm install

Launching Angular Application

Open Integrated Terminal and type:
npm start
This will build app and launch in the browser.

This also launches the web server. To stop the web server type control-c at the command prompt.