Angular 4: Pass data parent to child component (part 2 of 2)

The full code for part 2 here and demo on gh-pages here.

Following on from part 1, next we will pass an array of objects between components.

In child.component.ts we add another @Input like this,

@Input() data: {name: string, id: number}[] = [];

Then to app.component.ts add,

  id: number = null;
  name: string = null;
  details: {name: string, id: number}[] = [];

Then in app.component.html we will add input forms for ‘id’ and ‘name’.

<label for="box2">id:</label>
<input type="number" name="box2" class="form-control" [(ngModel)]="id" />
<label for="box3">name:</label>
<input type="string" name="box3" class="form-control" [(ngModel)]="name" />
<p><button (click)="pushto()" class="btn btn-warning btn-sm">Submit</button></p>

again we are using [(ngModel)]. We also have a submit button and when this data is submitted the pushto() function is called.

The pushto() function in app.component.ts is,

pushto(){
    this.details.push({name: this.name, id: this.id});
    this.name = null;
    this.id = null;
  }

This will push a new object to the details array. Let’s display them on the root app page in app.component.html

<div class="col-xs-4 col-md-4">
  <p *ngFor="let element of details"><strong>name: </strong>{{element.name}} <strong>id: </strong>{{element.id}}</p>
</div>

Next we want to pass the array ‘details’ to the child component. To do this we include ‘[data]=”details”‘ in the <app-child> tag like this,

<app-child [quantity]="newvalue" [data]="details"></app-child>

So now in the child component child.component.html we will use *ngFor to loop through the array ‘data’.

<p *ngFor="let element of data"><strong>name:</strong> {{element.name}} <strong>id:</strong> {{element.id}}</p>

The full code for part 2 here and demo on gh-pages here.

Angular 4: Pass data parent to child component (part 1 of 2)

The full code for part 1 & 2 here and demo on gh-pages here.

This post explains how to pass data from a parent component directly into a child component without iteration using ngFor as we did in the other post on this same issue here.

With angular-cli previously installed, create a new project,

$ ng new angulardataparenttochild

Then change directory into that newly created directory,

$ cd angulardataparenttochild

Next create a child component,

$ ng g c child

In your editor place a tag <app-child$gt;$lt;app-child/$gt; in app.component.html to put the child component inside the parent component. Also add some bootstrap to make it nice! app.component.html should look like this,

<div class="container" style="border: 3px solid #515B89; background-color: #79809E; border-radius: 15px;">
  <div class="row">
    <div class="col-xs-12">
      <h1>
        {{title}}
      </h1>
    </div>
  </div>
  <div class="row">
    <div class="col--xs-12">
      <app-child></app-child>
    </div>
  </div>
</div>

Likewise the child.component.html file is

<div class="container" style="border: 3px solid #458075; background-color: #6D948C; border-radius: 15px;">
  <div class="row">
    <div class="col-xs-12">
      <p>
        child works!
      </p>
    </div>
  </div>
</div>

Let’s check this works with

$ ng serve

Navigate in your browser to localhost:4200

First be sure to import ‘Input’ into the top of the child component’s ts file child.component.ts,

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

Then just inside the child component’s class, in child.component.ts, use the input decorator to setup the data structure of the data being input to this child component,

@Input() quantity: number = null;

Add an input form to the root app, app.component.html

<input type="number" class="form-control" [(ngModel)]="value" (ngModelChange)="fun()"/>

Here we are using [(ngModel)] and setting any input to “value”. (ngModelChange)=”fun()” will call a function fun() whenever there is a change in the input form.

The full app.component.html file should look like this,

<div class="container" style="border: 3px solid #515B89; background-color: #79809E; border-radius: 15px;">
  <div class="row">
    <div class="col-xs-12">
      <h1>
        {{title}}
      </h1>
      <label for="box">Value:</label>
      <input type="number" class="form-control" [(ngModel)]="value" (ngModelChange)="fun()" />
      <p>value = {{ value }}</p>
      <p>newvalue = value + 2 = {{ newvalue }}</p>
    </div>
  </div>
  <div class="row">
    <div class="col--xs-12">
      <app-child [quantity]="newvalue"></app-child>
    </div>
  </div>
</div>

In app.component.ts just inside the “export class AppComponent(” we will define value and also in this class we will create the fun() function which increase “value” by 2, just to do something with it! We also set this then equal to “newvalue” and define that as we did with “value”.

So app.component.ts should look like this,

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

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

  constructor(){
  }

  ngOnInit(){
  }

  fun(){
    this.newvalue = this.value + 2;
  }
}

