Play Framework 2.1 - AngularJS routing - best solution?

前端 未结 7 1782
既然无缘
既然无缘 2020-12-23 16:57

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 t

相关标签:
7条回答
  • 2020-12-23 17:29

    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.

    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.

    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.

    0 讨论(0)
  • 2020-12-23 17:30

    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.

    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

    0 讨论(0)
  • 2020-12-23 17:33

    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.

    0 讨论(0)
  • 2020-12-23 17:36

    For question #1 you could introduce a route like this:

    /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 above the dynamic one:

    /partials/specific    controllers.Application.specific()
    
    0 讨论(0)
  • 2020-12-23 17:38

    This won't answer your question directly, but I found this to be the best way to build Play + Angular apps:

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

    0 讨论(0)
  • 2020-12-23 17:44

    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:

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

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

    0 讨论(0)
提交回复
热议问题