32

我正在学习 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'});
}]);

我试图想出一个好地方来存储我的部分(Angular 特定的 HTML 文件)。理想情况下,我希望能够从 Play 中对它们进行模板化(即,将它们作为 *.scala.html 文件)。我可以使用播放路由文件来完成此操作,如下所示:

GET     /partials/phone_index       controllers.Application.phone_index

我基本上将/部分分配给这样的控制器操作:

def phone_index = Action {
  Ok(views.html.partials.phone_index())
}

我正在寻找的解决方案是两种理想的结合:

  1. 我会有某种映射,可以让我访问 /partial/* 下的任何文件并取回部分文件。
  2. 我想要覆盖到特定部分的路由,因此我可以使用控制器操作来动态填充数据(很少见)。

有任何想法吗?

4

7 回答 7

31

当我尝试类似的事情时,我得出的结论是最好将其分成两部分:

  • 将 Play 用作您通过 Ajax 调用与之交互的后端
  • 将 Angular 模板存储在 Playpublic文件夹中(类似于/public/angular/)并使用默认的 AngularJs 方式来映射模板

我知道这听起来不太好,并且真的没有回答你关于如何做到这一点的问题,但是由于模板及其 url 在 Angular 中的映射方式,尝试链接这两个框架可能会出现问题,而且好处将非常任何更改都将意味着大量工作,从而消除了 Play 和 Angular 的主要优点,即快速开发。

这也允许您更好地分离关注点,如果您的项目增长可能很重要,因为您可以将 AngularJS 代码作为连接到后端的独立应用程序拿走,它会正常工作。

你可以在这个Github 存储库中看到我所说的一些示例代码(基于 AngularJS 的 TODO 教程)。我警告你,代码不是很好,但应该给你一个想法,并且作为奖励向你展示如何将 Jasmine 集成到 Play 中,用于 AngularJS 单元测试。

于 2013-04-22T13:53:48.117 回答
4

最终的种子 ( https://github.com/angyjoe/eventual ) 是构建 Play + AngularJS 应用程序的另一种方式。该代码是一个甜心并且有据可查。

于 2013-11-17T02:44:46.197 回答
3

这不会直接回答您的问题,但我发现这是构建 Play + Angular 应用程序的最佳方式:

https://github.com/typesafehub/angular-seed-play

于 2013-07-04T15:03:54.303 回答
3

是的,可以创建客户端模板的服务器端元模板。这提供了一些独特的能力,因为这两种方法并不完全重叠。还有很多混淆的空间,所以请确保您知道为什么要编写 Play 块而不是 Angular 指令。

你是否应该这样做仍然是一个悬而未决的问题。这实际上取决于您是否真的需要访问模板中的服务器信息。我认为有必要和适当的一个例子是在您的视图中实施访问控制。

现在回答你的问题。通过内联部分而不是尝试为它们提供按需加载的路线来解决问题。请参阅http://docs.angularjs.org/api/ng.directive:script

模板如下所示:

@(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>

和应用程序:

'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'});
}]);

只需包括这个助手:

@**
 * @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>

并确保在 Angular 应用程序的根范围内使用它。

于 2013-08-30T18:00:09.033 回答
1

对于问题 #1,您可以引入这样的路线:

/partials/:view    controllers.Application.showView(view:String)

然后在您的控制器中,您需要从视图名称映射到实际视图:

Map("phone_index" -> views.html.partials.phone_index())

您可能希望延迟渲染模板或要求存在请求,那么您可能应该执行以下操作:

val routes = Map(
  "phone_index" -> { implicit r:RequestHeader => 
     views.html.partials.phone_index()) 
  }

您的操作将如下所示:

def showView(view:String) = 
  Action { implicit r =>
    routes(view)
  }

如果您想要特定路由的特定控制器方法(问题#2),您只需在动态路由上方添加一个路由:

/partials/specific    controllers.Application.specific()
于 2013-04-20T23:32:21.690 回答
1

我真的认为这不是一个好主意,即使它确实来自一个恭敬的心。

我认为将每个想法都保留为默认设置(约定优于配置原则)是一种非常好的做法,这对我来说意味着我们可能更感兴趣将每个范式(Play 和 AngularJS)分开,因为其中一个或两个可能会在近期或遥远的未来,它将为代码维护付出代价。

第二个非常重要的点是可测试性,如果你混合两种技术,你最终会得到一个混合,在你的应用程序的两边都提供真正好的测试覆盖率。干杯

于 2013-04-26T21:17:53.423 回答
1

这可能无法准确回答问题,但您可以尝试关注这个项目,因为它似乎是构建 Play/scala/Angular 应用程序的好例子:

https://github.com/lashford/modern-web-template#master

http://typesafe.com/activator/template/modern-web-template

于 2015-04-23T10:05:37.013 回答