Szkielet (Core)
Globalizacja (g11n)
Bezpieczeństwo
UX
Pozostałe elementy wspólne
Feature #1
Uwierzytelnienie, Autoryzacja, Dane
Lokalizacja, Internacjonalizacja
Wspólne komponenty i kontenery
Routing, Serwisy, Storage
Moduły biznesowe
Feature #2
+
+
=
subscription
Core
Store
Sandbox
Feature #1
Feature #3
Feature #2
Services
Shared components
Services
Services
Services
Components
Components
Components
Store
Store
Store
Sandbox
Sandbox
Sandbox
app.module.ts
app.sandbox.ts
app
store
core
features
feature1.module.ts
feature1.sandbox.ts
store
feature1
feature2.module.ts
feature2.sandbox.ts
store
feature2
actions
reducers
effects
selectors
states
Sandbox
@Injectable()
class AppSandbox {
constructor(
private appState$: Store<AppState>,
private actionsSubj: ActionsSubject,
private childSandbox: ChildSandbox) {}
dataStream$ = this.appState$.select(dataSelector);
}
Components
Store
Data streams
Dispatchers
Special (observable) dispatchers
@Injectable()
class AppSandbox {
constructor(
private appState$: Store<AppState>,
private actionsSubj: ActionsSubject,
private childSandbox: ChildSandbox) {}
dataStream$ = this.appState$.select(dataSelector);
doSomething(newData) {
this.appState$.dispatch(new DoSomethingAction(newData))
}
}
@Injectable()
class AppSandbox {
constructor(
private appState$: Store<AppState>,
private actionsSubj: ActionsSubject,
private childSandbox: ChildSandbox) {}
dataStream$ = this.appState$.select(dataSelector);
doSomething(newData) {
this.appState$.dispatch(new DoSomethingAction(newData))
}
doSomethingSpecial$$(): Observable<string> {
return getDispatchObservable(
this.actionsSubject,
this.appState$,
SampleActionTypes.DoSomethingSpecialSuccess,
SampleActionTypes.DoSomethingSpecialFailure,
new DoSomethingSpecialAction()
);
}
}
@Injectable()
class AppSandbox {
constructor(
private appState$: Store<AppState>,
private actionsSubj: ActionsSubject,
private childSandbox: ChildSandbox) {}
}
Services
Services
@Injectable()
class AppSandbox {
constructor(
private appState$: Store<AppState>,
private actionsSubj: ActionsSubject,
private childSandbox: ChildSandbox) {}
dataStream$ = this.appState$.select(dataSelector);
doSomething(newData) {
this.appState$.dispatch(new DoSomethingAction(newData))
}
doSomethingSpecial$$(): Observable<string> {
return getDispatchObservable(
this.actionsSubject,
this.appState$,
SampleActionTypes.DoSomethingSpecialSuccess,
SampleActionTypes.DoSomethingSpecialFailure,
new DoSomethingSpecialAction()
);
}
doSomethingElse(data) {
this.childSandbox.doSomethingElse(data);
}
}
Re-exports
// src/app/component/sample.component.ts
// ...
@Component({
selector: 'sample',
templateUrl: './sample.component.html', styleUrls: ['./sample.component.scss']
})
export class SampleComponent implement OnInit, OnDestroy {
dataStream$: Observable<any>;
constructor(private appSandbox: AppSandbox, private childSandbox: ChildSandbox) {
this.dataStream$ = this.appSandbox.dataStream$;
}
}
// src/app/component/sample.component.ts
// ...
@Component({
selector: 'sample',
templateUrl: './sample.component.html', styleUrls: ['./sample.component.scss']
})
export class SampleComponent implement OnInit, OnDestroy {
dataStream$: Observable<any>;
constructor(private appSandbox: AppSandbox, private childSandbox: ChildSandbox) {
this.dataStream$ = this.appSandbox.dataStream$;
}
ngOnInit() {
this.routerSubscription = this.appSandbox.routeParams$.pipe(take(1))
.subscribe((p: Params) => {}, () => {});
}
}
// src/app/component/sample.component.ts
// ...
@Component({
selector: 'sample',
templateUrl: './sample.component.html', styleUrls: ['./sample.component.scss']
})
export class SampleComponent implement OnInit, OnDestroy {
dataStream$: Observable<any>;
constructor(private appSandbox: AppSandbox, private childSandbox: ChildSandbox) {
this.dataStream$ = this.appSandbox.dataStream$;
}
ngOnInit() {
this.routerSubscription = this.appSandbox.routeParams$.pipe(take(1))
.subscribe((p: Params) => this.appSandbox.doSomething(p.param1), () => {});
}
buttonClicked() {
this.childSandbox.doSomethingElse();
}
ngOnDestroy() {
this.routerSubscription.unsubscribe();
}
}
// src/app/component/sample.component.ts
// ...
@Component({
selector: 'sample',
templateUrl: './sample.component.html', styleUrls: ['./sample.component.scss']
})
export class SampleComponent implement OnInit, OnDestroy {
dataStream$: Observable<any>;
constructor(private appSandbox: AppSandbox, private childSandbox: ChildSandbox) {
this.dataStream$ = this.appSandbox.dataStream$;
}
ngOnInit() {
this.routerSubscription = this.appSandbox.routeParams$.pipe(take(1))
.subscribe((p: Params) => this.appSandbox.doSomething(p.param1), () => {});
}
}
// src/app/component/sample.component.ts
// ...
@Component({
selector: 'sample',
templateUrl: './sample.component.html', styleUrls: ['./sample.component.scss']
})
export class SampleComponent implement OnInit, OnDestroy {
dataStream$: Observable<any>;
constructor(private appSandbox: AppSandbox, private childSandbox: ChildSandbox) {
this.dataStream$ = this.appSandbox.dataStream$;
}
ngOnInit() {
this.routerSubscription = this.appSandbox.routeParams$.pipe(take(1))
.subscribe((p: Params) => this.appSandbox.doSomething(p.param1), () => {});
}
buttonClicked() {
this.childSandbox.doSomethingElse();
}
}
linkedin.com/in/lukasz-max-kokoszka
twitter.com/rafal_brzoska
linkedin.com/in/rafalbrzoska
linkedin.com/in/lukasz-max-kokoszka
twitter.com/rafal_brzoska
linkedin.com/in/rafalbrzoska