Question

Dans actuelle1, j'ai l'habitude de prendre toutes les données dans les actions, de les utiliser directement dans les vues.Depuis nous n'avons pas besoin de déclarer explicitement les paramètres dans la vue, c'est très facile.

Mais dans play2, j'ai trouvé que nous avons à déclarer tous les paramètres(y compris les request) dans la tête de vues, il va être très ennuyeux pour obtenir toutes les données dans les actions et de les transmettre dans les vues.

Par exemple, si j'ai besoin d'afficher les menus qui sont chargés à partir de la base de données dans la première page, j'ai de la définir dans main.scala.html:

@(title: String, menus: Seq[Menu])(content: Html)    

<html><head><title>@title</title></head>
<body>
    <div>
    @for(menu<-menus) {
       <a href="#">@menu.name</a>
    }
    </div>
    @content
</body></html>

Puis-je déclarer dans chaque sous-page:

@(menus: Seq[Menu])

@main("SubPage", menus) {
   ...
}

Puis-je obtenir les menus et la transmettre à la vue de chaque action:

def index = Action {
   val menus = Menu.findAll()
   Ok(views.html.index(menus))
}

def index2 = Action {
   val menus = Menu.findAll()
   Ok(views.html.index2(menus))
}

def index3 = Action {
   val menus = Menu.findAll()
   Ok(views.html.index(menus3))
}

Pour l'instant c'est un seul paramètre dans main.scala.html, si il y a beaucoup?

Si à la fin, j'ai décidé de tous les Menu.findAll() directement dans la vue:

@(title: String)(content: Html)    

<html><head><title>@title</title></head>
<body>
    <div>
    @for(menu<-Menu.findAll()) {
       <a href="#">@menu.name</a>
    }
    </div>
    @content
</body></html>

Je ne sais pas si c'est bon ou recommandé, est-il une meilleure solution pour cela?

Était-ce utile?

La solution

À mon avis, le fait que les modèles sont de type statique est en fait un bon chose:vous avez la garantie que le fait d'appeler votre modèle ne manquera pas, si il compile.

Cependant, il ajoute en effet certains passe-partout sur la vocation des sites.Mais vous pouvez le réduire (sans perdre le typage statique avantages).

En Scala, je vois deux façons d'y parvenir:par le biais d'actions de la composition ou à l'aide de paramètres implicites.En Java, je suggère d'utiliser le Http.Context.args carte pour stocker les valeurs utiles et de les récupérer à partir des modèles sans avoir à transmettre explicitement comme des modèles de paramètres.

À l'aide de paramètres implicites

Place de la menus paramètre à la fin de votre main.scala.html les paramètres de modèle et de le marquer comme “implicite”:

@(title: String)(content: Html)(implicit menus: Seq[Menu])    

<html>
  <head><title>@title</title></head>
  <body>
    <div>
      @for(menu<-menus) {
        <a href="#">@menu.name</a>
      }
    </div>
    @content
  </body>
</html>

Maintenant, si vous avez des modèles à l'appel de cette template principal, vous pouvez avoir la menus paramètre implicitement passé pour vous à la main modèle par le compilateur Scala s'il est déclaré comme un paramètre implicite dans ces modèles ainsi:

@()(implicit menus: Seq[Menu])

@main("SubPage") {
  ...
}

Mais si vous voulez l'avoir implicitement adoptée à partir de votre contrôleur, vous devez fournir une valeur implicite, disponible dans le champ d'application de l'endroit où vous appelez le modèle.Par exemple, vous pouvez déclarer la méthode suivante dans votre contrôleur:

implicit val menu: Seq[Menu] = Menu.findAll

Ensuite, dans vos actions, vous serez en mesure de simplement écrire ce qui suit:

def index = Action {
  Ok(views.html.index())
}

def index2 = Action {
  Ok(views.html.index2())
}

Vous pouvez trouver plus d'informations sur cette approche dans ce blog et dans cet exemple de code.

Mise à jour:Un joli blog en démontrant ce motif a également été écrite ici.

À l'aide d'actions de la composition

