From f3581956d90ff93b68f6602df63a5bcc1deacf52 Mon Sep 17 00:00:00 2001 From: Ahsan Ayaz Date: Thu, 5 May 2016 23:03:35 +0500 Subject: [PATCH 1/3] First view and initial routing done Encapsulated styles from app component for global styles --- index.html | 3 ++ src/app/app.component.ts | 39 ++++++++++++++++++++++++ src/app/app.styles.css | 36 ++++++++++++++++++++++ src/app/app.view.html | 6 ++++ src/app/countries/countries.component.ts | 15 +++++++++ src/app/countries/countries.styles.css | 0 src/app/countries/countries.view.html | 1 + src/app/home/home.component.ts | 15 +++++++++ src/app/home/home.styles.css | 0 src/app/home/home.view.html | 10 ++++++ src/bootstrap.ts | 12 ++------ 11 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 src/app/app.component.ts create mode 100644 src/app/app.styles.css create mode 100644 src/app/app.view.html create mode 100644 src/app/countries/countries.component.ts create mode 100644 src/app/countries/countries.styles.css create mode 100644 src/app/countries/countries.view.html create mode 100644 src/app/home/home.component.ts create mode 100644 src/app/home/home.styles.css create mode 100644 src/app/home/home.view.html diff --git a/index.html b/index.html index 222e67a..5784fa6 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ + Angular 2 - Countries and Capitals @@ -15,6 +16,8 @@ + + + diff --git a/src/app/app-footer/app-footer.component.ts b/src/app/app-footer/app-footer.component.ts index e6ff289..4176435 100644 --- a/src/app/app-footer/app-footer.component.ts +++ b/src/app/app-footer/app-footer.component.ts @@ -13,8 +13,10 @@ export class AppFooterComponent implements OnInit { } ngOnInit() { } - isActive(instruction: any[]): boolean { - return this.router.isRouteActive(this.router.generate(instruction)); + + // this function returns whether the current route is the route passed in the function + isActive(route: any[]): boolean { + return this.router.isRouteActive(this.router.generate(route)); } } \ No newline at end of file diff --git a/src/app/app-footer/app-footer.view.html b/src/app/app-footer/app-footer.view.html index 873ba33..67af0cd 100644 --- a/src/app/app-footer/app-footer.view.html +++ b/src/app/app-footer/app-footer.view.html @@ -1,4 +1,4 @@
- Browse Countries - + Home + Browse Countries
\ No newline at end of file diff --git a/src/app/app-header/app-header.view.html b/src/app/app-header/app-header.view.html index 87f3e50..d853276 100644 --- a/src/app/app-header/app-header.view.html +++ b/src/app/app-header/app-header.view.html @@ -1,3 +1,3 @@

Countries & Capitals

-
\ No newline at end of file + \ No newline at end of file diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 4692729..946909e 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,12 @@ import { Component, OnInit, ViewEncapsulation} from 'angular2/core'; import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from 'angular2/router'; -import {HomeComponent} from './main/home/home.component'; -import {CountriesComponent} from './main/countries/countries.component'; import {AppHeaderComponent} from './app-header/app-header.component'; import {AppFooterComponent} from './app-footer/app-footer.component'; import {MainComponent} from './main/main.component'; +import {HomeComponent} from './main/home/home.component'; +import {CountriesComponent} from './main/countries/countries.component'; +import {CountryComponent} from './main/country/country.component'; + @Component({ moduleId:'appModule', selector: 'app', @@ -15,7 +17,7 @@ import {MainComponent} from './main/main.component'; encapsulation: ViewEncapsulation.None }) - +// defining routes here @RouteConfig([ { path: '/home', @@ -27,6 +29,11 @@ import {MainComponent} from './main/main.component'; path: '/countries', name: 'Countries', component:CountriesComponent + }, + { + path: '/country/:code', // eg localhost:3000/country/US, localhost:3000/country/PK etc + name: 'Country', + component:CountryComponent } ]) @@ -34,9 +41,8 @@ import {MainComponent} from './main/main.component'; export class AppComponent implements OnInit { constructor() { } - ngOnInit() { - - console.log("init"); + ngOnInit() { + console.log("app initiated"); } } \ No newline at end of file diff --git a/src/app/app.styles.css b/src/app/app.styles.css index 54da69f..475f463 100644 --- a/src/app/app.styles.css +++ b/src/app/app.styles.css @@ -3,7 +3,7 @@ .btn{ border:1px solid grey; border-radius: 4px; - padding: 4px; + padding: 4px 10px; color:black; } @@ -24,14 +24,10 @@ -moz-transition: 0.4s all ease; transition: 0.4s all ease; } -a.btn{ +a{ text-decoration: none; } -.main-view-container{ - margin: 40px; -} - /* APP COMPONENT STYLES*/ .header { diff --git a/src/app/countries.service.ts b/src/app/countries.service.ts new file mode 100644 index 0000000..3eb4630 --- /dev/null +++ b/src/app/countries.service.ts @@ -0,0 +1,33 @@ +import {Injectable} from 'angular2/core'; +import {Http} from 'angular2/http'; +import 'rxjs/add/operator/map'; +import { Observable } from 'rxjs/Observable'; + +@Injectable() +export class CountriesService { + + constructor (private http: Http) {} + private countriesUrl = 'http://api.geonames.org/searchJSON?q=country&username=ahsan.ubitian'; // URL to web api + private neighboursUrl = "http://api.geonames.org/neighboursJSON?username=ahsan.ubitian&country="; + private countryUrl = "http://api.geonames.org/countryInfoJSON?formatted=true&lang=it&username=ahsan.ubitian&style=full&country="; + + getCountries (){ + let url = this.countriesUrl; //url to be used for call + return this.http.get(url) + .map(res => res.json()) + .map((data) => { return data.geonames; });; + } + getCountry (countryCode){ + let url = this.countryUrl + countryCode; //url to be used for call (appending countryCode to make it like '&country=PK') + return this.http.get(url) + .map(res => res.json()) + .map((data) => { return data.geonames[0]; }); //since we expect [0] will have our required country + } + + getNeighbours(countryCode){ + let url = this.neighboursUrl + countryCode; //url to be used for call (appending countryCode to make it like '&country=PK') + return this.http.get(url) + .map(res => res.json()) + .map((data) => { return data.geonames; }); + } +} \ No newline at end of file diff --git a/src/app/main/countries/countries.component.ts b/src/app/main/countries/countries.component.ts index f36fb3b..bc9ec78 100644 --- a/src/app/main/countries/countries.component.ts +++ b/src/app/main/countries/countries.component.ts @@ -1,15 +1,33 @@ import { Component, OnInit } from 'angular2/core'; -import {ROUTER_DIRECTIVES} from 'angular2/router'; +import {ROUTER_DIRECTIVES, Router} from 'angular2/router'; +import {CountriesService} from '../../countries.service'; +import {SpinnerComponent} from '../../../shared/spinner/spinner.component'; +import { HTTP_PROVIDERS } from 'angular2/http'; @Component({ moduleId: 'countriesModule', selector: 'countries', templateUrl: 'src/app/main/countries/countries.view.html', styleUrls:['src/app/main/countries/countries.styles.css'], - directives: [ROUTER_DIRECTIVES] + directives: [ROUTER_DIRECTIVES,SpinnerComponent], + providers: [CountriesService,HTTP_PROVIDERS] }) export class CountriesComponent implements OnInit { - constructor() { } - - ngOnInit() { } + private countries = []; + private isRequesting: boolean = true; + constructor(private countriesService: CountriesService, private router:Router) { + //injected countriesService to use it later + } + ngOnInit() { + this.countriesService.getCountries() + .subscribe(countries => { + this.countries = countries; + this.isRequesting = false; //hide loader + }); + } + + onCountryClick(country){ + console.log(country); + this.router.navigate(['Country', {code:country.countryCode}]); //navigate to the desired router + } } \ No newline at end of file diff --git a/src/app/main/countries/countries.styles.css b/src/app/main/countries/countries.styles.css index e69de29..a5e204e 100644 --- a/src/app/main/countries/countries.styles.css +++ b/src/app/main/countries/countries.styles.css @@ -0,0 +1,13 @@ +#countriesTableContainer{ + max-height: 300px; + overflow: auto; +} +#countriesTable{ +} +#countriesTable td{ + text-align: center; +} +#countriesTable tr:hover{ + background-color: #dcdcdc; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/main/countries/countries.view.html b/src/app/main/countries/countries.view.html index bd830e3..56bf121 100644 --- a/src/app/main/countries/countries.view.html +++ b/src/app/main/countries/countries.view.html @@ -1,4 +1,17 @@ - -
-
My Countries
+ + +
+ + + + + + + + + + + + +
NameCountry CodePopulation
{{cnt.name}}{{cnt.countryCode}}{{cnt.population}}
\ No newline at end of file diff --git a/src/app/main/country/country.component.ts b/src/app/main/country/country.component.ts new file mode 100644 index 0000000..9c6866d --- /dev/null +++ b/src/app/main/country/country.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit, Pipe, PipeTransform } from 'angular2/core'; +import {ROUTER_DIRECTIVES, RouteParams} from 'angular2/router'; +import {CountriesService} from '../../countries.service'; +import {SpinnerComponent} from '../../../shared/spinner/spinner.component'; +import { HTTP_PROVIDERS } from 'angular2/http'; + +// We use the @Pipe decorator to register the name of the pipe +@Pipe({ + name: 'customLimit' +}) +// The work of the pipe is handled in the tranform method with our pipe's class +class CustomLimitPipe implements PipeTransform { + transform(array: Array, args: any[]) { + array = array.slice(0,3); + return array; + } +} + + + +@Component({ + moduleId: 'countryModule', + selector: 'country', + templateUrl: 'src/app/main/country/country.view.html', + styleUrls:['src/app/main/country/country.styles.css'], + directives: [ROUTER_DIRECTIVES,SpinnerComponent], + providers: [CountriesService,HTTP_PROVIDERS], + pipes:[CustomLimitPipe] +}) +export class CountryComponent implements OnInit { + private country = {}; + private neighbours = []; + private isRequesting: boolean = true; + constructor(countriesService: CountriesService,params: RouteParams) { + console.log(params); + console.log(params.get("code")); + // get country based on the country code (code) we have + countriesService.getCountry(params.get("code")) + .subscribe(country => { + this.country = country; + // get country neighbours + countriesService.getNeighbours(params.get("code")) + .subscribe(neighbours => { + this.neighbours = neighbours; + this.isRequesting = false; //hide the loader + }); + }); + } + ngOnInit() { } +} \ No newline at end of file diff --git a/src/app/main/country/country.styles.css b/src/app/main/country/country.styles.css new file mode 100644 index 0000000..7e1b39e --- /dev/null +++ b/src/app/main/country/country.styles.css @@ -0,0 +1,4 @@ +.country-container{ + max-width: 300px; + margin: 0 auto; +} \ No newline at end of file diff --git a/src/app/main/country/country.view.html b/src/app/main/country/country.view.html new file mode 100644 index 0000000..1d8a0b2 --- /dev/null +++ b/src/app/main/country/country.view.html @@ -0,0 +1,21 @@ + +
+
+

