scala Play Framework 2.1 - AngularJS 路由 - 最佳解决方案?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16085544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Play Framework 2.1 - AngularJS routing - best solution?
提问by Dominic Bou-Samra
I am working my way through the AngularJS tutorial. Angular uses it's own JS routing mechanism to allow for single page apps. A sample routing file for Angular looks like this:
我正在学习 AngularJS 教程。Angular 使用它自己的 JS 路由机制来支持单页应用程序。Angular 的示例路由文件如下所示:
angular.module('phonecat', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {templateUrl: '/partials/phone-list', controller: PhoneListCtrl}).
when('/phones/:phoneId', {templateUrl: 'partials/phone-detail', controller: PhoneDetailCtrl}).
otherwise({redirectTo: '/phones'});
}]);
I am trying to come up with a good place to store my partials (Angular specific HTML files). Ideally i WOULD like the ability to template them from within Play (i.e. have them as *.scala.html files). I can accomplish this using a a Play routes file like so:
我试图想出一个好地方来存储我的部分(Angular 特定的 HTML 文件)。理想情况下,我希望能够从 Play 中对它们进行模板化(即,将它们作为 *.scala.html 文件)。我可以使用播放路由文件来完成此操作,如下所示:
GET /partials/phone_index controllers.Application.phone_index
I basically partials/ to a controller action like this:
我基本上偏爱/这样的控制器动作:
def phone_index = Action {
Ok(views.html.partials.phone_index())
}
The solution I am looking for is a combination of two ideals:
我正在寻找的解决方案是两个理想的组合:
- I would have some sort of mapping that lets me visit any file under /partial/* and get back the partial file.
- I would like the overriding a route to a specific partial so I CANuse a controller action to dynamically fill with data (rare).
- 我会有某种映射,让我访问 /partial/* 下的任何文件并取回部分文件。
- 我想重写路由到特定的部分,所以我的CAN用控制器动作来动态填充用数据(罕见)。
Any ideas?
有任何想法吗?
采纳答案by Pere Villega
When I was trying something similar I came to the conclusion that it's better to break it on 2 parts:
当我尝试类似的东西时,我得出的结论是最好把它分成两部分:
- Use Play as a backend you interact with via Ajax calls
- Store the Angular templates in Play
publicfolder (something like/public/angular/) and use the default AngularJs way to map the templates
- 使用 Play 作为您通过 Ajax 调用与之交互的后端
- 将 Angular 模板存储在 Play
public文件夹中(类似于/public/angular/)并使用默认的 AngularJs 方式来映射模板
I know it doesn't sound great and really doesn't answer your question on how to do it, but trying to link both frameworks may be problematic due to the way templates and their urls are mapped in Angular, and the benefit will be very small as any change will imply a lot of work, thus removing the arguably main benefit of both Play and Angular, rapid development.
我知道这听起来不太好,并且确实没有回答您关于如何操作的问题,但是由于模板及其 URL 在 Angular 中的映射方式,尝试链接这两个框架可能会出现问题,并且好处将非常大小,因为任何更改都意味着大量工作,从而消除了 Play 和 Angular 快速开发的主要好处。
This also allows you to separate concerns better, which if your project grows may be important as you can just take the AngularJS code away as a standalone app connecting to a backend, and it will work fine.
这也允许您更好地分离关注点,如果您的项目增长,这可能很重要,因为您可以将 AngularJS 代码作为连接到后端的独立应用程序拿走,它会正常工作。
You can see some sample code of what I said (based on the TODO tutorial of AngularJS) in this Github repository. I warn you, the code is not too nice, but should give you an idea and as a bonus shows you how to integrate Jasmine into Play, for AngularJS unit testing.
你可以在这个Github 存储库中看到我所说的一些示例代码(基于 AngularJS 的 TODO 教程)。我警告你,代码不太好,但应该给你一个想法,作为奖励向你展示如何将 Jasmine 集成到 Play 中,用于 AngularJS 单元测试。
回答by user2845946
The eventual seed (https://github.com/angyjoe/eventual) is yet another way to build a Play + AngularJS app. The code is a sweetheart and well-documented.
最终种子 ( https://github.com/angyjoe/eventual) 是构建 Play + AngularJS 应用程序的另一种方式。该代码是一个甜心,并且有据可查。
回答by Alex
This won't answer your question directly, but I found this to be the best way to build Play + Angular apps:
这不会直接回答您的问题,但我发现这是构建 Play + Angular 应用程序的最佳方式:
回答by dbaumann
Yes, it's possible to create server-side meta-templates of client-side templates. This offers some unique abilities, as the two methods don't overlap completely. There's also plenty of room for confusion so be sure you know why you're writing a Play block instead of an Angular directive.
是的,可以创建客户端模板的服务器端元模板。这提供了一些独特的能力,因为这两种方法并不完全重叠。还有很多令人困惑的地方,因此请确保您知道为什么要编写 Play 块而不是 Angular 指令。
Whether or not you should do it remains an open question; it really depends on whether you actually need access to server information in your templates. An example of where I think it would be necessary and appropriate would be for implementing access control in your views.
你是否应该这样做仍然是一个悬而未决的问题。这实际上取决于您是否真的需要访问模板中的服务器信息。我认为必要和适当的一个例子是在您的视图中实施访问控制。
Now to answer your question. The problem is solved by inlining the partials instead of trying to provide a route for them to be loaded on demand. See http://docs.angularjs.org/api/ng.directive:script.
现在回答你的问题。问题是通过内联部分而不是尝试为它们提供按需加载的路径来解决的。请参阅http://docs.angularjs.org/api/ng.directive:script。
Here's what the template looks like:
这是模板的样子:
@(id: Long)(implicit request: RequestWithUser[AnyContent])
@import helper._
<!doctype html>
<html lang="en" ng-app="phonecat">
<head>
<meta charset="utf-8">
<title>Google Phone Gallery</title>
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="css/bootstrap.css">
<script src="lib/angular/angular.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/services.js"></script>
<script src="lib/angular/angular-resource.js"></script>
</head>
<body>
<div ng-view></div>
@ngTemplate("phone-list.html") {
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">Hello @request.user.name</div>
</div>
<div class="row-fluid">
<div class="span2">
<!--Sidebar content-->
Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</div>
<div class="span10">
<!--Body content-->
<ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail">
<a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a>
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<p>{{phone.snippet}}</p>
</li>
</ul>
</div>
</div>
</div>
}
@ngTemplate("phone-detail.html") {
<img ng-src="{{mainImageUrl}}" class="phone">
<h1>{{phone.name}}</h1>
<p>{{phone.description}}</p>
<ul class="phone-thumbs">
<li ng-repeat="img in phone.images">
<img ng-src="{{img}}" ng-click="setImage(img)">
</li>
</ul>
<ul class="specs">
<li>
<span>Availability and Networks</span>
<dl>
<dt>Availability</dt>
<dd ng-repeat="availability in phone.availability">{{availability}}</dd>
</dl>
</li>
</ul>
}
</body>
</html>
And the app:
和应用程序:
'use strict';
/* App Module */
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {templateUrl: 'phone-list.html', controller: PhoneListCtrl}).
when('/phones/:phoneId', {templateUrl: 'phone-detail.html', controller: PhoneDetailCtrl}).
otherwise({redirectTo: '/phones'});
}]);
Just include this helper:
只需包括这个助手:
@**
* @ngTemplate
* Generate an AngularJS inlined template.
*
* Note: Do not include scripts in your @template HTML. This will break the template.
*
* @param name
* @param template
*@
@(name: String)(template: Html)
<script type="text/ng-template" id="@name">@template</script>
And make sure to use it within the root scope of your angular app.
并确保在 angular 应用程序的根范围内使用它。
回答by Seif Tamallah
This might not answer the question exactly but you can try follow this project as it seems good example to build Play/scala/Angular apps:
这可能无法准确回答问题,但您可以尝试关注这个项目,因为它似乎是构建 Play/scala/Angular 应用程序的好例子:
https://github.com/lashford/modern-web-template#master
https://github.com/lashford/modern-web-template#master
回答by Abderrazak BOUADMA
I really think it's not a very good idea even it comes from a respectfully mind indeed.
我真的认为这不是一个很好的主意,即使它确实来自恭敬的头脑。
I think it's a very good practice to leave every think as defaulted (convention over configuration principle) which means for me that we've probably more interest to keep each Paradigms (Play and AngularJS) separated as one or both could evolve in the near or the far future which will have its cost for code maintenance.
我认为将每一个想法都保留为默认(约定优于配置原则)是一个非常好的做法,这意味着我们可能更感兴趣将每个范式(Play 和 AngularJS)分开,因为一个或两个可能会在近期或遥远的未来将有其代码维护成本。
The second very important point is testability, if you mix both technos you'll end up with a mix to come up with real good coverage of tests in both side of your application. Cheers
第二个非常重要的一点是可测试性,如果你混合两种技术,你最终会得到一个混合,在你的应用程序的两边都得到真正好的测试覆盖。干杯
回答by EECOLOR
For question #1 you could introduce a route like this:
对于问题#1,您可以引入这样的路线:
/partials/:view controllers.Application.showView(view:String)
Then in your controller you would need to map from view name to actual view:
然后在您的控制器中,您需要从视图名称映射到实际视图:
Map("phone_index" -> views.html.partials.phone_index())
You might want to render the templates lazy or require the request to be present, then you should probably do something like this:
您可能希望延迟渲染模板或要求存在请求,那么您可能应该执行以下操作:
val routes = Map(
"phone_index" -> { implicit r:RequestHeader =>
views.html.partials.phone_index())
}
Your action would look something like this:
您的操作将如下所示:
def showView(view:String) =
Action { implicit r =>
routes(view)
}
If you want a specific controller method for a certain route (question #2) you simple add a route abovethe dynamic one:
如果您想要特定路由的特定控制器方法(问题#2),您只需在动态路由上方添加一个路由:
/partials/specific controllers.Application.specific()

![Scala 的可变 Map 更新 [map(key) = newValue] 语法如何工作?](/res/img/loading.gif)