We will display the values “value” and “newvalue” in app.component.html using interpolation which is just a fancy word for the double curly brackets {{ newvalue }},

<p>value = {{ value }}</p>
<p>newvalue = value + 2 = {{ newvalue }}</p>

Also in the file we will include child component using it’s selector which is app-child, like this,

<app-child></app-child>

But this where we pass the parent component value “newvalue” to the child value “quantity”.

<app-child [quantity]="newvalue"></app-child>

But we don’t want to pass it to the child.component.html just yet. We will like to get it into the child.componet.ts file first and do soemthing with it. We will again just increase it’s value by 2. This is done using the ngOnChanges() function.

But do use this you must import ‘OnChanges’ at the tope of child.component.ts,

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

Also you need to implement it with the class like this,

export class ChildComponent implements OnInit, OnChanges {...

Increasing the this.quantity value by 2 in ngOnChanges() is done like this,

  ngOnChanges(){
      this.quantity = this.quantity + 2;
  }

The function ngOnChanges() runs anytime the quantity value changes. In other words when there is an change to “newvalue” in the parent component. This is very useful!

Next we display that value in child.component.html using the {{quantity}}.

The child.component.html file,

<div class="container" style="border: 3px solid #458075; background-color: #6D948C; border-radius: 15px;">
  <div class="row">
    <div class="col-xs-12">
      <h3>child app</h3>
      <p>
        value + 4 = newvalue + 2 = quantity = <span *ngIf="quantity">{{quantity}}</span>
      </p>
    </div>
  </div>
</div>

However I found this always displayed the ‘quantity’ value as 2, even before anything was input.

As a result I put an if(quantity){…} around this line. So child.component.ts looks like this,

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

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges {
@Input() quantity: number = null;

  constructor() {
  }

  ngOnInit() {
  }

  ngOnChanges(){
    if(this.quantity){
      this.quantity = this.quantity + 2;
    }
  }
}

The full code for part 1 & 2 here and demo on gh-pages here.

Angular 4 & D3.js

Code is on github on d3graph repo.
View demo on gh-pages.


Having angular-cli installed (how to install angular-cli), then create a project called ‘angular-d3-example’

$ ng new angular-d3-example

Next we’ll add a component for the graph, which we’ll call ‘d3graph’,

$ ng g c d3graph

Add the selector to the app.component.html file.
We need to install the service ‘d3-ng2-service’. The github page for this is here. Install this service with npm using,

$ npm install d3-ng2-service --save

You will need to import the ‘D3Service’ from ‘d3-ng2-service’ by adding to the top of app.module.ts,

import { D3Service } from 'd3-ng2-service';

Also import ‘D3Service’ to the providers array in the same file.
Then module.ts should look like this,

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 { D3graphComponent } from './d3graph/d3graph.component';

import { D3Service } from 'd3-ng2-service'; // <-- import statement

@NgModule({
  declarations: [
    AppComponent,
    D3graphComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [D3Service], // <-- import provider
  bootstrap: [AppComponent]
})
export class AppModule { }

Services can be greated with angular-cli using,

$ ng g s SERVICENAME

At this stage it is a good idea to check everything is working by running,

$ ng serve

and navigate to http://localhost:4200 where is should say ‘app works!’ and below it ‘d3graph works!’

We’ll create a bar chart using,

data = [
          {name : 'A', yVal : 1},
          {name : 'B', yVal : 4},
          {name : 'C', yVal : 2},
          {name : 'D', yVal : 3}
      ];

The d3graph.componet.ts will look like this,

import { Component, ElementRef, NgZone, OnDestroy, OnInit } from '@angular/core';

import {
  D3Service,
  D3,
  Axis,
  BrushBehavior,
  BrushSelection,
  D3BrushEvent,
  ScaleLinear,
  ScaleOrdinal,
  Selection,
  Transition
} from 'd3-ng2-service';


@Component({
  selector: 'app-d3graph',
  template: '<svg width="200" height="200"></svg>'
})
export class D3graphComponent implements OnInit {
  private d3: D3;
  private parentNativeElement: any;
  private d3Svg: Selection<SVGSVGElement, any, null, undefined>;

  constructor(element: ElementRef, private ngZone: NgZone, d3Service: D3Service) {
    this.d3 = d3Service.getD3();
    this.parentNativeElement = element.nativeElement;
  }

  ngOnInit() {
            let self = this;
            let d3 = this.d3;
            let d3ParentElement: any;
            let svg: any;
            let name: string;
            let yVal: number;
            let colors: any = [];
            let data: {name: string, yVal: number}[] = [];
            let padding: number = 25;
            let width: number = 500;
            let height: number = 150;
            let xScale: any;
            let yScale: any;
            let xColor: any;
            let xAxis: any;
            let yAxis: any;

    if (this.parentNativeElement !== null) {
      svg = d3.select(this.parentNativeElement)
          .append('svg')        // create an <svg> element
          .attr('width', width) // set its dimensions
          .attr('height', height);

      colors = ['red', 'yellow', 'green', 'blue'];

      data = [
          {name : 'A', yVal : 1},
          {name : 'B', yVal : 4},
          {name : 'C', yVal : 2},
          {name : 'D', yVal : 3}
      ];

      xScale = d3.scaleBand()
          .domain(data.map(function(d){ return d.name; }))
          .range([0, 200]);

      yScale = d3.scaleLinear()
          .domain([0,d3.max(data, function(d) {return d.yVal})])
          .range([100, 0]);

      xAxis = d3.axisBottom(xScale) // d3.js v.4
          .ticks(5)
          .scale(xScale);

      yAxis = d3.axisLeft(xScale) // d3.js v.4
          .scale(yScale)
          .ticks(7);

        svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + (padding) + "," + padding + ")")
        .call(yAxis);

	       svg.append('g')            // create a <g> element
         .attr('class', 'axis')   // specify classes
	       .attr("transform", "translate(" + padding + "," + (height - padding) + ")")
         .call(xAxis);            // let the axis do its thing

      var rects = svg.selectAll('rect')
          .data(data);
          rects.size();

      var newRects = rects.enter();

      newRects.append('rect')
          .attr('x', function(d,i) {
            return xScale(d.name );
          })
          .attr('y', function(d) {
              return yScale(d.yVal);
            })
	        .attr("transform","translate(" + (padding -5  + 25) + "," + (padding - 5) + ")")
          .attr('height', function(d) {
              return height - yScale(d.yVal) - (2*padding) + 5})
          .attr('width', 10)
          .attr('fill', function(d, i) {
            return colors[i];
          });
     }
   }
 }

Should look like this,

Code is on github on d3graph repo.
View demo on gh-pages.

Angular 4: Simple Routing

All code is on github https://github.com/shanegibney/angular-routing
A demo is available on gh-pages https://shanegibney.github.io/angular-routing/

Start a new project using angular-cli,

$ ng new angularRouting

Move into the project root directory

$ cd angularRouting

Create app-routing.module.ts

$ ng g module app-routing

Set the app-routing.module.ts to add components and routes. Also note the changes to ngModule imports and exports.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { InfoComponent } from '../info/info.component'
import { AboutComponent } from '../about/about.component'

const routes: Routes = [
{
path: 'about',
component: AboutComponent,
},
{
path: 'info',
component: InfoComponent,
},
];

@NgModule({
imports: [
RouterModule.forRoot(routes)
],
exports: [
RouterModule
],
declarations: []
})
export class AppRoutingModule { }

Next create two components ‘about’ and ‘info’.

$ ng g c info
$ ng g c about

To app.module.ts import the AppRoutingModule and to ngModule imports add AppRoutingModule, so that app.module.ts looks like this,

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app-routing/app-routing.module';

import { AppComponent } from './app.component';
import { InfoComponent } from './info/info.component';
import { AboutComponent } from './about/about.component';

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

To app.component.html add the element. This is where the component will render. Also add link to the components,

<h1>
{{title}}
</h1>
<a routerLink="/info" routerLinkActive="active">Info</a>
<a routerLink="/about" routerLinkActive="active">About</a>
<router-outlet></router-outlet>

Add the following routes to redirect empty routes ” and wildcards ‘**’ to home,

    
{
path: '',
redirectTo: '/home',
pathMatch: 'full',
},
{
path: '**',
redirectTo: '/home',
pathMatch: 'full'
}

Note Angular checks the routes in order so empty routes and wildcards must be after all other routes with the wildcard route at the end.

All code is on github https://github.com/shanegibney/angular-routing
and a demo is available on gh-pages https://shanegibney.github.io/angular-routing/

Useful link: http://shermandigital.com/blog/configure-routing-in-an-angular-cli-project/

Angular 4: Building a Simple Service

Create the project with angular-cli

$ ng new angular-service-project

Create a service with angular-cli

The service was created with,

$ ng g s example-service

where ‘g’ is a shortcut for ‘generate’ and ‘s’ is a shortcut for ‘service’.

The actual service is at: example-service-service.ts

import { Injectable } from '@angular/core';
@Injectable()
export class ExampleServiceService {
someMethod(){
return "Heya!";
}
constructor() { }
}

Then make the changes to app.component.ts

import { Component, OnInit } from '@angular/core'; // added OnInit
import { ExampleServiceService } from './example-service.service' // added this import

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ExampleServiceService]
})
export class AppComponent {
title = 'app works!';
example: string;
constructor(private _exampleServiceService: ExampleServiceService){ // added this constructor
}
// added this ngOnInit method
ngOnInit(){
this.example = this._exampleServiceService.someMethod();
}
}

Get example into the app.component.html file,

<h1>{{ title }}</h1>
<h3>{{ example }}</h3>

To make this service available to all components, cut the line

providers: [ExampleServiceService]

from app.component.ts and put it is app.module.ts and also make it available with

import { ExampleServiceService } from './example-service.service'

app.module.ts should look like this,

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { ExampleServiceService } from './example-service.service'
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule
],
providers: [ExampleServiceService],
bootstrap: [AppComponent]
})
export class AppModule { }

Angular4: Pass data from parent to child component (part 5)

Set  up an ng project,

$ ng new angularcomponentpassing

Create a new component,

$ ng g c cockpit

File: cockpit.component.ts

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

@Component({
selector: 'app-cockpit',
templateUrl: './cockpit.component.html',
styleUrls: ['./cockpit.component.css']
})
export class CockpitComponent implements OnInit {
@Input('srvElement') element: {name: string, id: number;}
constructor() { }

ngOnInit() {
}
}

Note: ‘srvElement’ is an alias for ‘element’ and can be left out above like this,

@Input() element: {name: string, id: number;}
constructor() { }

File: cockpit.component.html

<hr>
<p>
cockpit works!
</p>
<p><strong>Name:</strong> {{ element.name }}, <strong>id:</strong> {{ element.id }}</p>

