Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ca9b744

Browse files
committedJul 9, 2019
feat: ivy UseStoreon hook
1 parent a81d8db commit ca9b744

10 files changed

+129
-6
lines changed
 

‎README.md

+34-3
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,9 @@ export const defaultStore = createStore<State, Events>([counterModule, !environm
5757

5858
// your NgModule
5959

60-
import { StoreonModule, STOREON } from '@storeon/angular';
60+
import { STOREON } from '@storeon/angular';
6161

6262
@NgModule({
63-
imports: [StoreonModule], // StoreonModule
64-
...
6563
providers: [{
6664
provide: STOREON,
6765
useValue: defaultStore // your store
@@ -98,3 +96,36 @@ export class AppComponent implements OnInit {
9896
}
9997

10098
```
99+
100+
```typescript
101+
102+
// example using Ivy hooks
103+
104+
import { Component, OnInit } from '@angular/core';
105+
import { Observable } from 'rxjs';
106+
import { UseStoreon } from '@storeon/angular';
107+
import { Events, State } from '../app.module';
108+
import { Dispatch } from 'storeon';
109+
110+
@Component({
111+
selector: 'app-hook-counter',
112+
templateUrl: './hook-counter.component.html',
113+
styleUrls: ['./hook-counter.component.scss']
114+
})
115+
@UseStoreon<State, Events>({keys: [ 'count' ], dispatcher: 'dispatch'})
116+
export class HookCounterComponent implements OnInit {
117+
118+
count: Observable<number>;
119+
dispatch: Dispatch<Events>;
120+
121+
constructor() { }
122+
123+
ngOnInit() {
124+
}
125+
126+
increment() {
127+
this.dispatch('inc');
128+
}
129+
}
130+
131+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ɵɵdirectiveInject as directiveInject } from '@angular/core';
2+
import { StoreonService } from './storeon.service';
3+
4+
5+
/***
6+
*
7+
* Experimental feature, works only with Ivy renderer
8+
* Patches the component with keys from storeon store
9+
*
10+
*/
11+
export function UseStoreon<State, Events>(config: {
12+
keys: Array<keyof State>,
13+
dispatcher?: string
14+
}) {
15+
return (cmpType) => {
16+
const originalFactory = cmpType.ngComponentDef.factory;
17+
cmpType.ngComponentDef.factory = () => {
18+
const cmp = originalFactory(cmpType.ngComponentDef.type);
19+
20+
const storeon = directiveInject<StoreonService<State, Events>>(StoreonService );
21+
22+
config.keys.forEach(key => cmp[key] = storeon.useStoreon(key));
23+
24+
if (config.dispatcher) {
25+
cmp[config.dispatcher] = storeon.dispatch.bind(storeon);
26+
}
27+
28+
return cmp;
29+
};
30+
31+
};
32+
}

‎projects/ng-storeon/src/public_api.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
export * from './lib/storeon.service';
66
export * from './lib/storeon.module';
77
export * from './lib/storeon.token';
8+
export * from './lib/useStoreon.decorator';

‎src/app/app-routing.module.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import { Routes, RouterModule } from '@angular/router';
33

44
import { CounterComponent } from './counter/counter.component';
55
import { Counter1Component } from './counter1/counter1.component';
6+
import { HookCounterComponent } from './hook-counter/hook-counter.component';
67

78
const routes: Routes = [
89
{ path: 'counter', component: CounterComponent },
9-
{ path: 'counter1', component: Counter1Component }
10+
{ path: 'counter1', component: Counter1Component },
11+
{ path: 'ivy-hook', component: HookCounterComponent }
1012
];
1113

1214
@NgModule({

‎src/app/app.module.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
33

4-
import { StoreonModule, STOREON } from '@storeon/angular';
4+
import { STOREON } from '@storeon/angular';
55

66
import createStore, { Module, StoreonEvents } from 'storeon';
77
import devtools from 'storeon/devtools';
@@ -12,6 +12,7 @@ import { AppComponent } from './app.component';
1212
import { MenuComponent } from './menu/menu.component';
1313
import { CounterComponent } from './counter/counter.component';
1414
import { Counter1Component } from './counter1/counter1.component';
15+
import { HookCounterComponent } from './hook-counter/hook-counter.component';
1516

1617
// State structure
1718
export interface State {
@@ -43,11 +44,11 @@ export const defaultStore = createStore<State, Events>([counterModule, !environm
4344
MenuComponent,
4445
CounterComponent,
4546
Counter1Component,
47+
HookCounterComponent,
4648
],
4749
imports: [
4850
BrowserModule,
4951
AppRoutingModule,
50-
StoreonModule
5152
],
5253
providers: [{
5354
provide: STOREON,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div>
2+
<button (click)="increment()">Increment counter</button>
3+
<span>Total count: {{ count | async }}</span>
4+
</div>

‎src/app/hook-counter/hook-counter.component.scss

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { HookCounterComponent } from './hook-counter.component';
4+
5+
describe('HookCounterComponent', () => {
6+
let component: HookCounterComponent;
7+
let fixture: ComponentFixture<HookCounterComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ HookCounterComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(HookCounterComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { Observable } from 'rxjs';
3+
import { UseStoreon } from '@storeon/angular';
4+
import { Events, State } from '../app.module';
5+
import { Dispatch } from 'storeon';
6+
7+
@Component({
8+
selector: 'app-hook-counter',
9+
templateUrl: './hook-counter.component.html',
10+
styleUrls: ['./hook-counter.component.scss']
11+
})
12+
@UseStoreon<State, Events>({keys: [ 'count' ], dispatcher: 'dispatch'})
13+
export class HookCounterComponent implements OnInit {
14+
15+
count: Observable<number>;
16+
dispatch: Dispatch<Events>;
17+
18+
constructor() { }
19+
20+
ngOnInit() {
21+
}
22+
23+
increment() {
24+
this.dispatch('inc');
25+
}
26+
}

‎src/app/menu/menu.component.html

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<ul>
22
<li><a [routerLink]="['/counter']" routerLinkActive="router-link-active">Counter</a></li>
3+
<li><a [routerLink]="['/ivy-hook']" routerLinkActive="router-link-active">Counter with Ivy Hook</a></li>
34
<li><a [routerLink]="['/counter1']" routerLinkActive="router-link-active">Counter 1</a></li>
45
</ul>

0 commit comments

Comments
 (0)
Please sign in to comment.