Skip to content

Instantly share code, notes, and snippets.

@johnlindquist
Last active October 30, 2018 12:23
Show Gist options
  • Save johnlindquist/3682134ab53c08b809fd789dcb319df9 to your computer and use it in GitHub Desktop.
Save johnlindquist/3682134ab53c08b809fd789dcb319df9 to your computer and use it in GitHub Desktop.
Angular 2 Wikipedia Image Search

Angular2 Starter Gist Run

SystemJS.config({
transpiler: "typescript",
typescriptOptions: {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
map: {
"rxjs": "https://npmcdn.com/rxjs@5.0.0-beta.6",
"angular2": "https://npmcdn.com/angular2@2.0.0-beta.15",
"typescript": "https://npmcdn.com/typescript@1.8.10/lib/typescript.js"
},
packages: {
"rxjs": { "defaultExtension": "js" },
"angular2": { "defaultExtension": "js" },
"@ngrx/store":{
"main":"dist/index.js"
},
"src": { "defaultExtension": "ts" },
"build": { "defaultExtension": "ts" }
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Angular 2 App</title>
<script src="https://npmcdn.com/angular2/bundles/angular2-polyfills.js"></script>
<script src="https://npmcdn.com/systemjs/dist/system.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<app></app>
<script src="config.js"></script>
<script>System.import('src/main');</script>
</body>
</html>
import {Component} from 'angular2/core';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/concatAll';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/scan';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/reduce';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/combineLatest';
import 'rxjs/add/operator/withLatestFrom';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/concat';
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/operator/race';
import 'rxjs/add/operator/mapTo';
import 'rxjs/add/observable/bindCallback';
import 'rxjs/add/observable/merge';
import {JSONP_PROVIDERS, HTTP_PROVIDERS, Http, Jsonp} from 'angular2/http';
import {Subject} from 'rxjs/Subject';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {WikipediaService} from './services/wikipedia.service';
import {Observable} from 'rxjs/Observable';
@Component({
selector: 'app',
providers: [HTTP_PROVIDERS, JSONP_PROVIDERS, WikipediaService]
template: `
<style>
.container{
width: 350px;
}
img{
width: 90px;
border: 5px solid black;
}
img:hover {
width: 90px;
border: 5px solid gray;
}
</style>
<div>
<h2>Search: {{(searchTerm$ | async)}}</h2>
<input type="text" (input)="input$.next($event)">
<h3>{{imageCount$ | async}} results</h3>
<div class="container">
<a *ngFor="#image of images$ | async" [href]="image.descriptionurl">
<img [src]="image.url" alt="">
</a>
</div>
</div>
`
})
export class App {
input$ = new Subject().map(event => event.target.value);
searchTerm$;
images$;
imageCount$;
constructor(wikipediaService:WikipediaService) {
this.searchTerm$ = this.input$
.distinctUntilChanged()
.debounceTime(500)
.filter(term => term.length > 0)
.share();
this.images$ = this.searchTerm$
.switchMap(term=> wikipediaService.searchAllImages(term)
.map(wikipediaService.mapAllImagesToTitles)
.concatAll()
.mergeMap(wikipediaService.getImageInfoFromTitle)
.map(wikipediaService.mapImageInfoToUrls)
.scan((acc, curr)=> [...acc, ...curr])
)
.startWith([])
.share()
this.imageCount$ = this.images$
.map(results => results.length)
}
}
import {enableProdMode} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
enableProdMode();
bootstrap(App)
.catch(console.log.bind(console));
console.clear();
import {Injectable} from 'angular2/core';
import {Jsonp} from 'angular2/http';
const CALLBACK = 'callback=JSONP_CALLBACK';
const WIKIPEDIA = 'https://en.wikipedia.org/w/api.php';
const QUERY = 'action=query';
const JSON = 'format=json';
const ALLIMAGES = 'list=allimages';
const IMAGEINFO = 'prop=imageinfo';
const API = `${WIKIPEDIA}?${QUERY}&${JSON}&${CALLBACK}&${ALLIMAGES}`;
const PROP_URL = 'iiprop=url';
@Injectable()
export class WikipediaService{
constructor(private _jsonp:Jsonp){}
searchAllImages = term => this._jsonp.get(`${API}&${ALLIMAGES}&aifrom=${term}`)
.map(res => res.json());
mapAllImagesToTitles = allImages => allImages.query.allimages.map(({title}) => title);
getImageInfoFromTitle= title => this._jsonp.get(`${API}&${IMAGEINFO}&${PROP_URL}&titles=${title}`)
.map(res => res.json());
mapImageInfoToUrls = body => Object.keys(body.query.pages)
.filter(page => page > 0) //page -1 means no images
.map(page =>{
return body.query.pages[page].imageinfo[0];
});
}
/* Styles go here */
body{
font-family: sans-serif;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment