diff --git a/app/app-routing.module.ts b/app/app-routing.module.ts
new file mode 100644
index 0000000..739b378
--- /dev/null
+++ b/app/app-routing.module.ts
@@ -0,0 +1,30 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+
+import { NotFoundComponent } from './pages/not-found/not-found.component';
+import { DefaultChangeDetectionComponent } from './pages/default/default-change-detection.component';
+import { ManualChangeDetectionComponent } from './pages/manual/manual-change-detection.component';
+import { OnPushChangeDetectionComponent } from './pages/on-push/on-push-change-detection.component';
+import { OnPushChangeDetectionObservablesComponent } from './pages/on-push-observables/on-push-change-detection-observables.component';
+
+import { AuthGuard } from './secure/auth-guard.service';
+
+const appRoutes: Routes = [
+ { path: 'default-change-detection', component: DefaultChangeDetectionComponent },
+ { path: 'on-push-change-detection', component: OnPushChangeDetectionComponent },
+ { path: 'on-push-change-detection-observables', component: OnPushChangeDetectionObservablesComponent },
+ { path: 'manual-change-detection', component: ManualChangeDetectionComponent },
+ { path: '', redirectTo: '/default-change-detection', pathMatch: 'full' },
+ { path: '**', component: NotFoundComponent }
+];
+
+@NgModule({
+ imports: [
+ RouterModule.forRoot(appRoutes)
+ ],
+ exports: [
+ RouterModule
+ ]
+})
+export class AppRoutingModule { }
diff --git a/app/app.component.ts b/app/app.component.ts
index 00fd09b..3b0e758 100644
--- a/app/app.component.ts
+++ b/app/app.component.ts
@@ -1,9 +1,36 @@
-import { Component } from '@angular/core';
+import { Component, ViewChild, forwardRef } from '@angular/core';
+
+import { Subject } from 'rxjs/Subject';
@Component({
selector: 'my-app',
template: `
-
Angular 2 Systemjs start
+
+ Investigation ng2 Change Detection
+
+
+
+
+
+
+
+
`
})
-export class AppComponent { }
\ No newline at end of file
+export class AppComponent {
+ ngOnChange() {
+
+ }
+
+ ngOnInit() {
+ console.log('App component ngOnInit');
+ }
+
+}
\ No newline at end of file
diff --git a/app/app.module.ts b/app/app.module.ts
index e096758..6e37186 100644
--- a/app/app.module.ts
+++ b/app/app.module.ts
@@ -3,9 +3,36 @@ import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
+import { AppRoutingModule } from './app-routing.module';
+
+import { DefaultChangeDetectionComponent, defaultComponents } from './pages/default/default-change-detection.component';
+import { ManualChangeDetectionComponent, manualComponents } from './pages/manual/manual-change-detection.component';
+import { OnPushChangeDetectionComponent, onPushComponents } from './pages/on-push/on-push-change-detection.component';
+import { OnPushChangeDetectionObservablesComponent, observableComponents } from './pages/on-push-observables/on-push-change-detection-observables.component';
+
+import { NotFoundComponent } from './pages/not-found/not-found.component';
+
@NgModule({
- imports: [ BrowserModule ],
- declarations: [ AppComponent ],
+ imports: [
+ BrowserModule,
+ AppRoutingModule
+ ],
+ declarations: [
+ AppComponent,
+ DefaultChangeDetectionComponent,
+ defaultComponents,
+
+ ManualChangeDetectionComponent,
+ manualComponents,
+
+ OnPushChangeDetectionComponent,
+ onPushComponents,
+
+ OnPushChangeDetectionObservablesComponent,
+ observableComponents,
+
+ NotFoundComponent
+ ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
\ No newline at end of file
diff --git a/app/pages/default/default-change-detection.component.ts b/app/pages/default/default-change-detection.component.ts
new file mode 100644
index 0000000..408daa1
--- /dev/null
+++ b/app/pages/default/default-change-detection.component.ts
@@ -0,0 +1,142 @@
+import { Component, ElementRef, NgZone, ViewChild } from '@angular/core';
+
+import { Subject } from 'rxjs/Subject';
+
+import { toggleClass } from 'app/services/toggle-class.service';
+
+@Component({
+ selector: 'default-change-detection-component',
+ template: `
+ Default Change Detection
+ This demo shows how change detection is performed for each component after every VM turn. All components should light
+ up when:
+
+
+ The app is bootstrapped (reload browser to double-check)
+ Click "Trigger CD", performs CD everywhere
+
+
+
+ Trigger Change Detection
+
+
+
+ `,
+ providers: []
+})
+export class DefaultChangeDetectionComponent {}
+
+
+class ToggleClass {
+ constructor(private zone: NgZone, private el: ElementRef) { }
+
+ ngAfterViewChecked() {
+ toggleClass(this.el, this.zone);
+ }
+}
+
+@Component({
+ selector: 'default1',
+ template: `
+ Comp1
+
+ `
+})
+export class Default1 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+@Component({
+ selector: 'default2',
+ template: `
+ Comp2
+
+ `
+})
+export class Default2 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'default3',
+ template: `
+ Comp3
+
+ `
+})
+export class Default3 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'default4',
+ template: 'Comp4 '
+})
+export class Default4 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'default5',
+ template: 'Comp5 '
+})
+export class Default5 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'default6',
+ template: 'Comp6 '
+})
+export class Default6 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'default7',
+ template: 'Comp7 '
+})
+export class Default7 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+export const defaultComponents = [
+ Default1,
+ Default2,
+ Default3,
+ Default4,
+ Default5,
+ Default6,
+ Default7
+];
\ No newline at end of file
diff --git a/app/pages/manual/manual-change-detection.component.ts b/app/pages/manual/manual-change-detection.component.ts
new file mode 100644
index 0000000..d4ca01f
--- /dev/null
+++ b/app/pages/manual/manual-change-detection.component.ts
@@ -0,0 +1,340 @@
+import { Component, ChangeDetectorRef, forwardRef, Inject, ChangeDetectionStrategy, Input, NgZone, ElementRef } from '@angular/core';
+import { Subject } from 'rxjs/Rx';
+
+import { toggleClass } from 'app/services/toggle-class.service';
+
+@Component({
+ selector: 'manual-cd',
+ template: `
+ Manual Change Detection
+ This demo shows how a change detector is detached from the change detector tree
+ and performes change detection manually.
+
+
+
+ The app is bootstrapped (reload browser to double-check)
+ Click "Trigger CD", skips Comp2 and Comp6 subtrees
+ Attach cdRef, performs CD everywhere (onPush component is getting input changes)
+ Click "Trigger CD", skips Comp2 subtree
+
+
+
+ Trigger Change Detection
+
+
+ Attach/Detach Change Detector
+
+
+
+
+ `
+})
+export class ManualChangeDetectionComponent {
+ attachOrDetachNotifier:Subject = new Subject();
+
+ attachOrDetachChangeDetector(attach) {
+ this.attachOrDetachNotifier.next(attach);
+ }
+}
+
+class ToggleClass {
+ constructor(protected zone: NgZone, protected el: ElementRef) { }
+
+ ngAfterViewChecked() {
+ toggleClass(this.el, this.zone);
+ }
+}
+
+@Component({
+ selector: 'manual1',
+ template: `
+ Comp1
+
+ `
+})
+export class Manual1 extends ToggleClass {
+
+ @Input() notifier:Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual2',
+ template: `
+ Comp2
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Manual2 extends ToggleClass {
+
+ @Input() notifier:Subject;
+
+ constructor(zone: NgZone, el: ElementRef, private cd: ChangeDetectorRef) {
+ super(zone, el);
+ }
+
+ ngOnInit() {
+ this.cd.detach();
+
+ this.notifier.subscribe((attach) => {
+ if (attach) {
+ this.el.nativeElement.querySelector('a').classList.remove('detached');
+ this.cd.reattach();
+ } else {
+ this.el.nativeElement.querySelector('a').classList.add('detached');
+ this.cd.detach();
+ }
+ });
+ }
+}
+
+@Component({
+ selector: 'manual3',
+ template: `
+ Comp3
+
+ `
+})
+export class Manual3 extends ToggleClass {
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+@Component({
+ selector: 'manual4',
+ template: `
+ Comp4
+
+ `
+})
+export class Manual4 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+
+ triggerChangeDetection () { }
+}
+
+@Component({
+ selector: 'manual5',
+ template: `
+ Comp5
+
+ `
+})
+export class Manual5 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual6',
+ template: `
+ Comp6
+
+ `
+})
+export class Manual6 extends ToggleClass {
+
+ constructor(
+ zone: NgZone, el:
+ ElementRef, private cd: ChangeDetectorRef,
+ @Inject(forwardRef(() => ManualChangeDetectionComponent)) private parentComp: ManualChangeDetectionComponent) {
+ super(zone, el);
+ }
+
+ ngOnInit() {
+ this.cd.detach();
+
+ this.parentComp.attachOrDetachNotifier.subscribe((attach) => {
+ if (attach) {
+ this.el.nativeElement.querySelector('a').classList.remove('detached');
+ this.cd.reattach();
+ } else {
+ this.el.nativeElement.querySelector('a').classList.add('detached');
+ this.cd.detach();
+ }
+ });
+ }
+}
+
+@Component({
+ selector: 'manual7',
+ template: `
+ Comp7
+
+ `
+})
+export class Manual7 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+
+@Component({
+ selector: 'manual8',
+ template: `
+ Comp8
+
+ `
+})
+export class Manual8 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+@Component({
+ selector: 'manual9',
+ template: `
+ Comp9
+
+ `
+})
+export class Manual9 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual10',
+ template: `Comp10 `
+})
+export class Manual10 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual11',
+ template: `Comp11 `
+})
+export class Manual11 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual12',
+ template: `Comp12 `
+})
+export class Manual12 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual13',
+ template: `Comp13 `
+})
+export class Manual13 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual14',
+ template: `Comp14 `
+})
+export class Manual14 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual15',
+ template: `Comp15 `
+})
+export class Manual15 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual16',
+ template: `Comp16 `
+})
+export class Manual16 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'manual17',
+ template: `Comp17 `
+})
+export class Manual17 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+export const manualComponents = [
+ Manual1,
+ Manual2,
+ Manual3,
+ Manual4,
+ Manual5,
+ Manual6,
+ Manual7,
+ Manual8,
+ Manual9,
+ Manual10,
+ Manual11,
+ Manual12,
+ Manual13,
+ Manual14,
+ Manual15,
+ Manual16,
+ Manual17
+];
\ No newline at end of file
diff --git a/app/pages/not-found/not-found.component.ts b/app/pages/not-found/not-found.component.ts
new file mode 100644
index 0000000..77dc7ab
--- /dev/null
+++ b/app/pages/not-found/not-found.component.ts
@@ -0,0 +1,7 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'not-found',
+ template: 'Sorry, page not found'
+})
+export class NotFoundComponent { }
\ No newline at end of file
diff --git a/app/pages/on-push-observables/on-push-change-detection-observables.component.ts b/app/pages/on-push-observables/on-push-change-detection-observables.component.ts
new file mode 100644
index 0000000..b297545
--- /dev/null
+++ b/app/pages/on-push-observables/on-push-change-detection-observables.component.ts
@@ -0,0 +1,334 @@
+import { Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, NgZone, ElementRef } from '@angular/core';
+import { Subject } from 'rxjs/Rx';
+
+import { toggleClass } from 'app/services/toggle-class.service';
+
+@Component({
+ selector: 'on-push-cd-observables',
+ template: `
+ OnPush Change Detection (Observables)
+ This demo shows how Angular performs change detection only for a path when Observables are used.
+
+
+ Bootstrapped app, performs CD everywhere
+ Click "Trigger CD" button, skips "Comp1" subtree
+ Click "Push to Comp17", performs CD only on path from root to Comp17
+ Click "Comp7", skips subtrees of "Comp6", "Comp5", "Comp8" and performs CD on path from root to Comp17
+
+
+
+ Trigger Change Detection
+ Push to Comp17
+
+
+
+ `
+})
+export class OnPushChangeDetectionObservablesComponent {
+ model: Subject = new Subject();
+
+ emitAndTriggerChangeDetection() {
+ this.model.next(null);
+ }
+}
+
+class ToggleClass {
+ constructor(protected zone: NgZone, protected el: ElementRef) { }
+
+ ngAfterViewChecked() {
+ toggleClass(this.el, this.zone);
+ }
+}
+
+@Component({
+ selector: 'observable1',
+ template: `
+ Comp1
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable1 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable2',
+ template: `
+ Comp2
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable2 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+
+@Component({
+ selector: 'observable3',
+ template: `
+ Comp3
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable3 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable4',
+ template: `
+ Comp4
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable4 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable5',
+ template: `
+ Comp5
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable5 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable6',
+ template: `
+ Comp6
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable6 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable7',
+ host: { '(click)':'emitAndTriggerChangeDetection()' },
+ template: `
+ Comp7
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable7 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+
+ emitAndTriggerChangeDetection() {
+ this.model.next(null);
+ }
+}
+
+@Component({
+ selector: 'observable8',
+ template: `
+ Comp8
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable8 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable9',
+ template: `
+ Comp9
+
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable9 extends ToggleClass {
+ @Input() model: Subject;
+
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable10',
+ template: `Comp10 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable10 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable11',
+ template: `Comp11 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable11 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable12',
+ template: `Comp12 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable12 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable13',
+ template: `Comp13 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable13 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable14',
+ template: `Comp14 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable14 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable15',
+ template: `Comp15 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable15 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable16',
+ template: `Comp16 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable16 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'observable17',
+ template: `Cmp17 `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class Observable17 extends ToggleClass {
+ @Input() model:Subject;
+
+ constructor(zone: NgZone, el: ElementRef, private cd: ChangeDetectorRef) {
+ super(zone, el);
+ }
+
+ ngOnInit() {
+ this.model.subscribe(() => {
+ this.cd.markForCheck();
+ toggleClass(this.el, this.zone, 'checked-observable');
+ })
+ }
+}
+
+export const observableComponents = [
+ Observable1,
+ Observable2,
+ Observable3,
+ Observable4,
+ Observable5,
+ Observable6,
+ Observable7,
+ Observable8,
+ Observable9,
+ Observable10,
+ Observable11,
+ Observable12,
+ Observable13,
+ Observable14,
+ Observable15,
+ Observable16,
+ Observable17
+];
\ No newline at end of file
diff --git a/app/pages/on-push/on-push-change-detection.component.ts b/app/pages/on-push/on-push-change-detection.component.ts
new file mode 100644
index 0000000..06cd4eb
--- /dev/null
+++ b/app/pages/on-push/on-push-change-detection.component.ts
@@ -0,0 +1,302 @@
+import { Component, NgZone, ChangeDetectorRef, ChangeDetectionStrategy, ElementRef, OnInit } from '@angular/core';
+import { Subject } from 'rxjs/Rx';
+
+import { toggleClass } from 'app/services/toggle-class.service';
+
+@Component({
+ selector: 'on-push-cd',
+ template: `
+ OnPush Change Detection
+ This demo shows how change detection skips a component's subtree when
+ it's set to OnPush and non of its input property change or an
+ event is fired inside that component.
+
+
+ Bootstrapped app, performs CD everywhere (reload to check)
+ Click "Trigger CD" button, skips "Comp2" subtree
+ Click "Comp12", skips "Comp2" subtree
+ Click "Comp10", skips "Comp8" subtree
+ Click "Comp16", performs CD everywhere
+
+
+
+ Trigger Change Detection
+
+
+
+ `
+})
+export class OnPushChangeDetectionComponent { }
+
+class ToggleClass {
+ constructor(protected zone: NgZone, protected el: ElementRef) { }
+
+ ngAfterViewChecked() {
+ toggleClass(this.el, this.zone);
+ }
+}
+
+
+@Component({
+ selector: 'onpush1',
+ template: `
+ Comp1
+
+ `
+})
+export class OnPush1 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush2',
+ template: `
+ Comp2
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class OnPush2 {
+
+ counter:number = 0;
+
+ constructor(private zone: NgZone, private el: ElementRef, private cd: ChangeDetectorRef) {}
+
+ ngAfterViewChecked() {
+ toggleClass(this.el, this.zone);
+ }
+}
+
+@Component({
+ selector: 'onpush3',
+ template: `
+ Comp3
+
+ `
+})
+export class OnPush3 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush4',
+ template: `
+ Comp4
+
+ `
+})
+export class OnPush4 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush5',
+ template: `
+ Comp4
+
+ `
+})
+export class OnPush5 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush6',
+ template: `
+ Comp6
+
+ `
+})
+export class OnPush6 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush7',
+ template: `
+ Comp7
+
+ `
+})
+export class OnPush7 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush8',
+ template: `
+ Comp8
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class OnPush8 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush9',
+ template: `
+ Comp9
+
+ `
+})
+export class OnPush9 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush10',
+ host: { '(click)': 'triggerChangeDetection()' },
+ template: `Comp10 `
+})
+export class OnPush10 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+
+ triggerChangeDetection () { }
+}
+
+@Component({
+ selector: 'onpush11',
+ template: `Comp11 `
+})
+export class OnPush11 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush12',
+ host: { '(click)': 'triggerChangeDetection()' },
+ template: `Comp12 `
+})
+export class OnPush12 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+
+ triggerChangeDetection () { }
+}
+
+@Component({
+ selector: 'onpush13',
+ template: `Comp13 `
+})
+export class OnPush13 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush14',
+ template: `Comp14 `
+})
+export class OnPush14 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush15',
+ template: `Comp15 `
+})
+export class OnPush15 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+@Component({
+ selector: 'onpush16',
+ host: { '(click)': 'triggerChangeDetection()' },
+ template: `Comp16 `
+})
+export class OnPush16 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+
+ triggerChangeDetection () { }
+}
+
+@Component({
+ selector: 'onpush17',
+ template: `Comp17 `
+})
+export class OnPush17 extends ToggleClass {
+ constructor(zone: NgZone, el: ElementRef) {
+ super(zone, el);
+ }
+}
+
+export const onPushComponents = [
+ OnPush1,
+ OnPush2,
+ OnPush3,
+ OnPush4,
+ OnPush5,
+ OnPush6,
+ OnPush7,
+ OnPush8,
+ OnPush9,
+ OnPush10,
+ OnPush11,
+ OnPush12,
+ OnPush13,
+ OnPush14,
+ OnPush15,
+ OnPush16,
+ OnPush17
+];
\ No newline at end of file
diff --git a/app/secure/auth-guard.service.ts b/app/secure/auth-guard.service.ts
new file mode 100644
index 0000000..887fc59
--- /dev/null
+++ b/app/secure/auth-guard.service.ts
@@ -0,0 +1,59 @@
+import { Injectable } from '@angular/core';
+import {
+ CanActivate, Router,
+ ActivatedRouteSnapshot,
+ RouterStateSnapshot,
+ CanActivateChild,
+ NavigationExtras,
+ CanLoad, Route
+} from '@angular/router';
+import { AuthService } from './auth.service';
+
+@Injectable()
+export class AuthGuard implements CanActivate, CanActivateChild, CanLoad {
+ constructor(private authService: AuthService, private router: Router) {}
+
+ canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
+ let url: string = state.url;
+
+ return this.checkLogin(url);
+ }
+
+ canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
+ return this.canActivate(route, state);
+ }
+
+ canLoad(route: Route): boolean {
+ let url = `/${route.path}`;
+
+ return this.checkLogin(url);
+ }
+
+ checkLogin(url: string): boolean {
+ if (this.authService.isLoggedIn) { return true; }
+
+ // Store the attempted URL for redirecting
+ this.authService.redirectUrl = url;
+
+ // Create a dummy session id
+ let sessionId = 123456789;
+
+ // Set our navigation extras object
+ // that contains our global query params and fragment
+ let navigationExtras: NavigationExtras = {
+ queryParams: { 'session_id': sessionId },
+ fragment: 'anchor'
+ };
+
+ // Navigate to the login page with extras
+ this.router.navigate(['/login'], navigationExtras);
+ return false;
+ }
+}
+
+
+/*
+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
+*/
\ No newline at end of file
diff --git a/app/secure/auth.service.ts b/app/secure/auth.service.ts
new file mode 100644
index 0000000..b55d7af
--- /dev/null
+++ b/app/secure/auth.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+
+import { Observable } from 'rxjs/Observable';
+
+import 'rxjs/add/observable/of';
+import 'rxjs/add/operator/do';
+import 'rxjs/add/operator/delay';
+
+@Injectable()
+export class AuthService {
+ isLoggedIn: boolean = false;
+
+ // store the URL so we can redirect after logging in
+ redirectUrl: string;
+
+ login(): Observable {
+ return Observable.of(true).delay(1000).do(val => this.isLoggedIn = true);
+ }
+
+ logout(): void {
+ this.isLoggedIn = false;
+ }
+}
diff --git a/app/services/logger.service.ts b/app/services/logger.service.ts
new file mode 100644
index 0000000..c885b50
--- /dev/null
+++ b/app/services/logger.service.ts
@@ -0,0 +1,27 @@
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class LogerService {
+ logs: string[] = [];
+ prevMsg = '';
+ prevMsgCount = 1;
+
+ log(msg: string) {
+ if (msg === this.prevMsg) {
+ // Repeat message; update last log entry with count.
+ this.logs[this.logs.length - 1] = msg + ` (${this.prevMsgCount += 1}x)`;
+ } else {
+ // New message; log it.
+ this.prevMsg = msg;
+ this.prevMsgCount = 1;
+ this.logs.push(msg);
+ }
+ }
+
+ clear() { this.logs.length = 0; }
+
+ // schedules a view refresh to ensure display catches up
+ tick() { this.tick_then(() => { }); }
+
+ tick_then(fn: () => any) { setTimeout(fn, 0); }
+}
\ No newline at end of file
diff --git a/app/services/toggle-class.service.ts b/app/services/toggle-class.service.ts
new file mode 100644
index 0000000..eca7d3d
--- /dev/null
+++ b/app/services/toggle-class.service.ts
@@ -0,0 +1,11 @@
+
+export function toggleClass(el, zone, className = 'checked') {
+ let a = el.nativeElement.querySelector('a');
+ a.classList.add(className);
+ zone.runOutsideAngular(() => {
+ setTimeout(() => {
+ a.classList.remove(className);
+ }, 400);
+ })
+}
+
diff --git a/index.html b/index.html
index 6fa427d..5879e41 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,7 @@
Angular 2 QuickStart
+
@@ -21,7 +22,9 @@
- Loading...
+
+
+