Wednesday, May 23, 2018

Angular - Creating a Component using Angular CLI

Install Angular CLI

If you don't have Angular CLI you will need to install it using npm

npm install -g @angular/cli


Usage


ng g c products/product-detail.component --flat

ng = Angular CLI
g = generate
c = component
--flat = no folder will be created

This will create 4 files:

  src\app\products\product-detail\product-detail.component.css
  src\app\products\product-detail\product-detail.component.html
  src\app\products\product-detail\product-detail.component.spec.ts
  src\app\products\product-detail\product-detail.component.ts

It will update the file which will register the component in the app.module.ts:
  src\app\app.module.ts

It will also wire the components together putting some useful code in
src\app\products\product-detail\product-detail.component.ts


Wednesday, May 9, 2018

Angular - Retrieving data using http and observables

Import HttpClientModule

Add HttpClientModule to the imports array of one of the application's Angular Modules

The items in bold are the ones that are specific to adding http.

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 { HttpClientModule } from '@angular/common/http';


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

Adding Http to Service

my.service.ts


import { Injectable } from "@angular/core";
import { IProduct } from "./product";
import { HttpClient } from "@angular/common/http";
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/Observable/throw'
import 'rxjs/add/operator/catch'
import 'rxjs/add/operator/do'
import { HttpErrorResponse } from "@angular/common/http";

@Injectable()
export class ThingService {
    
    private _thingUrl = 'www.myWebApi.com/api/myThings';

    constructor (private _http: HttpClient){ }

    getMyThings(): Observable<IThing[]> {
        return this._http.get<IThing[]>(this._thingUrl)
        .do(data => console.log('data: ' + JSON.stringify(data)))
        .catch(this.handleError);
    }

    private handleError(err: HttpErrorResponse) {
            return Observable.throw(err.message);
    }
}

TIP: The url can be to a local JSON file that has the desired response. This can be useful for mocking out the web service you are calling when testing or rapidly developing.

Using Service / Subscribing

Call the subscribe method of the returned observable

In your component you could have something like this.

ngOnInit(): void {
this._productService.myThings()
.subscribe(things => {
this.things = things;
}, 
error => {
                      /// handle error here...
});
}

Wednesday, May 2, 2018

Kill all instances of a process using Powershell

Sometimes it is just too tedious to click on and kill all the processes in Task Manager in Windows.

If you have a PowerShell prompt open and several instances to kill the following command will do the trick.

Kill the processes

One of my favorite examples:

stop-process -name phantomjs

Get List of Processes

If you don't know the name, use the following command to get a list of all processes running

Get-Process


Tuesday, May 1, 2018

Angular - Services

What is a service

Simply put it is a class with a focused purpose. Generally it is not specific to any component, and thus provides logic that can be used for different components. Useful for encapsulating external interactions such as web api calls, etc.

Dependency Injection

We can use Angular and Dependency Injection to inject the service into the component. This makes testing much easier by allowing for Mocks. Luckily, Angular has a built in injector.

In order for a component to use the service it just needs to add a parameter to the constructor of the component.

Example:

my.service.ts

import { Injectable } from '@angular/core'

@Injectable()
export class MyService {
   getMyThings() : IThing[] { ... }
}

export class MyComponent {
    private _myService;
    constructor(myService: MyService) {
        _myService = myService
    }
}

Tip: Here is the same MyComponent class, but in shorter syntax

export class MyComponent {

    constructor(private _myService: MyService) {
    }
}

Registering the Service


A service can be registered at with different scope. Choose the right method to get the right scope.

Method 1: Registering a Provider

To make the service available to a component and its children add it to the array of providers where the component is defined.

import { MyService } from './my.service';

@Component({
    selector: ...,
    template: ..., 
    providers: [MyService]
})
export class MyComponent {
    constructor(private _myService) {}
}



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 { }