{{country.countryName}}

+
+
+

Population : {{country.population}}

+

Area : {{country.areaInSqKm}}

+

Capital : {{country.capital}}

+

Population : {{country.population}}

+ +

3 neighbours: + + + {{neigh.countryName}} + + , + +

+
+
\ No newline at end of file diff --git a/src/app/main/main.styles.css b/src/app/main/main.styles.css index e69de29..05654b7 100644 --- a/src/app/main/main.styles.css +++ b/src/app/main/main.styles.css @@ -0,0 +1,4 @@ +.main-view-container{ + min-height: 150px; + margin: 40px 100px; +} \ No newline at end of file diff --git a/src/app/main/main.view.html b/src/app/main/main.view.html index c49d708..8d50fc2 100644 --- a/src/app/main/main.view.html +++ b/src/app/main/main.view.html @@ -1,3 +1,5 @@ - \ No newline at end of file +
+ +
diff --git a/src/shared/spinner/spinner.component.ts b/src/shared/spinner/spinner.component.ts new file mode 100644 index 0000000..cdfa3a9 --- /dev/null +++ b/src/shared/spinner/spinner.component.ts @@ -0,0 +1,42 @@ +'use strict'; + +import {Component, Input, OnDestroy} from 'angular2/core'; + +@Component({ + selector: 'my-spinner', + templateUrl: 'src/shared/spinner/spinner.view.html', + styleUrls:['src/shared/spinner/spinner.styles.css'] +}) +export class SpinnerComponent implements OnDestroy { + private currentTimeout: number; + private isDelayedRunning: boolean = false; + + @Input() + public delay: number = 300; + + @Input() + public set isRunning(value: boolean) { + if (!value) { + this.cancelTimeout(); + this.isDelayedRunning = false; + } + + if (this.currentTimeout) { + return; + } + + this.currentTimeout = setTimeout(() => { + this.isDelayedRunning = value; + this.cancelTimeout(); + }, this.delay); + } + + private cancelTimeout(): void { + clearTimeout(this.currentTimeout); + this.currentTimeout = undefined; + } + + ngOnDestroy(): any { + this.cancelTimeout(); + } +} \ No newline at end of file diff --git a/src/shared/spinner/spinner.styles.css b/src/shared/spinner/spinner.styles.css new file mode 100644 index 0000000..4e7848d --- /dev/null +++ b/src/shared/spinner/spinner.styles.css @@ -0,0 +1,41 @@ +.spinner { + width: 40px; + height: 40px; + display: block; + position: relative; + margin: 100px auto; +} + +.double-bounce1, .double-bounce2 { + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #333; + opacity: 0.6; + position: absolute; + top: 0; + left: 0; + + -webkit-animation: sk-bounce 2.0s infinite ease-in-out; + animation: sk-bounce 2.0s infinite ease-in-out; +} + +.double-bounce2 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; +} + +@-webkit-keyframes sk-bounce { + 0%, 100% { -webkit-transform: scale(0.0) } + 50% { -webkit-transform: scale(1.0) } +} + +@keyframes sk-bounce { + 0%, 100% { + transform: scale(0.0); + -webkit-transform: scale(0.0); + } 50% { + transform: scale(1.0); + -webkit-transform: scale(1.0); + } +} \ No newline at end of file diff --git a/src/shared/spinner/spinner.view.html b/src/shared/spinner/spinner.view.html new file mode 100644 index 0000000..0083290 --- /dev/null +++ b/src/shared/spinner/spinner.view.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file