diff --git a/README.md b/README.md index 2f73ed7..66563b2 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,9 @@ export const defaultStore = createStore([counterModule, !environm // your NgModule -import { StoreonModule, STOREON } from '@storeon/angular'; +import { STOREON } from '@storeon/angular'; @NgModule({ - imports: [StoreonModule], // StoreonModule - ... providers: [{ provide: STOREON, useValue: defaultStore // your store @@ -98,3 +96,36 @@ export class AppComponent implements OnInit { } ``` + +```typescript + +// example using Ivy hooks + +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { UseStoreon } from '@storeon/angular'; +import { Events, State } from '../app.module'; +import { Dispatch } from 'storeon'; + +@Component({ + selector: 'app-hook-counter', + templateUrl: './hook-counter.component.html', + styleUrls: ['./hook-counter.component.scss'] +}) +@UseStoreon({keys: [ 'count' ], dispatcher: 'dispatch'}) +export class HookCounterComponent implements OnInit { + + count: Observable; + dispatch: Dispatch; + + constructor() { } + + ngOnInit() { + } + + increment() { + this.dispatch('inc'); + } +} + +``` diff --git a/projects/ng-storeon/src/lib/storeon.decorator.ts b/projects/ng-storeon/src/lib/storeon.decorator.ts new file mode 100644 index 0000000..b16aa6c --- /dev/null +++ b/projects/ng-storeon/src/lib/storeon.decorator.ts @@ -0,0 +1,32 @@ +import { ɵɵdirectiveInject as directiveInject } from '@angular/core'; +import { StoreonService } from './storeon.service'; + + +/*** + * + * Experimental feature, works only with Ivy renderer + * Patches the component with keys from storeon store + * + */ +export function UseStoreon(config: { + keys: Array, + dispatcher?: string +}) { + return (cmpType) => { + const originalFactory = cmpType.ngComponentDef.factory; + cmpType.ngComponentDef.factory = () => { + const cmp = originalFactory(cmpType.ngComponentDef.type); + + const storeon = directiveInject>(StoreonService ); + + config.keys.forEach(key => cmp[key] = storeon.useStoreon(key)); + + if (config.dispatcher) { + cmp[config.dispatcher] = storeon.dispatch.bind(storeon); + } + + return cmp; + }; + + }; +} diff --git a/projects/ng-storeon/src/lib/storeon.module.ts b/projects/ng-storeon/src/lib/storeon.module.ts deleted file mode 100644 index 18d5320..0000000 --- a/projects/ng-storeon/src/lib/storeon.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; -import { StoreonService } from './storeon.service'; - -@NgModule({ - declarations: [], - imports: [], - providers: [], - exports: [] -}) -export class StoreonModule { } diff --git a/projects/ng-storeon/src/public_api.ts b/projects/ng-storeon/src/public_api.ts index 67968d8..c62e4d4 100644 --- a/projects/ng-storeon/src/public_api.ts +++ b/projects/ng-storeon/src/public_api.ts @@ -3,5 +3,5 @@ */ export * from './lib/storeon.service'; -export * from './lib/storeon.module'; export * from './lib/storeon.token'; +export * from './lib/storeon.decorator'; diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 32e8994..13f8423 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -3,10 +3,12 @@ import { Routes, RouterModule } from '@angular/router'; import { CounterComponent } from './counter/counter.component'; import { Counter1Component } from './counter1/counter1.component'; +import { HookCounterComponent } from './hook-counter/hook-counter.component'; const routes: Routes = [ { path: 'counter', component: CounterComponent }, - { path: 'counter1', component: Counter1Component } + { path: 'counter1', component: Counter1Component }, + { path: 'ivy-hook', component: HookCounterComponent } ]; @NgModule({ diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4ef7fa8..b7ed373 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; -import { StoreonModule, STOREON } from '@storeon/angular'; +import { STOREON } from '@storeon/angular'; import createStore, { Module, StoreonEvents } from 'storeon'; import devtools from 'storeon/devtools'; @@ -12,6 +12,7 @@ import { AppComponent } from './app.component'; import { MenuComponent } from './menu/menu.component'; import { CounterComponent } from './counter/counter.component'; import { Counter1Component } from './counter1/counter1.component'; +import { HookCounterComponent } from './hook-counter/hook-counter.component'; // State structure export interface State { @@ -43,11 +44,11 @@ export const defaultStore = createStore([counterModule, !environm MenuComponent, CounterComponent, Counter1Component, + HookCounterComponent, ], imports: [ BrowserModule, AppRoutingModule, - StoreonModule ], providers: [{ provide: STOREON, diff --git a/src/app/hook-counter/hook-counter.component.html b/src/app/hook-counter/hook-counter.component.html new file mode 100644 index 0000000..1273113 --- /dev/null +++ b/src/app/hook-counter/hook-counter.component.html @@ -0,0 +1,4 @@ +
+ + Total count: {{ count | async }} +
diff --git a/src/app/hook-counter/hook-counter.component.scss b/src/app/hook-counter/hook-counter.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/hook-counter/hook-counter.component.spec.ts b/src/app/hook-counter/hook-counter.component.spec.ts new file mode 100644 index 0000000..16db6f8 --- /dev/null +++ b/src/app/hook-counter/hook-counter.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HookCounterComponent } from './hook-counter.component'; + +describe('HookCounterComponent', () => { + let component: HookCounterComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HookCounterComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HookCounterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/hook-counter/hook-counter.component.ts b/src/app/hook-counter/hook-counter.component.ts new file mode 100644 index 0000000..a867c24 --- /dev/null +++ b/src/app/hook-counter/hook-counter.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { UseStoreon } from '@storeon/angular'; +import { Events, State } from '../app.module'; +import { Dispatch } from 'storeon'; + +@Component({ + selector: 'app-hook-counter', + templateUrl: './hook-counter.component.html', + styleUrls: ['./hook-counter.component.scss'] +}) +@UseStoreon({keys: [ 'count' ], dispatcher: 'dispatch'}) +export class HookCounterComponent implements OnInit { + + count: Observable; + dispatch: Dispatch; + + constructor() { } + + ngOnInit() { + } + + increment() { + this.dispatch('inc'); + } +} diff --git a/src/app/menu/menu.component.html b/src/app/menu/menu.component.html index 1d43442..cb5fc50 100644 --- a/src/app/menu/menu.component.html +++ b/src/app/menu/menu.component.html @@ -1,4 +1,5 @@