Skip to content

Instantly share code, notes, and snippets.

@ysyun
Created July 21, 2016 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ysyun/b9e19db765b079979479fbc535c79af4 to your computer and use it in GitHub Desktop.
Save ysyun/b9e19db765b079979479fbc535c79af4 to your computer and use it in GitHub Desktop.
Angular 2 - New Router rc.5 - lazyloading & all option
[{
"id": 34,
"username": "spiderman",
"roles": ["admin", "user"]
}, {
"id": 67,
"username": "batman",
"roles": ["user"]
}]
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'about',
template: `
<h1>About</h1>
<p>Magic Number: {{magicNumber}}</p>
`
})
export class About {
magicNumber: number;
constructor(private route: ActivatedRoute){
console.log('Called constructor');
// resolved data available from:
// route.snapshot.data: any
// route.data: Observable<any>
this.magicNumber = route.snapshot.data.magicNumber;
}
}
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AboutResolver implements Resolve {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<any> {
console.log('Waiting to resolve...');
let p = new Promise(resolve => setTimeout(() => resolve(4545), 2000));
//let p = new Promise(resolve => resolve(window.confirm('Resolve?')));
return Observable.from(p);
}
}
import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
@Component({
selector: 'my-app',
template: `
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" [routerLink]="['home']">Logo</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" ng-controller="HeaderController as header">
<ul class="nav navbar-nav">
<li routerLinkActive="active">
<a [routerLink]="['home']">Home</a>
</li>
<li routerLinkActive="active">
<a [routerLink]="['users']">Users</a>
</li>
<li routerLinkActive="active">
<a [routerLink]="['about']">About</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid slide">
<router-outlet></router-outlet>
<router-outlet name="bottom"></router-outlet>
</div>
`,
directives: [ROUTER_DIRECTIVES]
})
export class App { }
import { RouterConfig } from '@angular/router';
import { Home } from './home.component';
import { About } from './about.component';
import { NotFound } from './notfound.component';
import { Banner } from './banner.component';
import { usersRoutes } from './users.routes';
import { USERS_GARDS } from './users.routes';
import { AuthCanActivate } from './auth.canActivate';
import { AboutResolver } from './about.resolver';
export const routes: RouterConfig = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: Home },
{ path: 'about', component: About,
resolve: { magicNumber: AboutResolver}
},
...usersRoutes,
{
path: 'banner',
component: Banner,
outlet: 'bottom'
},
{ path: '**', component: NotFound }, //always last
];
export const APP_GARDS = [
USERS_GARDS,
AuthCanActivate,
AboutResolver
];
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { LoginService } from './login.service';
@Injectable()
export class AuthCanActivate implements CanActivate {
constructor(private loginService: LoginService, private router: Router) {}
canActivate() {
console.log('Called CanActivate');
if (!this.loginService.authorised) {
this.router.navigate(['/home']);
return false;
}
return true;
}
}
import { Component } from '@angular/core';
@Component({
selector: 'banner',
template: `
<img src="http://stream1.gifsoup.com/view6/2427161/spider-roll-o.gif">
`
})
export class Banner { }
import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { LoginService } from './login.service';
@Component({
selector: 'home',
template: `
<h1>Home</h1>
<div class="onoffswitch">
<input #switch type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="myonoffswitch" [checked]="loginService.authorised" (click)="change(switch.checked)">
<label class="onoffswitch-label" for="myonoffswitch"></label>
</div>
<p>Logged: <span>{{loginService.authorised?'Yes':'No'}}</span></p>
<div *ngIf="loginService.authorised">
<a href="#/users/34">Today's best superheroe</a><br/>
<pre>&lt;a href=&quot;#/users/34&quot;&gt;Today's best superheroe&lt;/a&gt;</pre>
<a [routerLink]="['/users', 34, {flag: true}]" [queryParams]="{q: 1}">Today's best superheroe</a>
<pre>&#x3C;a [routerLink]=&#x22;[&#x27;/users&#x27;, 34, {flag: true}]&#x22; [queryParams]=&#x22;{q: 1}&#x22;&#x3E;Today&#x27;s best superheroe&#x3C;/a&#x3E;</pre>
<!--
<a href="#/home(bottom:banner)">Navigate Bottom</a><br/>
<a href="#/about(bottom:banner)">Navigate Both</a><br/>
-->
</div>
`,
directives: [ROUTER_DIRECTIVES]
})
export class Home {
constructor(private loginService:LoginService) { }
change(checked){
this.loginService.authorise(checked);
}
}
import { Injectable } from '@angular/core';
@Injectable()
export class LoginService {
authorised = false;
authorise(value) {
this.authorised = value;
}
}
// main entry point
import { bootstrap } from '@angular/platform-browser-dynamic';
import { App } from './app.component';
import { LoginService } from './login.service';
import { provideRouter } from '@angular/router';
import { HashLocationStrategy, LocationStrategy } from '@angular/common';
import { routes, APP_GARDS } from './app.routes';
bootstrap(App, [
...APP_GARDS,
provideRouter(routes),
{ provide: LocationStrategy, useClass: HashLocationStrategy },
LoginService, // Singleton
])
.catch(err => console.error(err));
import { Component } from '@angular/core';
@Component({
selector: 'notfound',
template: '<h1>404</h1>'
})
export class NotFound { }
import { CanDeactivate } from '@angular/router';
import { User } from './user.component';
import { Injectable } from '@angular/core';
Injectable()
export class UserCanDeactivate implements CanDeactivate<User> {
canDeactivate() {
return window.confirm('Do you want to continue?');
}
}
import { Component, OnInit } from '@angular/core';
import { ROUTER_DIRECTIVES, ActivatedRoute, Router } from '@angular/router';
import 'rxjs/add/operator/map';
import { HTTP_PROVIDERS } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { UsersService } from './users.service';
import { LoginService } from './login.service';
@Component({
selector: 'user-details',
template: `
<h1>User Details</h1>
<div class="loader loader--style1" title="Loading..." *ngIf="loading">
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 20 20"
to="360 20 20"
dur="0.5s"
repeatCount="indefinite"/>
</path>
</svg>
</div>
<div class="user-details" *ngFor="let user of users | async">
<p>Id: {{user.id}}</p>
<p>Username: {{user.username}}</p>
<p>Roles: {{user.roles.join(', ')}}</p>
<p>CONFIDENTIAL INFORMATION</p>
<a [routerLink]="['/users']">Back</a>
</div>
`,
providers: [UsersService, HTTP_PROVIDERS],
directives: [ROUTER_DIRECTIVES]
})
export class User implements OnInit {
loading = true;
constructor(private service: UsersService, private route: ActivatedRoute, private router: Router ){
//this.route.url.subscribe(s =>
// console.log(router.createUrlTree(s).toString())
//);
}
ngOnInit() {
console.log('Called constructor');
// active url
console.log(this.router.url);
// queryParams:
// router.routerState.snapshot.queryParams : {string:any}
// router.routerState.queryParams : Observable<{string:any}>
this.router.routerState.queryParams.subscribe(p => console.log(p));
// data:
// route.snapshot.data : {string:any}
// route.data : Observable<{string:any}>
this.route.data.subscribe(data => console.log(data));
// params:
// route.snapshot.params : {string:any}
// route.params : Observable<{string:any}>
this.route.params.subscribe(params => {
let id = params.id;
let flag = params.flag;
// parameters that don't match are added to the url and accessible
// Eg: ['user', 34, {flag: true}] becomes #/user/34;flag=true
if (flag) console.log('flag: ' + flag);
this.users = this.service.get()
.map(users => {
this.loading = false;
return users.filter(u => {
return u.id == id;
})
});
});
}
}
import { Component } from '@angular/core';
import { ROUTER_DIRECTIVES } from '@angular/router';
import { HTTP_PROVIDERS } from '@angular/http';
import { UsersService } from './users.service';
import { LoginService } from './login.service';
@Component({
selector: 'users',
template: `
<h1>Users</h1>
<table class="table">
<thead>
<tr>
<th>id</th>
<th>Username</th>
<th>Roles</th>
</tr>
</thead>
<tbody>
<tr *ngIf="!users">
<div class="loader loader--style1" title="Loading..." >
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml"
attributeName="transform"
type="rotate"
from="0 20 20"
to="360 20 20"
dur="0.5s"
repeatCount="indefinite"/>
</path>
</svg>
</div>
<tr>
<tr *ngFor="let user of users | async">
<td>{{user.id}}</td>
<td>
<a *ngIf="loginService.authorised" [routerLink]="['/users', user.id]">{{user.username}}</a>
<span *ngIf="!loginService.authorised">{{user.username}}</span>
</td>
<td>{{user.roles.join(', ')}}</td>
</tr>
</tbody>
</table>
<div class="container-fluid slide">
</div>
`,
providers: [UsersService, HTTP_PROVIDERS],
directives: [ROUTER_DIRECTIVES]
})
export class Users {
constructor(private service:UsersService, private loginService:LoginService){
this.users = service.get();
}
}
import { RouterConfig } from '@angular/router';
import { Users } from './users.component';
import { User } from './user.component';
import { UserCanDeactivate } from './user.canDeactivate';
import { AuthCanActivate } from './auth.canActivate';
export const usersRoutes: RouterConfig = [
{
path: 'users',
component: Users
},
{
path: 'users/:id',
component: User,
canActivate: [AuthCanActivate],
canDeactivate: [UserCanDeactivate],
data: { key: 1 } // has to be an object
}
];
export const USERS_GARDS = [
UserCanDeactivate
];
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/retryWhen';
import 'rxjs/add/operator/delay';
@Injectable()
export class UsersService {
constructor(private http:Http) { }
get(){
return this.http.get('api/users.json')
.map(response => response.json())
.retryWhen(errors => errors.delay(2000));
}
}
<!DOCTYPE html>
<html>
<head>
<!-- Set the base href -->
<script>document.write('<base href="' + document.location + '" />');</script>
<title>Router Sample</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap 3 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="https://npmcdn.com/core-js/client/shim.min.js"></script>
<script src="https://npmcdn.com/zone.js@0.6.12?main=browser"></script>
<script src="https://npmcdn.com/reflect-metadata@0.1.3"></script>
<script src="https://npmcdn.com/systemjs@0.19.27/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app')
.catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>
<div id="container">
<div class="box"><h1>Loading...</h1></div>
<div class="box">
<img src="https://49.media.tumblr.com/e031a970961e16125d56faa90cbc657d/tumblr_n34fi1vhSW1suivyoo4_500.gif" width="300px" />
</div>
</div>
</my-app>
</body>
</html>
@import url(https://fonts.googleapis.com/css?family=Ubuntu:500);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono);
body {
margin: 0;
font-family: "Ubuntu";
}
a:link,
a:visited {
border: none;
color: rgb(255, 0, 100);
text-decoration: none;
}
#container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.box {
width: 300px;
margin: 5px;
text-align: center;
}
ul {
list-style-type: none;
padding: 0;
}
.list {
max-height: 150px;
width: 100%;
overflow-y: auto;
background-color: #fff;
border: 1px solid #eee;
}
.result {
padding: 10px;
cursor: pointer;
}
.result:hover,
.result:hover a {
background-color: rgb(255, 0, 100);
color: #fff;
text-decoration: none;
}
.user-details {
background-color: #eee;
padding: 10px;
}
/*
Set the color of the icon
*/
svg path,
svg rect{
fill: rgb(255, 0, 100);
}
/* https://proto.io/freebies/onoff */
.onoffswitch {
position: relative; width: 71px;
-webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block; overflow: hidden; cursor: pointer;
height: 31px; padding: 0; line-height: 31px;
border: 2px solid #CCCCCC; border-radius: 31px;
background-color: #FFFFFF;
transition: background-color 0.3s ease-in;
}
.onoffswitch-label:before {
content: "";
display: block; width: 33px; margin: 0px;
background: #FFFFFF;
position: absolute; top: 0; bottom: 0;
right: 38px;
border: 2px solid #CCCCCC; border-radius: 31px;
transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label {
background-color: rgb(255, 0, 100);
}
.onoffswitch-checkbox:checked + .onoffswitch-label, .onoffswitch-checkbox:checked + .onoffswitch-label:before {
border-color: rgb(255, 0, 100);
}
.onoffswitch-checkbox:checked + .onoffswitch-label:before {
right: 0px;
}
/**
* PLUNKER VERSION (based on systemjs.config.js in angular.io)
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function(global) {
var ngVer = '@2.0.0-rc.4'; // lock in the angular package version; do not let it float to current!
var routerVer = '@3.0.0-beta.2'; // lock router version
var formsVer = '@0.2.0'; // lock forms version
var routerDeprecatedVer = '@2.0.0-rc.2'; // temporarily until we update all the guides
//map tells the System loader where to look for things
var map = {
'app': 'app',
'@angular': 'https://npmcdn.com/@angular', // sufficient if we didn't pin the version
'@angular/router': 'https://npmcdn.com/@angular/router' + routerVer,
'@angular/forms': 'https://npmcdn.com/@angular/forms' + formsVer,
'@angular/router-deprecated': 'https://npmcdn.com/@angular/router-deprecated' + routerDeprecatedVer,
'angular2-in-memory-web-api': 'https://npmcdn.com/angular2-in-memory-web-api', // get latest
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6',
'ts': 'https://npmcdn.com/plugin-typescript@4.0.10/lib/plugin.js',
'typescript': 'https://npmcdn.com/typescript@1.9.0-dev.20160409/lib/typescript.js',
};
//packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.ts', defaultExtension: 'ts' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
};
var ngPackageNames = [
'common',
'compiler',
'core',
'http',
'platform-browser',
'platform-browser-dynamic',
'upgrade',
];
// Add map entries for each angular package
// only because we're pinning the version with `ngVer`.
ngPackageNames.forEach(function(pkgName) {
map['@angular/'+pkgName] = 'https://npmcdn.com/@angular/' + pkgName + ngVer;
});
// Add package entries for angular packages
ngPackageNames.forEach(function(pkgName) {
// Bundled (~40 requests):
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
// Individual files (~300 requests):
//packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
// No umd for router yet
packages['@angular/router'] = { main: 'index.js', defaultExtension: 'js' };
// Forms not on rc yet
packages['@angular/forms'] = { main: 'index.js', defaultExtension: 'js' };
// Temporarily until we update the guides
packages['@angular/router-deprecated'] = { main: '/bundles/router-deprecated' + '.umd.js', defaultExtension: 'js' };
var config = {
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
tsconfig: true
},
meta: {
'typescript': {
"exports": "ts"
}
},
map: map,
packages: packages
};
System.config(config);
})(this);
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment