<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Angular2 + Youtube Search</title>
<link rel="stylesheet" href="styles.css">
<!-- ES6-related imports -->
<script src="http://cdn.rawgit.com/google/traceur-compiler/90da568c7aa8e53ea362db1fc211fbb4f65b5e94/bin/traceur-runtime.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/systemjs/0.18.4/system.js"></script>
<script src="config.js"></script>
<!-- Angular2 import -->
<script src="http://code.angularjs.org/2.0.0-alpha.35/angular2.dev.js"></script>
<script src="http://code.angularjs.org/2.0.0-alpha.35/http.dev.js"></script>
<script>
//bootstrap the Angular2 application
System.import('app').catch(console.log.bind(console));
</script>
</head>
<body>
<youtube-app>Loading...</youtube-app>
</body>
</html>
import {
bind,
bootstrap,
Component,
View,
Injectable,
CORE_DIRECTIVES,
ON_PUSH
} from 'angular2/angular2';
import {
Http, HTTP_BINDINGS
} from 'http/http'
import {
FormBuilder,
Validators,
FORM_BINDINGS,
FORM_DIRECTIVES
} from 'angular2/forms';
import {RxPipe} from './rxPipe';
import {YouTubeAPI} from './YouTube'
@Component({
selector: 'search-result',
properties: ['video'],
changeDetection: ON_PUSH
})
@View({
template: `
<div style="border: 1px solid black">
<h3>{{video.snippet.title}}</h3>
<h4>{{video.snippet.channelTitle}}</h4>
<div>
<img [src]="video.snippet.thumbnails.default.url"></img>
</div>
</div>
`
})
class SearchResult {}
@Component({
selector: 'youtube-app',
changeDetection: ON_PUSH
})
@View({
template: `
<div>
<h3>angular2 + youtube search</h3>
<form [ng-form-model]="youtubeQuery">
<input type="text" ng-control="title">
</form>
<div *ng-for="#video of videos | rx">
<search-result [video]="video"></search-result>
</div>
</div>
`,
directives: [CORE_DIRECTIVES, FORM_DIRECTIVES, SearchResult],
pipes: [RxPipe]
})
export class YouTubeApp {
constructor(youtube: YouTubeAPI,formBuilder:FormBuilder){
this.youtubeQuery = formBuilder.group({
title: ["", Validators.required]
});
let queries = this.youtubeQuery.valueChanges.toRx();
this.videos = queries.flatMapLatest(query => youtube.search(query.title));
}
}
bootstrap(YouTubeApp,[FORM_BINDINGS, HTTP_BINDINGS, YouTubeAPI])
.catch(err => console.log(err));
/// https://gist.github.com/jashmenn/d8f5cbf5fc20640bac30
/// <reference path="../../typings/app.d.ts" />
//
// Creates a pipe suitable for a RxJS observable:
//
// @View({
// template: '{{ someObservable | rx}}'
// pipes: [RxPipe]
// })
//
// Originally written by @gdi2290 but updated for 2.0.0.alpha-35 and use AsyncPipe
// (Soon the Angular team will be using RxJS natively and this pipe will be
// unnecessary because we'll be able to use the `async` pipe.)
//
// References:
// * rxPipeRegistry.ts https://gist.github.com/gdi2290/e9b2880a1d13057197d7 by @gdi2290
// * AsyncPipe https://github.com/angular/angular/blob/master/modules/angular2/src/pipes/async_pipe.ts
import {PipeFactory, Pipe, Injectable, bind, ChangeDetectorRef} from "angular2/angular2";
import {AsyncPipe} from "angular2/pipes";
import * as Rx from 'rx';
import {Observable} from 'rx';
function isObservable(obs) {
console.log(obs)
return obs && typeof obs.subscribe === 'function';
}
class RxStrategy {
createSubscription(async: any, updateLatestValue: any): any {
return async.subscribe((values) => {
updateLatestValue(values);
}, e => { throw e; });
}
dispose(subscription: any): void { subscription.dispose(); }
onDestroy(subscription: any): void { subscription.dispose(); }
}
var _rxStrategy = new RxStrategy();
@Pipe({name: 'rx'})
export class RxPipe extends AsyncPipe {
constructor(public _ref: ChangeDetectorRef) { super(_ref); }
supports(obs) { return isObservable(obs); }
_selectStrategy(obj: Observable<any>): any {
return _rxStrategy;
}
}
export var rxPipeInjectables: Array<any> = [
bind(RxPipe).toValue(RxPipe)
];
System.config({
defaultJSExtensions: true,
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true
},
map: {
typescript: 'https://cdn.rawgit.com/robwormald/9883afae87bffa2f4e00/raw/8bca570a696c47a4f8dd03a52c98734676e94cea/typescript.js',
'rx.all': 'https://cdnjs.cloudflare.com/ajax/libs/rxjs/3.1.1/rx.all.js',
'redux': 'https://cdn.rawgit.com/rackt/redux/master/src/index.js'
},
paths: {
app: 'src'
},
packages: {
app: {
main: 'app.ts',
defaultExtension: 'ts',
}
}
});
.completed {
color:red;
text-decoration:line-through;
}
### angular2 + http
searchin' youtube with ng2http and pipes
import {Http, HttpConfig} from 'http/http';
import {Injectable} from 'angular2/angular2';
import {Observable} from 'rx'
const BASE_URL = 'https://www.googleapis.com/youtube/v3/search';
const API_TOKEN = 'AIzaSyAJk1xUI72YYfBMgEc84gjHUX-k2AN6-B0';
@Injectable()
export class YouTubeAPI {
constructor(http:Http){
this.http = http;
}
search(query){
//wouldnt need this if .partition was in angular2's rx :(
if(!query.length){
return Observable.just([])
}
return this.http.get(`${BASE_URL}?q=${query}&part=snippet&key=${API_TOKEN}`)
.toRx()
.map(res => res.json())
.map(json => json.items);
}
}