En fait, il est souvent utile de passer le RequestHeader de la valeur pour les modèles (voir par ex. cet exemple).Ce n'ajoute pas tellement passe-partout pour votre contrôleur de code, parce que vous pouvez facilement écrire des actions de la réception d'une demande implicite de valeur:

def index = Action { implicit request =>
  Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}

Ainsi, depuis les modèles reçoivent souvent au moins ce paramètre implicite, vous pouvez le remplacer avec une riche valeur contenant par exemplevos menus.Vous pouvez faire cela en utilisant la les actions de la composition mécanisme de Jouer à 2.

Pour cela, vous devez définir vos Context la classe, l'enchaînement d'un sous-jacente de la demande:

case class Context(menus: Seq[Menu], request: Request[AnyContent])
        extends WrappedRequest(request)

Ensuite, vous pouvez définir les éléments suivants ActionWithMenu méthode:

def ActionWithMenu(f: Context => Result) = {
  Action { request =>
    f(Context(Menu.findAll, request))
  }
}

Qui peut être utilisée comme ceci:

def index = ActionWithMenu { implicit context =>
  Ok(views.html.index())
}

Et vous pouvez prendre le contexte comme un paramètre implicite dans vos templates.E. g.pour main.scala.html:

@(title: String)(content: Html)(implicit context: Context)

<html><head><title>@title</title></head>
  <body>
    <div>
      @for(menu <- context.menus) {
        <a href="#">@menu.name</a>
      }
    </div>
    @content
  </body>
</html>

Utilisant les actions de la composition permet de regrouper toutes les valeurs implicites des templates de votre besoin en une seule valeur, mais d'un autre côté, vous pouvez perdre un peu de souplesse...

À L'Aide De Http.Contexte (Java)

Depuis Java n'a pas de Scala implicites mécanisme ou similaire, si vous voulez éviter de transmettre explicitement les modèles de paramètres d'une solution possible est de les stocker dans la Http.Context objet qui ne vit que pour la durée d'une requête.Cet objet contient un args valeur de type Map<String, Object>.

Ainsi, vous pouvez commencer par écrire un intercepteur, comme expliqué dans la documentation:

public class Menus extends Action.Simple {

    public Result call(Http.Context ctx) throws Throwable {
        ctx.args.put("menus", Menu.find.all());
        return delegate.call(ctx);
    }

    public static List<Menu> current() {
        return (List<Menu>)Http.Context.current().args.get("menus");
    }
}

La méthode statique est juste un raccourci pour récupérer les menus dans le contexte actuel.Ensuite annoter votre contrôleur à être mélangée avec l' Menus l'action de l'intercepteur:

@With(Menus.class)
public class Application extends Controller {
    // …
}

Enfin, récupérer le menus de la valeur à partir de vos modèles, comme suit:

@(title: String)(content: Html)
<html>
  <head><title>@title</title></head>
  <body>
    <div>
      @for(menu <- Menus.current()) {
        <a href="#">@menu.name</a>
      }
    </div>
    @content
  </body>
</html>

Autres conseils

La façon dont je le fais, est de créer un nouveau contrôleur pour ma navigation/menu et l'appeler à partir de la vue

Ainsi, vous pouvez définir votre NavController:

object NavController extends Controller {

  private val navList = "Home" :: "About" :: "Contact" :: Nil

  def nav = views.html.nav(navList)

}

nav.scala.html

@(navLinks: Seq[String])

@for(nav <- navLinks) {
  <a href="#">@nav</a>
}

Puis, dans ma vue principale, je peux appeler que NavController:

@(title: String)(content: Html)
<!DOCTYPE html>
<html>
  <head>
    <title>@title</title>
  </head>
  <body>
     @NavController.nav
     @content
  </body>
</html>

Je soutiens stian de réponse.C'est un moyen très rapide pour obtenir des résultats.

Je viens de migré à partir de Java+Actuelle1.0 pour Java+Play2.0 et les modèles sont la partie la plus difficile jusqu'à présent, et le meilleur moyen que j'ai trouvé pour mettre en œuvre un modèle de base (pour le titre, tête etc..) est en utilisant le protocole Http.Contexte.

Il y a une très belle syntaxe que vous pouvez réaliser avec des balises.

views
  |
  \--- tags
         |
         \------context
                  |
                  \-----get.scala.html
                  \-----set.scala.html

où get.scala.html est :

@(key:String)
@{play.mvc.Http.Context.current().args.get(key)}

et set.scala.html est:

@(key:String,value:AnyRef)
@{play.mvc.Http.Context.current().args.put(key,value)}

signifie que vous pouvez écrire le code suivant dans n'importe quel modèle

@import tags._
@context.set("myKey","myValue")
@context.get("myKey")

Il est donc très lisible et agréable.

C'est la façon dont j'ai choisi d'aller.stian - de bons conseils.Prouve qu'il est important de faire défiler vers le bas pour voir toutes les réponses.:)

En passant HTML variables

Je n'ai pas encore appris comment passer Html variables.

@(titre:String,contenu:Html)

cependant, je sais comment les transmettre sous forme de bloc.

@(titre:String)(contenu:Html)

ainsi, vous pouvez remplacer set.scala.html avec

@(key:String)(value:AnyRef)
@{play.mvc.Http.Context.current().args.put(key,value)}

de cette façon, vous pouvez passer Html blocs comme

@context.set("head"){ 
     <meta description="something here"/> 
     @callSomeFunction(withParameter)
}

EDIT:Effet Secondaire Avec Mon "Jeu" De La Mise En Œuvre

Commune de cas d'utilisation il de l'héritage de modèle dans le Jeu.

Vous avez un base_template.html et puis vous avez page_template.html qui s'étend base_template.html.

base_template.html pourrait ressembler à quelque chose comme

<html> 
    <head>
        <title> @context.get("title")</title>
    </head>
    <body>
       @context.get("body")
    </body>
</html>

alors que le modèle de page pourrait ressembler à quelque chose comme

@context.set("body){
    some page common context here.. 
    @context.get("body")
}
@base_template()

et puis vous avez une page (permet de supposer login_page.html) qui ressemble à

@context.set("title"){login}
@context.set("body"){
    login stuff..
}

@page_template()

La chose importante à noter ici est que vous définissez "corps" à deux reprises.Une fois dans "login_page.html" et ensuite dans "page_template.html".

Il semble que cela déclenche un effet secondaire, aussi longtemps que vous le mettre en œuvre set.scala.html comme je l'ai suggéré ci-dessus.

@{play.mvc.Http.Context.current().put(key,value)}

comme la page afficher "connexion des choses..." deux fois parce que mettre renvoie la valeur qui apparaît le deuxième temps de mettre la même clé.(voir mettre de signature dans java docs).

scala permet une bien meilleure façon de modifier la carte

@{play.mvc.Http.Context.current().args(key)=value}

qui ne cause pas d'effets secondaires.

Si vous utilisez Java et je veux juste le plus simple possible, sans avoir à écrire un intercepteur et à l'aide de @Avec l'annotation, vous pouvez également accéder au contexte HTTP directement à partir du modèle.

E. g.si vous avez besoin d'une variable disponibles à partir d'un modèle, vous pouvez l'ajouter à la HTTP contexte avec:

Http.Context.current().args.put("menus", menus)

Vous pouvez ensuite y accéder à partir du modèle avec:

@Http.Context.current().args.get("menus").asInstanceOf[List<Menu>]

Évidemment, si vous avez de la litière de vos méthodes avec Http.Contexte.current().args.put ("",""), vous êtes mieux d'utiliser un intercepteur, mais pour les cas simples, il peut faire l'affaire.

De Stian de réponse, j'ai essayé une approche différente.Cela fonctionne pour moi.

DANS LE CODE JAVA

import play.mvc.Http.Context;
Context.current().args.put("isRegisterDone", isRegisterDone);

DANS LE MODÈLE HTML TÊTE

@import Http.Context
@isOk = @{ Option(Context.current().args.get("isOk")).getOrElse(false).asInstanceOf[Boolean] } 

ET DE LES UTILISER COMME

@if(isOk) {
   <div>OK</div>
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top