File: app.component.ts

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

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
title = 'app works!';
serverElements = [{name: 'John', id: 8}, {name: 'Matt', id: 10}];
}

File: app.component.html

<h1>
{{title}}
</h1>
<app-cockpit *ngFor="let serverElement of serverElements" [srvElement]="serverElement">hello</app-cockpit>

If the alias for ‘element’, which is ‘srvElement’ is not used then the above line should be,

<app-cockpit *ngFor="let serverElement of serverElements" [element]="serverElement">hello</app-cockpit>

Angular 4: Deploy to gh-pages (part 4)

Presuming: you have an Angular 2 or 4 project ready to deploy to gh-pages, and that you’ve created a github repo connected to your local directory and git inited it. Also you need to have installed and be using angular-cli. If not look at this post.

Angular 4 projects can be deployed on gh-pages by first installing the npm package angular-cli-ghpages,

$ sudo npm i -g angular-cli-ghpages

The previous command is run in your local master branch. There is no need to create a local gh-pages branch or in fact a remote one in your repository. First create your dist folder and set the base-href with,

$ ng build --prod --base-href https://<USERNAME>.github.io/<REPONAME>/

Do not forget the trailing forward slash at the end.

Then sent this to your remote gh-pages branch, which does not need to be previously created.

$ sudo angular-cli-ghpages --branch gh-pages

This is also run in your local master branch. Running this commands as deparately as above did not work for me, I had to create a script called ‘deploy’ which I placed at the end of the package.json “scripts” object, like this,

"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"deploy": "ng build --prod --base-href https://shanegibney.github.io/basic-maths-app/ && angular-cli-ghpages --branch gh-pages"
},

Then run this script with,

$ sudo npm run deploy

Then navigate to,

https:/<USERNAME>/.github.io/<REPO-NAME>/

The following blog post from shermandigital.com may be useful.

Angular 4: Forms (part 3)

Let’s add an input for with type=”number”. This will be in the sum app’s html file, src/app/sum/sum.component.html

What’s important here in the ngModel and it’s round and square brackets. We can set the inputted value to num1 with,

[(ngModel)]="num1"

Also the onSum() method is called when the button is clicked.

We need to set num1, num2 and sum variables in src/app/sum/sum.component.ts and create the onSum() method which is called to sum the numbers when the button is clicked.

Angular 4: Bootstrap & Components (part 2)

First install Bootstrap,

$ npm install --save bootstrap

Then add bootstrap to .angular-cli.json which can be found in the root of the project. Find the ‘styles’ and add the path for bootstrap like this,

