├── .editorconfig ├── .gitignore ├── README.md ├── notes.md ├── package.json ├── src ├── app.ts ├── demos │ ├── firebase │ │ └── firebasechat.ts │ ├── ngrx │ │ ├── todoapp.ts │ │ └── todos.ts │ └── typeahead │ │ └── typeahead.ts ├── favicon.ico ├── index.html └── main.ts ├── tsconfig.json ├── typings.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /typings/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fluent_demos 2 | Demo code from Reactive Angular2 @ Fluent 2016. Slides [here](https://docs.google.com/presentation/d/1pBM3Is5SrXn_wmK_sF2BDXZUm44BmoUT_Ohg9da6K1k/edit?usp=sharing) 3 | 4 | ## instructions 5 | 6 | - clone this repo 7 | - `npm install` 8 | - `npm install -g typings` 9 | - `typings install` 10 | - `npm start` 11 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | const BASE_URL = 'https://www.googleapis.com/youtube/v3/search'; 2 | const API_TOKEN = 'AIzaSyAJk1xUI72YYfBMgEc84gjHUX-k2AN6-B0'; 3 | 4 | `${BASE_URL}?q=${query}&part=snippet&key=${API_TOKEN}` 5 | 6 | 7 | 8 | 9 | 10 | 11 | https://ngnl-chat.firebaseio.com/ -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fluent-demos", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --inline --colors --display-error-details --display-cached --port 8000 --content-base src", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "postinstall": "typings install" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@ngrx/store": "1.3.3", 15 | "angular2": "2.0.0-beta.9", 16 | "angularfire2": "2.0.0-alpha.10", 17 | "es6-promise": "^3.0.2", 18 | "es6-shim": "^0.33.3", 19 | "firebase": "^2.4.0", 20 | "reflect-metadata": "^0.1.2", 21 | "rxjs": "5.0.0-beta.2", 22 | "zone.js": "^0.5.14" 23 | }, 24 | "devDependencies": { 25 | "ts-loader": "^0.8.1", 26 | "typescript": "^1.7.5", 27 | "webpack": "^1.12.13", 28 | "webpack-dev-server": "^1.14.1", 29 | "webpack-livereload-plugin": "^0.5.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core' 2 | import {ROUTER_PROVIDERS, ROUTER_DIRECTIVES, Router, RouteConfig} from 'angular2/router' 3 | 4 | import {TypeaheadDemo} from './demos/typeahead/typeahead.ts' 5 | import {FirebaseChat} from './demos/firebase/firebasechat.ts' 6 | import {TodoApp} from './demos/ngrx/todoapp.ts' 7 | 8 | @Component({ 9 | selector: 'app', 10 | template: ` 11 |
12 |

Reactive Angular2

13 |
14 | typeahead 15 | firebase 16 | todos 17 |
18 | 19 |
20 | `, 21 | directives: [ROUTER_DIRECTIVES], 22 | providers: [ROUTER_PROVIDERS] 23 | }) 24 | @RouteConfig([ 25 | {name: 'TypeaheadDemo', component: TypeaheadDemo, path: '/typeahead', useAsDefault: true}, 26 | {name: 'FirebaseChat', component: FirebaseChat, path: '/firebase'}, 27 | {name: 'TodoApp', component: TodoApp, path: '/todos'}, 28 | ]) 29 | export class App {} 30 | -------------------------------------------------------------------------------- /src/demos/firebase/firebasechat.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core' 2 | import {AngularFire, defaultFirebase, FIREBASE_PROVIDERS, FirebaseListObservable} from 'angularfire2' 3 | 4 | 5 | @Component({ 6 | selector: 'firebase-demo', 7 | template: ` 8 |

firebase demo

9 | 10 | 11 | 14 | `, 15 | providers: [ 16 | FIREBASE_PROVIDERS, 17 | defaultFirebase('https://fluent-chat-demo.firebaseio.com/') 18 | ] 19 | }) 20 | export class FirebaseChat { 21 | messages: FirebaseListObservable 22 | constructor(angularFire: AngularFire){ 23 | this.messages = angularFire.list('/messages'); 24 | } 25 | addMessage(el){ 26 | 27 | let newMessage = {text: el.value}; 28 | this.messages.add(newMessage); 29 | el.value = ''; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/demos/ngrx/todoapp.ts: -------------------------------------------------------------------------------- 1 | import {Component, Injectable} from 'angular2/core' 2 | import {provideStore, Store} from '@ngrx/store' 3 | import {todos} from './todos'; 4 | import {Observable} from 'rxjs/Rx' 5 | 6 | @Component({ 7 | selector: 'todo-app', 8 | template: ` 9 |

Todos

10 | 11 | 14 | `, 15 | providers: [provideStore({todos})] 16 | }) 17 | export class TodoApp { 18 | todos: Observable; 19 | constructor(private store:Store){ 20 | this.todos = store.select('todos'); 21 | } 22 | addTodo(el){ 23 | let text = el.value; 24 | this.store.dispatch({type: 'ADD_TODO', payload: {text}}); 25 | el.value = "" 26 | } 27 | deleteTodo(todo){ 28 | this.store.dispatch({type: 'DELETE_TODO', payload: todo}); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/demos/ngrx/todos.ts: -------------------------------------------------------------------------------- 1 | //todos reducer 2 | 3 | export const ADD_TODO = 'ADD_TODO'; 4 | export const UPDATE_TODO = 'UPDATE_TODO'; 5 | export const DELETE_TODO = 'DELETE_TODO'; 6 | export const COMPLETE_TODO = 'COMPLETE_TODO'; 7 | 8 | export const todos = (state = [], {type, payload}) => { 9 | switch(type){ 10 | case ADD_TODO: 11 | return state.concat([Object.assign({}, payload, {id: state.length + 1})]); 12 | case UPDATE_TODO: 13 | return state.map(todo => { 14 | return todo.id !== payload.id ? 15 | todo : 16 | Object.assign({}, todo, payload) 17 | }); 18 | case COMPLETE_TODO: 19 | return state.map(todo => { 20 | return todo.id !== payload.id ? 21 | todo : 22 | Object.assign({}, todo, {completed: true}) 23 | }); 24 | case DELETE_TODO: 25 | return state.filter(todo => todo.id !== payload.id); 26 | default: 27 | return state; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/demos/typeahead/typeahead.ts: -------------------------------------------------------------------------------- 1 | import {Component} from 'angular2/core' 2 | import {Control} from 'angular2/common' 3 | import {HTTP_PROVIDERS, Http, Response} from 'angular2/http' 4 | import 'rxjs/Rx' 5 | import {Observable} from 'rxjs/Observable' 6 | 7 | const BASE_URL = 'https://www.googleapis.com/youtube/v3/search'; 8 | const API_TOKEN = 'AIzaSyAJk1xUI72YYfBMgEc84gjHUX-k2AN6-B0'; 9 | 10 | const makeURL = (query) => `${BASE_URL}?q=${query}&part=snippet&key=${API_TOKEN}` 11 | 12 | @Component({ 13 | selector: 'my-typeahead', 14 | template: ` 15 | 16 |
    17 |
  • {{video | json}}
  • 18 |
19 | ` 20 | }) 21 | class MyTypeahead { 22 | videos: Observable; 23 | searchInput = new Control(); 24 | constructor(http: Http) { 25 | this.videos = this.searchInput.valueChanges 26 | //optionally debounce 27 | //.debounceTime(300) 28 | .map(inputText => makeURL(inputText)) 29 | //flatMap won't cancel in-flight requests, switchMap will... 30 | //.flatMap(url => http.get(url).map(res => res.json())) 31 | .switchMap(url => http.get(url).map(res => res.json())) 32 | .map(response => response['items']); 33 | } 34 | } 35 | 36 | 37 | @Component({ 38 | selector: 'typeahead-demo', 39 | template: ` 40 |

typeahead demo

41 | 42 | `, 43 | providers: [HTTP_PROVIDERS], 44 | directives: [MyTypeahead] 45 | }) 46 | export class TypeaheadDemo { 47 | constructor(private http: Http) { } 48 | } 49 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robwormald/fluent_demos/0eaf8fc86903188035146e53c6d7840e3e0382fc/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | fluent demos 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata' 2 | import 'zone.js' 3 | import {bootstrap} from 'angular2/platform/browser' 4 | import {enableProdMode} from 'angular2/core' 5 | import {App} from './app' 6 | 7 | enableProdMode(); 8 | 9 | bootstrap(App) 10 | .catch(console.log.bind(console)); 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "noImplicitAny": false, 6 | "sourceMap": false, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "suppressExcessPropertyErrors": true, 10 | "suppressImplicitAnyIndexErrors": true 11 | }, 12 | "files": [ 13 | "typings/browser.d.ts", 14 | "src/main.ts" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ambientDependencies": { 3 | "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", 4 | "firebase": "github:DefinitelyTyped/DefinitelyTyped/firebase/firebase.d.ts#e2251a6de4ec74c4c71cbb04baccdd261a643909" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var LiveReloadPlugin = require('webpack-livereload-plugin'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | resolve: { 6 | extensions: ['', '.scss', '.ts', '.js'] 7 | }, 8 | 9 | plugins: [ 10 | new LiveReloadPlugin({ 11 | appendScriptTag: true 12 | }) 13 | ], 14 | 15 | entry: './src/main.ts', 16 | output: { 17 | path: "./dist", 18 | publicPath: 'dist/', 19 | filename: "bundle.js" 20 | }, 21 | 22 | devtool: 'source-map', 23 | 24 | module: { 25 | loaders: [ 26 | { 27 | test: /\.ts$/, 28 | loader: 'ts-loader' 29 | }, 30 | { 31 | test: /\.css$/, 32 | loader: 'style-loader' 33 | } 34 | ] 35 | }, 36 | 37 | devServer: { 38 | historyApiFallback: true 39 | } 40 | }; 41 | --------------------------------------------------------------------------------