feat(platform-server): add an API to transfer state from server (#19134)
TransferState provides a shared store that is transferred from the server to client. To use it import BrowserTransferStateModule from the client app module and ServerTransferStateModule from the server app module and TransferState will be available as an Injectable object. PR Close #19134
This commit is contained in:

committed by
Igor Minar

parent
f96142cd7c
commit
cfd9ca0d6f
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {browser, by, element} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from './util';
|
||||
|
||||
describe('TransferState', function() {
|
||||
it('should transfer component state', function() {
|
||||
// Load the page without waiting for Angular since it is not boostrapped automatically.
|
||||
browser.driver.get(browser.baseUrl + 'transferstate');
|
||||
|
||||
// Test the contents from the server.
|
||||
const serverDiv = browser.driver.findElement(by.css('div'));
|
||||
expect(serverDiv.getText()).toEqual('5');
|
||||
|
||||
// Bootstrap the client side app and retest the contents
|
||||
browser.executeScript('doBootstrap()');
|
||||
expect(element(by.css('div')).getText()).toEqual('50');
|
||||
|
||||
// Make sure there were no client side errors.
|
||||
verifyNoBrowserErrors();
|
||||
});
|
||||
});
|
@ -15,6 +15,9 @@ import * as express from 'express';
|
||||
import {HelloWorldServerModuleNgFactory} from './helloworld/app.server.ngfactory';
|
||||
const helloworld = require('raw-loader!./helloworld/index.html');
|
||||
|
||||
import {TransferStateServerModuleNgFactory} from './transferstate/app.server.ngfactory';
|
||||
const transferstate = require('raw-loader!./transferstate/index.html');
|
||||
|
||||
const app = express();
|
||||
|
||||
function render<T>(moduleFactory: NgModuleFactory<T>, html: string) {
|
||||
@ -36,5 +39,6 @@ app.get('/favicon.ico', (req, res) => { res.send(''); });
|
||||
|
||||
//-----------ADD YOUR SERVER SIDE RENDERED APP HERE ----------------------
|
||||
app.get('/helloworld', render(HelloWorldServerModuleNgFactory, helloworld));
|
||||
app.get('/transferstate', render(TransferStateServerModuleNgFactory, transferstate));
|
||||
|
||||
app.listen(9876, function() { console.log('Server listening on port 9876!'); });
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ServerModule, ServerTransferStateModule} from '@angular/platform-server';
|
||||
|
||||
import {TransferStateModule} from './app';
|
||||
import {TransferStateComponent} from './transfer-state.component';
|
||||
|
||||
@NgModule({
|
||||
bootstrap: [TransferStateComponent],
|
||||
imports: [TransferStateModule, ServerModule, ServerTransferStateModule],
|
||||
})
|
||||
export class TransferStateServerModule {
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule, BrowserTransferStateModule} from '@angular/platform-browser';
|
||||
|
||||
import {TransferStateComponent} from './transfer-state.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [TransferStateComponent],
|
||||
bootstrap: [TransferStateComponent],
|
||||
imports: [
|
||||
BrowserModule.withServerTransition({appId: 'ts'}),
|
||||
BrowserTransferStateModule,
|
||||
],
|
||||
})
|
||||
export class TransferStateModule {
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import 'zone.js/dist/zone.js';
|
||||
|
||||
import {enableProdMode} from '@angular/core';
|
||||
import {platformBrowser} from '@angular/platform-browser';
|
||||
import {TransferStateModuleNgFactory} from './app.ngfactory';
|
||||
|
||||
window['doBootstrap'] = function() {
|
||||
platformBrowser().bootstrapModuleFactory(TransferStateModuleNgFactory);
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello World</title>
|
||||
<script src="built/transferstate-bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<transfer-state-app></transfer-state-app>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {isPlatformServer} from '@angular/common';
|
||||
import {Component, Inject, PLATFORM_ID} from '@angular/core';
|
||||
import {StateKey, TransferState, makeStateKey} from '@angular/platform-browser';
|
||||
|
||||
const COUNTER_KEY = makeStateKey<number>('counter');
|
||||
|
||||
@Component({
|
||||
selector: 'transfer-state-app',
|
||||
template: `
|
||||
<div>{{counter}}</div>
|
||||
`,
|
||||
})
|
||||
export class TransferStateComponent {
|
||||
counter = 0;
|
||||
|
||||
constructor(@Inject(PLATFORM_ID) private platformId: {}, private transferState: TransferState) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (isPlatformServer(this.platformId)) {
|
||||
// Set it to 5 in the server.
|
||||
this.counter = 5;
|
||||
this.transferState.set(COUNTER_KEY, 50);
|
||||
} else {
|
||||
// Get the transferred counter state in the client(should be 50 and not 0).
|
||||
this.counter = this.transferState.get(COUNTER_KEY, 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ const path = require('path');
|
||||
module.exports = {
|
||||
entry: {
|
||||
helloworld: './built/src/helloworld/client.js',
|
||||
transferstate: './built/src/transferstate/client.js',
|
||||
},
|
||||
output: {path: path.join(__dirname, 'built'), filename: '[name]-bundle.js'},
|
||||
module: {loaders: [{test: /\.js$/, loader: 'babel-loader?presets[]=es2015'}]},
|
||||
|
Reference in New Issue
Block a user