我们正在将应用程序从AngularJS转换为Angular5。我试图找出如何使用Angular5 -复制一些行为,即使用服务器端呈现来创建可注入的值.。
在我们当前的Angular1.6应用程序中,我们有以下index.hbs文件:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Collaborative Tool</title>
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon">
</head>
<body class="aui content" ng-app="app">
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script>
/* globals angular */
angular.module('app')
.value('USER', JSON.parse('{{{user}}}'))
.value('WORKSTREAM_ENUM', JSON.parse('{{{workStreamEnum}}}'))
.value('CATEGORY_ENUM', JSON.parse('{{{categoryEnum}}}'))
.value('ROLES_ENUM', JSON.parse('{{{roles}}}'))
.value('FUNCTIONAL_TEAM_ENUM', JSON.parse('{{{functionalTeams}}}'))
.value('CDT_ENV', '{{CDT_ENV}}')
.value('CDT_HOST', '{{CDT_HOST}}')
.value('CDT_LOGOUT_URL', '{{CDT_LOGOUT_URL}}');
</script>
</body>
</html>所以我们要做的是在第一个脚本标记中加载角,然后使用第二个脚本标记创建一些值/enum/常量。本质上是使用服务器端呈现(工具栏)将数据发送到前端。
我的问题是:是否有一些与Angular5非常相似的方法?我们如何使用服务器端呈现在Angular5?中创建可注入的模块/值?
发布于 2018-05-01 05:01:17
我的团队在从AngularJS过渡到Angular (v2的早期发布候选版本)时也遇到了同样的问题。我们提出了一个解决方案,我们仍然使用,我不知道任何更新,以使它更容易(至少当不使用角环球-如果您正在使用,然后有内置的东西来引导初始数据)。通过序列化JSON对象并将其设置为HTML中app根角组件上的属性,我们将数据传递给我们的角应用程序:
<app-root [configuration]="JSON_SERIALIZED_OBJECT"></app-root>其中JSON_SERIALIZED_OBJECT是实际的序列化对象。我们使用.NET (非核心,因此角环球并不是一个真正的选项)来呈现我们的页面(执行[configuration]="@JsonConvert.SerializeObject(Model.Context)"),所以不知道您需要做什么,但是看起来您应该能够做与之前序列化它相同的事情。
一旦安装完毕,我们必须在我们的主要应用程序组件中手动地JSON.parse(...)该对象,但是我们把它当作一个角度输入。这就是我们的组件抓取它的样子:
import { Component, ElementRef } from '@angular/core';
import { ConfigurationService } from 'app/core';
@Component(...)
export class AppComponent {
constructor(private element: ElementRef, private configurationService: ConfigurationService) {
this.setupConfiguration();
}
private setupConfiguration() {
const value = this.getAttributeValue('[configuration]');
const configuration = value ? JSON.parse(value) : {};
this.configurationService.setConfiguration(configuration);
}
private getAttributeValue(attribute: string) {
const element = this.element.nativeElement;
return element.hasAttribute(attribute) ? element.getAttribute(attribute) : null;
}
}如图所示,我们使用一个服务来共享系统周围的数据。它可以是这样简单的东西:
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Configuration } from './configuration.model';
@Injectable()
export class ConfigurationService {
private readonly configurationSubject$ = new BehaviorSubject<Configuration>(null);
readonly configuration$ = this.configurationSubject$.asObservable();
setConfiguration(configuration: Configuration) {
this.configurationSubject$.next(configuration);
}
}然后,在需要配置数据的组件中,注入此服务并监视更改。
import { Component, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/takeUntil';
import { ConfigurationService } from 'app/core';
@Component(...)
export class ExampleThemedComponent implements OnDestroy {
private readonly destroy$ = new Subject<boolean>();
readonly theme$: Observable<string> = this.configurationService.configuration$
.takeUntil(this.destroy$.asObservable())
.map(c => c.theme);
constructor(private configurationService: ConfigurationService) {
}
ngOnDestroy() {
this.destroy$.next(true);
}
}注意:我们有时在运行时对我们的配置进行更改,这就是为什么我们使用一个主题和可观察的。如果您的配置不会改变,那么您可以跳过这些示例的所有部分。
发布于 2018-05-01 05:29:23
在服务器端呈现依赖项时,仍然可以在组件内部使用依赖项注入。
如果您计划使用带有角5的服务器端呈现,您应该考虑查看角万向,它为在服务器端呈现角单页应用程序提供了构建块(对于SEO友好的可索引内容)。
有许多良好的角万向节项目在那里。[universal-starter][2]就是一个很好的例子。它使用ngExpressEngine在请求的url上动态呈现应用程序。它使用webpack项目配置,其中包含一个预发布任务,该任务编译您的应用程序并预先录制您的应用程序文件。此任务如下所示:
// Load zone.js for the server.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import {readFileSync, writeFileSync, existsSync, mkdirSync} from 'fs';
import {join} from 'path';
import {enableProdMode} from '@angular/core';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();
// Import module map for lazy loading
import {provideModuleMap} from '@nguniversal/module-map-ngfactory-loader';
import {renderModuleFactory} from '@angular/platform-server';
import {ROUTES} from './static.paths';
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP} = require('./dist/server/main.bundle');
const BROWSER_FOLDER = join(process.cwd(), 'browser');
// Load the index.html file containing referances to your application bundle.
const index = readFileSync(join('browser', 'index.html'), 'utf8');
let previousRender = Promise.resolve();
// Iterate each route path
ROUTES.forEach(route => {
var fullPath = join(BROWSER_FOLDER, route);
// Make sure the directory structure is there
if(!existsSync(fullPath)){
mkdirSync(fullPath);
}
// Writes rendered HTML to index.html, replacing the file if it already exists.
previousRender = previousRender.then(_ => renderModuleFactory(AppServerModuleNgFactory, {
document: index,
url: route,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
})).then(html => writeFileSync(join(fullPath, 'index.html'), html));
});稍后,您可以运行一个快速服务器,该服务器呈现应用程序生成的HTML:
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser'), {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('index', { req });
});
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});您可以运行服务器端特定的代码,例如:
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
constructor(@Inject(PLATFORM_ID) private platformId: Object) { ... }
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
// Client only code.
...
}
if (isPlatformServer(this.platformId)) {
// Server only code.
...
}
}但请注意,该窗口、文档、导航器和其他浏览器类型--服务器上不存在。因此,任何可能使用这些的库都可能无法工作。
发布于 2018-05-01 05:42:24
创建文件: data.ts。在这个文件中,声明变量及其类型(我只显示一个变量),并为每个变量创建InjectionToken:
import { InjectionToken } from '@angular/core';
// describes the value of the variable
export interface EmbeddedUserData {
userId: string;
// etc
}
// tells the app that there will be a global variable named EMBEDDED_USER_DATA (from index.html)
export declare const EMBEDDED_USER_DATA: EmbeddedUserData;
// creates injection token for DI that you can use it as a provided value (like value or constant in angular 1)
export UserData = new InjectionToken<EmbeddedUserData>('EmbeddedUserData');然后来到您的app.module.ts并提供以下标记:
// ...
providers: [
{ provide: UserData, useValue: EMBEDDED_USER_DATA }
],
// ...最后,将其用作任何正常的服务/注入值:
// ...
constructor(@Inject(UserData) userData: EmbeddedUserData) {}
// ...或者将其用作简单的导入变量(在本例中甚至不需要提供/注入任何内容):
import { EMBEDDED_USER_DATA } from './data.ts';因此,你几乎和你在安古拉杰的情况一样。剩下的唯一方法是在角脚本之前将变量添加到index.html中(也许把变量放在head中也是有意义的):
<script>var EMBEDDED_USER_DATA = JSON.parse({ ... })</script>https://stackoverflow.com/questions/49976990
复制相似问题