2013-04-18 36 views
33

我正在通過AngularJS教程學習。 Angular使用它自己的JS路由機制來支持單頁面應用。 Angular的示例路由文件如下所示:Play Framework 2.1 - AngularJS路由 - 最佳解決方案?

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文件)。我能做到這一點使用AA播放routes文件,像這樣:

GET  /partials/phone_index  controllers.Application.phone_index 

我基本上泛音/到一個控制器的動作是這樣的:

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

我正在尋找解決的辦法是兩種理想的組合:

  1. 我會有某種映射讓我訪問/ partial/*下的任何文件並獲取部分文件。
  2. 我想重寫一個路由到一個特定的部分,所以我CAN使用控制器動作來動態填充數據(罕見)。

任何想法?

回答

32

當我嘗試類似的東西我來,這是更好地打破它在兩個部分的結論:

  • 使用Play作爲後端你通過Ajax調用
  • 商店角模板播放public文件夾(類似/public/angular/)進行交互,並使用默認AngularJs方式向模板

我知道這聽起來不偉大的,真正沒有映射回答你的問題如何做,但試圖鏈接這兩個框架可能會有問題,因爲模板和他們的URL在Angular中映射的方式,並且好處將會很小,因爲任何更改都意味着很多工作,從而消除這可以說是Play和Angular的快速發展的主要好處。

這也允許你更好地分離問題,如果你的項目增長可能很重要,因爲你可以把AngularJS代碼作爲一個獨立的應用程序連接到後端,它會正常工作。

你可以在Github repository中看到我說的一些示例代碼(基於AngularJS的TODO教程)。我警告你,代碼不太好,但應該給你一個想法,並作爲獎金向你展示如何將Jasmine整合到Play中,以便進行AngularJS單元測試。

+2

我認爲這可能是我需要的方法。 –

+0

那麼,如果設置了「play.http.context」屬性,則此方法不起作用。該路由將錯過上下文前綴並因此失敗。任何想法如何克服這個問題? – user2715478

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() 
+0

這會工作。但它需要使用路由名稱映射到控制器。這不是一個更好的數字。謝謝你。希望它能幫助別人。 –

1

我真的覺得這不是一個很好的主意,即使它來自一個尊敬的心。

我認爲這是一個非常好的做法,讓每個想法都成爲默認(約定優於配置原則),這對我來說意味着我們可能更有興趣將每個Paradigms(Play和AngularJS)分離爲一個或兩個進化在不久的將來或將來會有代碼維護的代價。

第二個非常重要的問題是可測試性,如果你將兩種技術混合在一起,你最終會得到一個混合體,以在應用程序的兩端提供真正的測試覆蓋率。 乾杯

3

這不會直接回答你的問題,但我發現這是建立播放+角應用程序的最佳方式:

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

+1

我不喜歡這裏是在開始時使用requireJS和webjars。對我來說這是有道理的後添加。 (它不像Java中的maven那麼簡單,就像我一樣)。當應用程序足夠大時,這很有用。這不會改變+ Pere Villega關於'快速發展'的說法 – ses

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> 

,並確保根內使用你的角度應用程序的範圍。

4

最終的種子(https://github.com/angyjoe/eventual)是另一種構建Play + AngularJS應用的方式。該代碼是一個心上人,並有詳細記錄。

+2

您可能想要在這裏披露,我的檢查表明您是該作者。這本身並不是一種犯罪,它似乎是相關的信息,只是我們不善於廣告太多。 –

+0

這很好,正如我所說的,如果你打開並且說出類似「泄露:我是所述工具的作者,並且它是爲迴應這個問題而寫的」,那麼人們更相信你。 –