Skip to content

Commit a5b3be3

Browse files
committed
feature(StorageService): demo local Storage per platform
StorageService used and implemented as localStorage on the browser & in memory variable on the server. Added information on how to stay updated with the repository. Closes TrilonIO#35 Closes TrilonIO#34
1 parent 1777f43 commit a5b3be3

File tree

10 files changed

+131
-8
lines changed

10 files changed

+131
-8
lines changed

CHANGELOG.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,31 @@
11
# Changelog
22

3+
> This is a manual changelog at the moment to track the Major changes in the Repo.
4+
5+
## How do I stay up to date when Updates happen in this Starter?
6+
7+
Typically when you want to update your App with the latest from this repo, you should be able to get the latest from here
8+
and (depending on what has changed), you should be able to just drop in your Client & Server folders on top.
9+
10+
My goal is to point out the more **"Major"** issues & changes below, that might have affected the application in Client/Server aspects.
11+
For example, some additions made to each platform to add a new Feature (such as Storage that's using dependeny injection).
12+
Of course if some feature like that isn't important to you, there's no need to copy it over! A lot examples here are to get you up &
13+
running with a lot of the eco-system of .NET Core & Angular (v2+).
14+
15+
Don't hesitate to create an Issue with anything you run into, and Pull-Requests are always welcome for basic implementations of new features & fixes
16+
you think others would benefit from as well!
17+
18+
### 1.0.0-beta.3 - 1/23/2017
19+
20+
- [Closes #35](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/35) Implemented Storage service for Browser (localStorage) & Server (in memory variable)
21+
22+
- [Closes #34](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/45) Fix karma to handle Angular testing [commit](https://github.com/MarkPieszak/aspnetcore-angular2-universal/commit/1777f43ca23ede6c46d3cd37c1a2d35605a1355d)
23+
24+
325
### 1.0.0-beta.2 - 1/14/2017
426

527
- Update AppComponent to be `<app-root />` to satisfy TSLint. `bootstrap-server.ts` updated as well.
628

729
- Partial revert of ng2-bootstrap dependency down to **1.1.16**, 1.1.20+ require ng 2.4.x (unsupported by Universal atm) [commit](https://github.com/MarkPieszak/aspnetcore-angular2-universal/commit/524df2df00113d0ee2953b44ae40167112192f89)
830

9-
- [#33](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/33) Update CSS for bootstrap4 & fix ng2-bootstrap API changes [commit](https://github.com/MarkPieszak/aspnetcore-angular2-universal/commit/d0c0e7d98b9ac043be9880ba2656ddf0f0f2222d)
31+
- [Closes #33](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/33) Update CSS for bootstrap4 & fix ng2-bootstrap API changes [commit](https://github.com/MarkPieszak/aspnetcore-angular2-universal/commit/d0c0e7d98b9ac043be9880ba2656ddf0f0f2222d)

Client/app/platform-modules/app.browser.module.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { UniversalModule, isBrowser, isNode, AUTO_PREBOOT } from 'angular2-unive
88
import { AppCommonModule } from './app.common.module';
99
import { AppComponent } from 'app';
1010
// Universal : XHR Cache
11-
import { CacheService } from 'app-shared';
11+
import { CacheService, StorageService, BrowserStorage } from 'app-shared';
1212

1313
export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
1414

@@ -25,7 +25,7 @@ export function getResponse() {
2525
// "UniversalModule" Must be first import.
2626
// ** NOTE ** : This automatically imports BrowserModule, HttpModule, and JsonpModule for Browser,
2727
// and NodeModule, NodeHttpModule etc for the server.
28-
UniversalModule,
28+
UniversalModule,
2929

3030
AppCommonModule,
3131

@@ -40,7 +40,11 @@ export function getResponse() {
4040
{ provide: 'isNode', useValue: isNode },
4141

4242
{ provide: 'req', useFactory: getRequest },
43-
{ provide: 'res', useFactory: getResponse }
43+
{ provide: 'res', useFactory: getResponse },
44+
45+
// We're using Dependency Injection here to use a Browser specific "Storage" (localStorage here) through the empty shell class StorageService
46+
// The server will use a different one, since window & localStorage do not exist there
47+
{ provide: StorageService, useClass: BrowserStorage }
4448

4549
// Universal concept. Uncomment this if you want to Turn OFF auto preboot complete
4650
// { provide: AUTO_PREBOOT, useValue: false }

Client/app/platform-modules/app.server.module.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { UniversalModule, isBrowser, isNode } from 'angular2-universal/node';
99
import { AppCommonModule } from './app.common.module';
1010
import { AppComponent } from 'app';
1111
// Universal : XHR Cache
12-
import { CacheService } from 'app-shared';
12+
import { CacheService, StorageService, ServerStorage } from 'app-shared';
1313

1414
export function getRequest() {
1515
return Zone.current.get('req') || {};
@@ -36,7 +36,10 @@ export function getResponse() {
3636
{ provide: 'isNode', useValue: isNode },
3737

3838
{ provide: 'req', useFactory: getRequest },
39-
{ provide: 'res', useFactory: getResponse }
39+
{ provide: 'res', useFactory: getResponse },
40+
41+
// We're using Dependency Injection here to use a Server/Node specific "Storage" through the empty shell class StorageService
42+
{ provide: StorageService, useClass: ServerStorage }
4043

4144

4245
// Other providers you want to add that you don't want shared in "Common" but are browser only

Client/containers/platform-examples/examples.component.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, OnInit } from '@angular/core';
22
import { isBrowser } from 'angular2-universal';
33
import { Observable } from 'rxjs/Rx';
4+
import { StorageService } from 'app-shared';
45

56
@Component({
67
selector: 'app-examples',
@@ -31,7 +32,7 @@ export class ExamplesComponent implements OnInit {
3132
browserPlatformInterval: Observable<any>;
3233

3334
// Use "constructor"s only for dependency injection
34-
constructor () {}
35+
constructor (private storage: StorageService) {}
3536

3637
// Here you want to handle anything with @Input()'s @Output()'s
3738
// Data retrieval / etc - this is when the Component is "ready" and wired up
@@ -44,6 +45,18 @@ export class ExamplesComponent implements OnInit {
4445
if (isBrowser) {
4546
this.browserPlatformInterval = Observable.interval(300);
4647
}
48+
49+
// ************
50+
// Now let's play around with "Storage", but on a Platform level
51+
// Node will use in memory variable, while the Browser uses "localStorage"
52+
// Both are abstracted out use Dependency Injection to provide different classes for each use-case.
53+
// [high-five] :)
54+
55+
this.storage.setItem('test', 'This came from Storage within each Platform !!');
56+
57+
let storedItem = this.storage.getItem('test');
58+
59+
console.log('Platform [Storage] test :: ' + storedItem);
4760
}
4861

4962
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
export * from './storage.browser';
3+
export * from './storage.node';
4+
export * from './storage.service';
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { StorageService } from './storage.service';
2+
3+
export class BrowserStorage implements StorageService {
4+
getItem (key: string): any {
5+
let storedItem = window.localStorage.getItem(key);
6+
try {
7+
return JSON.parse(storedItem);
8+
} catch (ex) {
9+
return storedItem;
10+
}
11+
}
12+
13+
setItem (key: string, value: any) {
14+
// We need to try and stringify it first (we can't save Objects/etc or it'll error out)
15+
if (typeof value !== 'string') {
16+
window.localStorage.setItem(key, JSON.stringify(value));
17+
} else {
18+
window.localStorage.setItem(key, value);
19+
}
20+
}
21+
22+
removeItem (key: string) {
23+
window.localStorage.removeItem(key);
24+
}
25+
26+
clear () {
27+
window.localStorage.clear();
28+
}
29+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { StorageService } from './storage.service';
2+
3+
// Our pseudo server Storage we'll use on the server to replace localStorage
4+
// This can handle most scenarios, but if you truly needed a server Memory Cache
5+
// you'd want to use Redis or something here
6+
let fakeInMemoryStore = {};
7+
8+
export class ServerStorage implements StorageService {
9+
getItem(key) {
10+
return fakeInMemoryStore[key] || undefined;
11+
}
12+
setItem(key, value) {
13+
return fakeInMemoryStore[key] = value;
14+
}
15+
removeItem(key) {
16+
try {
17+
delete fakeInMemoryStore[key];
18+
} catch (ex) { }
19+
}
20+
clear() {
21+
fakeInMemoryStore = {};
22+
}
23+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Injectable } from '@angular/core';
2+
3+
// This is our "shell" Service that will be used through out the application
4+
5+
// Each "platform" will inject its own implementation (storage.browser & storage.node)
6+
// Browser is using window.localStorage
7+
// Node is using inMemory variable Object (which can work for most scenarios),
8+
// If you needed a true cache you'd need to implement Redis or similar here.
9+
10+
// Useage within the app:
11+
// constructor (private storage: StorageService) {}
12+
13+
// this.storage.setItem('someKey', 123);
14+
15+
@Injectable()
16+
export class StorageService {
17+
getItem = (key) : any => {};
18+
setItem = (key, value) => {};
19+
removeItem = (key) => {};
20+
clear = () => {};
21+
}

Client/shared/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
export * from './cache/api';
1818
export * from './cache/universal-cache';
19+
export * from './cache/storage';
1920

2021
export * from './http/http-gateway.service';
2122

2223
export * from './rx/rx-context.directive';
24+

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This repository is maintained by [Angular Universal](https://github.com/angular/
1010
Angular2, not only for the client-side, but to be rendered on the *server* for instant application paints
1111
(*Note*: If you don't need Universal (SSR) [read here](https://github.com/MarkPieszak/aspnetcore-angular2-universal#faq) on how to disable it).
1212

13+
**How do I stay up-to-date with the latest updates & changes of the repo?** [Check out the CHANGELOG here](https://github.com/MarkPieszak/aspnetcore-angular2-universal/blob/master/CHANGELOG.md)
1314

1415
This is meant to be a Feature-Rich Starter application containing all of the latest technologies, best build systems available, and include many real-world examples and libraries needed in todays Single Page Applications (SPAs).
1516

@@ -93,7 +94,8 @@ to: `ASPNETCORE_ENVIRONMENT=Production`, then run `webpack` manually. Then you c
9394
- [ ] Example of NgRx (redux) transfering App State from server to client - track [#29](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/29)
9495
- [ ] AoT (Ahead-of-time compilation) production builds - track [#10](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/10)
9596
- [ ] SignalR (Websockets) example - track [#39](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/39)
96-
- [ ] Update components real unit & e2e tests - track [#45](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/45)
97+
- [x] Update components real unit & e2e tests - track [#45](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/45)
98+
- [x] ~~Storage Service (localStorage) showcasing Dependency Injection per-platform - [#35](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues/35)~~
9799
- [x] ~~NgRx (reactive Redux application state management)~~
98100
- [x] ~~HMR State management (hold state when hot reload occurs)~~
99101
- [x] ~~Unit testing with Karma/Jasmine~~

0 commit comments

Comments
 (0)