"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
],

Then in the project root run,

$ npm install,

Create a component called ‘sum’ with,

$ ng g c sum

Next get the sum component into the root component.
Go to src/app/app.component.html and place the selector for the sum component which is,

<app-sum></app-sum>

This gets placed as follows,

Now that we’ve placed our sum component in the root component we would like to set it’s contents. This can be done in src/app/sum/sum.component.html

And so at http://localhost:4200 we should see the contents of the sum component inside the root component like this,

Angular 4: Getting started Install angular-cli (part 1)

We’ll create a simple app with Angular 4 which will sum two numbers input into a form.

First install Angular CLI (https://cli.angular.io/)

$ npm install -g @angular/cli

Create a new project called mathapp,

$ ng new mathapp

Move into this newly created directory,

$ cd mathapp

Now create a component called sum

$ ng g c sum

where g is short for generate and c is for component.

Next be sure to be in the same directory that has package.json and install all packages in there with npm. yarn is also a good package manager, consider faster than npm because it will not install package dependecies already installed in previous packages.

$ npm install

Now let us run the server with,

$ ng serve

Navigate to http://localhost:4200

and you should see the text,

So now we are well on our way! Well done!

Angular 4: Generating Components and How to Use

To create a new component in Angular 4 automatically with the Angular CLI, in the projects root directory type,

$ ng generate component my-component

Where ‘my-component’ is the name of the component. The commands ‘generate’ and ‘component’ can respectively be replaced with ‘g’ and ‘c’. The following command does the same as the above command,

$ ng g c my-component

This will create a new folder in the app directory with the following files,

The command also makes changes to the file src/app/app.module.ts on lines 7 and 12,

Also the file src/app/my-component/my-component.component.ts is created as follows,

These changes could all be implemented manually instead of using the command.

To create a new component without the src/app/my-component/my-component.component.spec.ts which is for unit unit testing,

$ ng g c my-component --spec false

my-component.component.ts contains

templateUrl: './my-component.component.html',

to use the contents of srcv/app/my-component.component.html in the root app html file src/app/app.component.html add a custom html tag with the component name as follows,

<app-my-component></app-my-component>

Angular 4: Data Binding Two-Way-Binding

Initially the button is disabled until a username is input, after which time it is possible to reset the username by clicking the button.


In app.component.ts he simply declare two variables and set ‘username’ to an empty string. The function clears the string and resets the username.

export class AppComponent {
username: string = '';
allowButton: boolean = false;
onUsernameReset(){
this.username = '';
}
}

In app.component.html we use [(ngModel)] for two-way-databinding. This uses both square and round brackets. The input is set to ‘username’ and because of the two-way-binding this is available everywhere, e.g. for string interploation on the next line using {{ username }} and for property binding [disabled]=”!username”

<div class="container">
  <div class="row">
    <div class="col-md-4">
     <label for="box">Username:</label>
     <input name="box" type="text" class="form-control" [(ngModel)]="username"/>
     <p> {{ username }} </p>
     <button class="btn btn-primary" [disabled]="!username" (click)="onUsernameReset()">Reset username</button>
    </div>
  </div>
</div>

The ‘click’ event is put in round brackets and it calls the function onUsernameReset() which can be found in app.component.ts

Angular 4: Data Binding Event Binding

When an event occurs i.e. clicking a button we want a function onButton() to be called.

In app.component.ts we have the function onButton() which simply logs a few words to the console,

export class AppComponent {
onButton(){
   console.log("You pressed it, well done!")
   }
}

In app.component.html the event, in this case ‘click’, is in round brackets,

<button class="btn btn-primary" (click)="onButton()">Button</button>

Angular 4: Basic Setup & Bootstrap

https://cli.angular.io/

Install Angular 4 using the Angular CLI tool,

$ npm install -g @angular/cli

Create a new app or project,

$ ng new my-new-app

This creates a new directory, next move in to it,

$ cd my-new-app

Run the app in development,

$ ng serve

Install bootstrap,

$ npm install --save bootstrap

Then add bootstrap to .angular-cli.json which can be found in the root of the project. Find the ‘styles’ and add the path for bootstrap like this,

"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
],

It may be necessary here to run,

$ npm install

from the project root directory, the directory containing the node_modules directory.

You can then use bootstrap in my-new-app/src/app/app.component.html

<div class="container">
  <div class="row">
    <div class="col-md-4">one</div>
    <div class="col-md-4">two</div>
    <div class="col-md-4">three</div>
  </div>
</div>