Skip to content

Commit 0527a28

Browse files
authored
add http-transfer mechanism (TrilonIO#179)
Closes TrilonIO#169 Closes TrilonIO#170
1 parent 6e1a51e commit 0527a28

21 files changed

+664
-293
lines changed

Client/app/app.component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { LinkService } from './shared/link.service';
77

88
// i18n support
99
import { TranslateService } from '@ngx-translate/core';
10+
import { REQUEST } from './shared/constants/request';
1011

1112
@Component({
1213
selector: 'app',
@@ -29,13 +30,18 @@ export class AppComponent implements OnInit, OnDestroy {
2930
private title: Title,
3031
private meta: Meta,
3132
private linkService: LinkService,
32-
public translate: TranslateService
33+
public translate: TranslateService,
34+
@Inject(REQUEST) private request
3335
) {
3436
// this language will be used as a fallback when a translation isn't found in the current language
3537
translate.setDefaultLang('en');
3638

3739
// the lang to use, if the lang isn't available, it will use the current loader to get them
3840
translate.use('en');
41+
42+
console.log(`What's our REQUEST Object look like?`);
43+
console.log(`The Request object only really exists on the Server, but on the Browser we can at least see Cookies`);
44+
console.log(this.request);
3945
}
4046

4147
ngOnInit() {

Client/app/app.module.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import { Ng2BootstrapComponent } from './containers/ng2-bootstrap-demo/ng2bootst
2121
import { LinkService } from './shared/link.service';
2222
import { ConnectionResolver } from './shared/route.resolver';
2323
import { ORIGIN_URL } from './shared/constants/baseurl.constants';
24+
import { TransferHttpModule } from '../modules/transfer-http/transfer-http.module';
2425

2526
export function createTranslateLoader(http: Http, baseHref) {
26-
console.log('\n\n\n New method? ' + baseHref);
2727
// Temporary Azure hack
2828
if (baseHref === null && typeof window !== 'undefined') {
2929
baseHref = window.location.origin;
@@ -41,13 +41,15 @@ export function createTranslateLoader(http: Http, baseHref) {
4141
HomeComponent,
4242
ChatComponent,
4343
Ng2BootstrapComponent
44-
],
44+
],
4545
imports: [
4646
CommonModule,
4747
HttpModule,
4848
FormsModule,
4949
Ng2BootstrapModule.forRoot(), // You could also split this up if you don't want the Entire Module imported
5050

51+
TransferHttpModule, // Our Http TransferData method
52+
5153
// i18n support
5254
TranslateModule.forRoot({
5355
loader: {

Client/app/browser-app.module.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { SignalRModule, SignalRConfiguration } from 'ng2-signalr';
88
import { ORIGIN_URL } from './shared/constants/baseurl.constants';
99
import { AppModule } from './app.module';
1010
import { AppComponent } from './app.component';
11+
import { REQUEST } from './shared/constants/request';
12+
import { BrowserTransferStateModule } from '../modules/transfer-state/browser-transfer-state.module';
1113

1214
export function createConfig(): SignalRConfiguration {
1315
const signalRConfig = new SignalRConfiguration();
@@ -24,23 +26,35 @@ export function getOriginUrl() {
2426
return window.location.origin;
2527
}
2628

29+
export function getRequest() {
30+
// the Request object only lives on the server
31+
return { cookie: document.cookie };
32+
}
33+
2734
@NgModule({
2835
bootstrap: [AppComponent],
2936
imports: [
3037
BrowserModule.withServerTransition({
3138
appId: 'my-app-id' // make sure this matches with your Server NgModule
3239
}),
3340
BrowserAnimationsModule,
41+
BrowserTransferStateModule,
42+
3443
// Our Common AppModule
3544
AppModule,
3645

3746
SignalRModule.forRoot(createConfig)
3847
],
3948
providers: [
4049
{
41-
// We need this for our Http calls since they'll be using APP_BASE_HREF (since the Server requires Absolute URLs)
50+
// We need this for our Http calls since they'll be using an ORIGIN_URL provided in main.server
51+
// (Also remember the Server requires Absolute URLs)
4252
provide: ORIGIN_URL,
4353
useFactory: (getOriginUrl)
54+
}, {
55+
// The server provides these in main.server
56+
provide: REQUEST,
57+
useFactory: (getRequest)
4458
}
4559
]
4660
})

Client/app/containers/users/users.component.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { APP_BASE_HREF } from '@angular/common';
77

88
import { Http, URLSearchParams } from '@angular/http';
99
import { ORIGIN_URL } from '../../shared/constants/baseurl.constants';
10+
import { TransferHttp } from '../../../modules/transfer-http/transfer-http';
1011

1112
@Component({
1213
selector: 'fetchdata',
@@ -33,16 +34,24 @@ export class UsersComponent implements OnInit {
3334

3435
// Use "constructor"s only for dependency injection
3536
constructor(
36-
private http: Http,
37+
private transferHttp: TransferHttp, // Use only for GETS that you want re-used between Server render -> Client render
38+
private http: Http, // Use for everything else
3739
@Inject(ORIGIN_URL) private baseUrl: string
3840
) { }
3941

4042
// Here you want to handle anything with @Input()'s @Output()'s
4143
// Data retrieval / etc - this is when the Component is "ready" and wired up
4244
ngOnInit() {
43-
this.newUserName = "";
44-
this.http.get(`${this.baseUrl}/api/user/all`).map(res => res.json()).subscribe(result => {
45-
console.log(result);
45+
46+
this.newUserName = '';
47+
48+
// ** TransferHttp example / concept **
49+
// - Here we make an Http call on the server, save the result on the window object and pass it down with the SSR,
50+
// The Client then re-uses this Http result instead of hitting the server again!
51+
52+
// NOTE : transferHttp also automatically does .map(res => res.json()) for you, so no need for these calls
53+
this.transferHttp.get(`${this.baseUrl}/api/user/all`).subscribe(result => {
54+
console.log('TransferHttp [GET] /api/user/allresult', result);
4655
this.users = result as IUser[];
4756
});
4857
}
@@ -52,9 +61,8 @@ export class UsersComponent implements OnInit {
5261
if (result.ok) {
5362
let position = this.users.indexOf(user);
5463
this.users.splice(position, 1);
55-
}
56-
else {
57-
alert("There was an issue, Could not delete user");
64+
} else {
65+
alert('There was an issue, Could not delete user');
5866
}
5967
});
6068
}
@@ -65,8 +73,9 @@ export class UsersComponent implements OnInit {
6573
urlSearchParams.append('name', user.name);
6674

6775
this.http.put(`${this.baseUrl}/api/user/update`, urlSearchParams).subscribe(result => {
68-
if (!result.ok) {
69-
alert("There was an issue, Could not edit user");
76+
console.log('result: ', result);
77+
if (!result) {
78+
alert('There was an issue, Could not edit user');
7079
}
7180
});
7281
}
@@ -76,12 +85,11 @@ export class UsersComponent implements OnInit {
7685
urlSearchParams.append('name', newUserName);
7786

7887
this.http.post(`${this.baseUrl}/api/user/insert`, urlSearchParams).subscribe(result => {
79-
if (result.ok) {
88+
if (result) {
8089
this.users.push(result.json());
81-
this.newUserName = "";
82-
}
83-
else {
84-
alert("There was an issue, Could not edit user");
90+
this.newUserName = '';
91+
} else {
92+
alert('There was an issue, Could not edit user');
8593
}
8694
});
8795
}

Client/app/server-app.module.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
11
import { NgModule } from '@angular/core';
22
import { ServerModule } from '@angular/platform-server';
33
import { BrowserModule } from '@angular/platform-browser';
4-
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
4+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
55

66
import { AppModule } from './app.module';
77
import { AppComponent } from './app.component';
8-
8+
import { ServerTransferStateModule } from '../modules/transfer-state/server-transfer-state.module';
9+
import { TransferState } from '../modules/transfer-state/transfer-state';
910

1011
@NgModule({
11-
bootstrap: [ AppComponent ],
12-
imports: [
13-
BrowserModule.withServerTransition({
14-
appId: 'my-app-id' // make sure this matches with your Browser NgModule
15-
}),
16-
ServerModule,
17-
NoopAnimationsModule,
18-
19-
// Our Common AppModule
20-
AppModule
21-
]
12+
bootstrap: [AppComponent],
13+
imports: [
14+
BrowserModule.withServerTransition({
15+
appId: 'my-app-id' // make sure this matches with your Browser NgModule
16+
}),
17+
ServerModule,
18+
NoopAnimationsModule,
19+
20+
ServerTransferStateModule,
21+
22+
// Our Common AppModule
23+
AppModule
24+
]
2225
})
2326
export class ServerAppModule {
2427

25-
// constructor(private transferState: TransferState) { }
28+
constructor(private transferState: TransferState) { }
2629

27-
// // Gotcha
28-
// ngOnBootstrap = () => {
29-
// this.transferState.inject();
30-
// }
30+
// Gotcha (needs to be an arrow function)
31+
ngOnBootstrap = () => {
32+
this.transferState.inject();
33+
}
3134
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { InjectionToken } from '@angular/core';
2+
3+
export const REQUEST = new InjectionToken<string>('REQUEST');

Client/main.server.aot.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,33 @@ import { ORIGIN_URL } from './app/shared/constants/baseurl.constants';
99
// Grab the (Node) server-specific NgModule
1010
import { ServerAppModuleNgFactory } from './ngfactory/app/server-app.module.ngfactory';
1111
// Temporary * the engine will be on npm soon (`@universal/ng-aspnetcore-engine`)
12-
import { ngAspnetCoreEngineAoT } from './polyfills/temporary-aspnetcore-engine';
12+
import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from './polyfills/temporary-aspnetcore-engine';
1313

1414
enableProdMode();
1515

1616
export default createServerRenderer(params => {
1717

18-
// Platform-server provider configuration
19-
const providers = [
20-
{
21-
provide: INITIAL_CONFIG,
22-
useValue: {
23-
document: '<app></app>', // Our Root application document
24-
url: params.url
25-
}
26-
}, {
27-
provide: ORIGIN_URL,
28-
useValue: params.origin
29-
}
30-
];
18+
// Platform-server provider configuration
19+
const setupOptions: IEngineOptions = {
20+
appSelector: '<app></app>',
21+
ngModule: ServerAppModuleNgFactory,
22+
request: params,
23+
providers: [
24+
// Optional - Any other Server providers you want to pass (remember you'll have to provide them for the Browser as well)
25+
]
26+
};
3127

32-
return ngAspnetCoreEngineAoT(providers, ServerAppModuleNgFactory).then(response => {
33-
return ({
34-
html: response.html,
35-
globals: response.globals
36-
});
28+
return ngAspnetCoreEngine(setupOptions).then(response => {
29+
// Apply your transferData to response.globals
30+
response.globals.transferData = createTransferScript({
31+
someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object'
3732
});
33+
34+
return ({
35+
html: response.html,
36+
globals: response.globals
37+
});
38+
});
3839
});
3940

4041
/* -------- THIS FILE IS TEMPORARY and will be gone when @ngtools/webpack can handle dual files (w server) ---------- */

Client/main.server.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,32 @@ import { ORIGIN_URL } from './app/shared/constants/baseurl.constants';
99
// Grab the (Node) server-specific NgModule
1010
import { ServerAppModule } from './app/server-app.module';
1111
// Temporary * the engine will be on npm soon (`@universal/ng-aspnetcore-engine`)
12-
import { ngAspnetCoreEngine } from './polyfills/temporary-aspnetcore-engine';
12+
import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from './polyfills/temporary-aspnetcore-engine';
1313

1414
enableProdMode();
1515

16-
export default createServerRenderer(params => {
16+
export default createServerRenderer((params: BootFuncParams) => {
1717

18-
// Platform-server provider configuration
19-
const providers = [
20-
{
21-
provide: INITIAL_CONFIG,
22-
useValue: {
23-
document: '<app></app>', // Our Root application document
24-
url: params.url
25-
}
26-
}, {
27-
provide: ORIGIN_URL,
28-
useValue: params.origin
29-
}
30-
];
18+
// Platform-server provider configuration
19+
const setupOptions: IEngineOptions = {
20+
appSelector: '<app></app>',
21+
ngModule: ServerAppModule,
22+
request: params,
23+
providers: [
24+
// Optional - Any other Server providers you want to pass (remember you'll have to provide them for the Browser as well)
25+
]
26+
};
3127

32-
return ngAspnetCoreEngine(providers, ServerAppModule).then(response => {
33-
return ({
34-
html: response.html,
35-
globals: response.globals
36-
});
28+
return ngAspnetCoreEngine(setupOptions).then(response => {
29+
// Apply your transferData to response.globals
30+
response.globals.transferData = createTransferScript({
31+
someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object',
32+
fromDotnet: params.data.thisCameFromDotNET // example of data coming from dotnet, in HomeController
3733
});
34+
35+
return ({
36+
html: response.html,
37+
globals: response.globals
38+
});
39+
});
3840
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { NgModule } from '@angular/core';
2+
import { Http, HttpModule } from '@angular/http';
3+
import { TransferHttp } from './transfer-http';
4+
5+
@NgModule({
6+
providers: [
7+
TransferHttp
8+
]
9+
})
10+
export class TransferHttpModule {}

0 commit comments

Comments
 (0)