2013-04-18 15 views
33

Sto lavorando al tutorial di AngularJS. Angular utilizza il proprio meccanismo di routing JS per consentire app a singola pagina. Un file di routing di esempio per angolare appare così:Play Framework 2.1 - Routing AngularJS - la soluzione migliore?

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

Sto cercando di venire con un buon posto dove riporre i miei parziali (file HTML specifici angolare). Idealmente mi piacerebbe la possibilità di modellarli all'interno di Play (ad esempio li hanno come file * .scala.html). Posso fare questo usando Giocare aa file di itinerari in questo modo:

GET  /partials/phone_index  controllers.Application.phone_index 

I parziali fondamentalmente/ad un'azione di controllo come questo:

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

La soluzione che sto cercando è una combinazione di due ideali:

  1. Avrei una sorta di mappatura che mi consente di visitare qualsiasi file in/partial/* e di recuperare il file parziale.
  2. Vorrei eseguire l'override di una route verso un partial specifico in modo che I CAN utilizzi un'azione controller per riempire dinamicamente con i dati (raro).

Qualche idea?

risposta

32

Quando stavo cercando qualcosa di simile sono giunto alla conclusione che è meglio rompere su 2 parti:

  • Usa Gioca come un backend si interagire con tramite Ajax chiama
  • Conservare i modelli angolari in Play cartella public (qualcosa come /public/angular/) e utilizzare il modo AngularJs di default per mappare i modelli

So che non suona grande e davvero non lo fa rispondi alla tua domanda su come farlo, ma provare a collegare entrambi i framework può essere problematico a causa del modo in cui i template e i loro url sono mappati in Angular, e il beneficio sarà molto piccolo in quanto qualsiasi modifica implicherà molto lavoro, rimuovendo così il principale vantaggio di Play e Angular, lo sviluppo rapido.

Questo permette anche di separare le preoccupazioni migliori, che se il progetto cresce può essere importante in quanto si può semplicemente prendere il codice AngularJS via come un'applicazione stand-alone la connessione a un back-end, e funzionerà bene.

È possibile visualizzare alcuni esempi di codice di ciò che ho detto (basato sul tutorial TODO di AngularJS) in questo Github repository. Ti avverto, il codice non è troppo bello, ma dovrebbe darti un'idea e come bonus ti mostra come integrare Jasmine in Play, per il test delle unità AngularJS.

+2

Penso che questo sia probabilmente l'approccio con cui dovrò andare. –

+0

Bene, questo approccio non funziona se la proprietà "play.http.context" è impostata. Il percorso mancherà il prefisso del contesto e quindi fallirà. Qualche idea su come superare questo problema? – user2715478

1

Per la domanda # 1 si potrebbe introdurre un percorso come questo:

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

Poi nel controller si avrebbe bisogno di mappare dal nome di una vista a vista reale:

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

si potrebbe desiderare di rendere i modelli pigri o richiedere la presenza della richiesta, quindi probabilmente dovresti fare qualcosa del genere:

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

La vostra azione sarebbe simile a questa:

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

Se si desidera un metodo di controllo specifico per un determinato percorso (domanda # 2) in modo semplice aggiungere un percorso sopra la dinamica uno:

/partials/specific controllers.Application.specific() 
+0

Questo potrebbe funzionare. Ma richiede l'utilizzo di una mappa dei nomi delle rotte per i controller. Non è una quantità enorme migliore. Grazie comunque. Spero che aiuterà qualcun altro. –

1

Penso davvero che non sia una buona idea anche se proviene da una mente rispettosa.

Penso che sia una buona pratica lasciare ogni pensiero come predefinito (convenzione rispetto al principio di configurazione), il che significa che probabilmente abbiamo più interesse a mantenere separati tutti i paradigmi (Play e AngularJS) in quanto uno o entrambi potrebbero evolvere nel vicino o nel lontano futuro che avrà il suo costo per la manutenzione del codice.

Il secondo punto molto importante è la testabilità, se si mescolano entrambe le tecnologie si finisce con un mix per ottenere una buona copertura dei test in entrambi i lati dell'applicazione. Acclamazioni

3

questo non rispondere alla tua domanda direttamente, ma ho scoperto che questo è il modo migliore per costruire gioco + applicazioni angolari:

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

+1

Quello che non mi piace qui è usare requireJS e webjars all'inizio. Per me ha senso aggiungere dopo. (non è così semplice come maven in java come per me). Funziona bene quando l'app è abbastanza grande. E questo non cambia quello che è stato detto da + Pere Villega sul 'rapido sviluppo' – ses

3

Sì, è possibile creare meta sul lato server -template di modelli lato client. Questo offre alcune abilità uniche, in quanto i due metodi non si sovrappongono completamente. C'è anche molto spazio per la confusione, quindi assicurati di sapere perché stai scrivendo un blocco Play invece di una direttiva Angular.

Se si debba o meno farlo rimane una domanda aperta; dipende davvero se hai effettivamente bisogno di accedere alle informazioni del server nei tuoi modelli. Un esempio di dove penso che sarebbe necessario e appropriato sarebbe per l'implementazione del controllo degli accessi nelle vostre opinioni.

Ora per rispondere alla tua domanda. Il problema viene risolto inserendo i partial invece di provare a fornire un percorso per caricarli su richiesta. Vedi http://docs.angularjs.org/api/ng.directive:script.

Ecco quello che sembra il modello simile:

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

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

sufficiente includere questo 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> 

e assicurarsi di utilizzarlo all'interno della radice portata della tua app angolare.

4

L'eventuale seme (https://github.com/angyjoe/eventual) è un altro modo per creare un'app Play + AngularJS. Il codice è un tesoro e ben documentato.

+2

Si potrebbe desiderare una divulgazione qui, il mio controllo suggerisce che ne sei l'autore. Questo di per sé non è un crimine, sembra essere un'informazione correlata, ma non prendiamo molto pubblicamente la pubblicità. –

+0

Va bene, proprio come ho detto, le persone si fidano di te di più se sei aperto e dici qualcosa come "Disclosure: sono autore di tale strumento ed è stato scritto in risposta a questa domanda". –

Problemi correlati