প্লে 2-এ সর্বত্র কীভাবে পরামিতিগুলি এড়ানো যায়?


125

প্লে 1 এ, আমি সাধারণত ক্রিয়ায় সমস্ত ডেটা পাই, এগুলি সরাসরি দর্শনগুলিতে ব্যবহার করি। যেহেতু আমাদের পরিষ্কারভাবে প্যারামিটারগুলি দেখার দরকার নেই, এটি খুব সহজ।

তবে প্লে 2-তে আমি দেখতে পেলাম যে দর্শনের শিরোনামে আমাদের সমস্ত প্যারামিটারগুলি (সহ request) ঘোষণা করতে হবে, ক্রিয়ায় সমস্ত ডেটা পেতে এবং সেগুলিকে দর্শনগুলিতে স্থান দেওয়া খুব বিরক্তিকর হবে।

উদাহরণস্বরূপ, যদি আমার প্রথম পৃষ্ঠায় ডাটাবেস থেকে লোড হওয়া মেনুগুলি প্রদর্শন করতে হয় তবে আমাকে এটিকে সংজ্ঞায়িত করতে হবে 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>

তারপরে আমাকে এটি প্রতিটি উপ পৃষ্ঠায় ঘোষণা করতে হবে:

@(menus: Seq[Menu])

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

তারপরে আমাকে প্রতিটি ক্রিয়াকলাপ দেখতে মেনুগুলি পেতে এবং এটি পাস করতে হবে:

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))
}

আপাতত এটি কেবলমাত্র একটি পরামিতি main.scala.html, সেখানে যদি অনেকগুলি থাকে?

সুতরাং শেষ অবধি, আমি প্রত্যেকে Menu.findAll()প্রত্যক্ষ দৃশ্যে সিদ্ধান্ত নিয়েছি :

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

আমি জানি না এটি ভাল বা প্রস্তাবিত কিনা, এর কি আরও ভাল সমাধান আছে?


সম্ভবত প্লে 2-এ লিফটের স্নিপেটের মতো কিছু যুক্ত করা উচিত
ফ্রিউইন্ড

উত্তর:


229

আমার মতে, টেমপ্লেটগুলি স্থিতিবদ্ধভাবে টাইপ করা প্রকৃতপক্ষে একটি ভাল জিনিস: আপনার গ্যারান্টিযুক্ত যে আপনার টেম্পলেটটি কল করলে এটি সংকলন করে ব্যর্থ হবে না।

যাইহোক, এটি প্রকৃতপক্ষে কলিং সাইটগুলিতে কিছু বয়লারপ্লেট যুক্ত করে। তবে আপনি এটি হ্রাস করতে পারেন (স্ট্যাটিক টাইপিং সুবিধাগুলি না হারিয়ে)।

স্কালায় আমি এটি অর্জনের দুটি উপায় দেখতে পাচ্ছি: ক্রিয়া সংমিশ্রণের মাধ্যমে বা অন্তর্নিহিত পরামিতি ব্যবহার করে। জাভাতে আমি এটি ব্যবহার করার পরামর্শ দিইHttp.Context.args মানচিত্রটি দরকারী মানগুলি সংরক্ষণ করতে এবং টেম্পলেটগুলির পরামিতি হিসাবে স্পষ্টভাবে পাস না করে টেমপ্লেটগুলি থেকে পুনরুদ্ধার করার ।

অন্তর্নিহিত পরামিতি ব্যবহার করে

menusআপনার main.scala.htmlটেম্পলেট প্যারামিটারের শেষে প্যারামিটারটি রাখুন এবং এটিকে "অন্তর্নিহিত" হিসাবে চিহ্নিত করুন:

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

এখন আপনার যদি এই প্রধান টেম্পলেটটিকে কল করে টেম্পলেট থাকে, আপনি যদি এই টেমপ্লেটগুলিতেও অন্তর্নিহিত পরামিতি হিসাবে ঘোষিত menusহয়ে থাকেন তবে আপনি প্যারামিটারটি mainস্কেল সংকলক দ্বারা স্পষ্টভাবে আপনার জন্য টেম্পলেটটিতে পৌঁছে দিতে পারেন:

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

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

তবে আপনি যদি এটিকে আপনার নিয়ামকের কাছ থেকে সুস্পষ্টভাবে প্রেরণ করতে চান তবে আপনাকে এটিকে একটি অন্তর্নিহিত মান হিসাবে সরবরাহ করতে হবে, যেখানে আপনি টেমপ্লেটটি কল করেন সেখান থেকে পাওয়া যায়। উদাহরণস্বরূপ, আপনি আপনার নিয়ামকটিতে নিম্নলিখিত পদ্ধতিটি ঘোষণা করতে পারেন:

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

তারপরে আপনার ক্রিয়াকলাপে আপনি কেবল নিম্নলিখিতগুলি লিখতে সক্ষম হবেন:

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

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

আপনি এই ব্লগ পোস্ট এবং এই কোড নমুনায় এই পদ্ধতির সম্পর্কে আরও তথ্য সন্ধান করতে পারেন ।

আপডেট : এই নিদর্শনটি প্রদর্শন করে একটি দুর্দান্ত ব্লগ পোস্টও এখানে লেখা হয়েছে

ক্রিয়া রচনা ব্যবহার করে

প্রকৃতপক্ষে, প্রায়শই RequestHeaderটেমপ্লেটগুলিতে মান পাস করার জন্য দরকারী (উদাহরণস্বরূপ এই নমুনা )। এটি আপনার নিয়ামক কোডটিতে এত বেশি বয়লারপ্লেট যুক্ত করে না কারণ আপনি সহজেই একটি অন্তর্ভুক্ত অনুরোধের মান গ্রহণ করে ক্রিয়া লিখতে পারেন:

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

সুতরাং, যেহেতু টেমপ্লেটগুলি প্রায়শই কমপক্ষে এই অন্তর্নিহিত প্যারামিটারটি গ্রহণ করে, আপনি এটিকে আপনার মেনুগুলি সমেত আরও সমৃদ্ধ মানের সাথে প্রতিস্থাপন করতে পারেন। আপনি প্লে 2 এর ক্রিয়া সংমিশ্রণ প্রক্রিয়াটি ব্যবহার করে এটি করতে পারেন ।

এটি করার জন্য আপনাকে Contextঅন্তর্নিহিত অনুরোধটি মোড়ানো, আপনার শ্রেণি সংজ্ঞায়িত করতে হবে :

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

তারপরে আপনি নিম্নলিখিত ActionWithMenuপদ্ধতিটি নির্ধারণ করতে পারেন :

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

যা এর মতো ব্যবহার করা যেতে পারে:

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

এবং আপনি আপনার টেমপ্লেটগুলিতে একটি অন্তর্নিহিত প্যারামিটার হিসাবে প্রসঙ্গটি নিতে পারেন। যেমন 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>

ক্রিয়া সংমিশ্রণটি ব্যবহার করা আপনাকে আপনার টেমপ্লেটগুলির জন্য প্রয়োজনীয় সমস্ত অন্তর্নিহিত মানগুলিকে একক মান হিসাবে সংযুক্ত করতে দেয় তবে অন্যদিকে আপনি কিছুটা নমনীয়তা হারাতে পারেন ...

Http.Context (জাভা) ব্যবহার করে

যেহেতু জাভাতে স্কালার জড়িত প্রক্রিয়া বা অনুরূপ নেই, আপনি যদি স্পষ্টভাবে টেম্পলেটগুলির পরামিতিগুলি এড়াতে চান তবে একটি সম্ভাব্য উপায় হ'ল এটি Http.Contextকেবলমাত্র একটি অনুরোধের সময়কালে অবজায় থাকা অবজেক্টে সংরক্ষণ করা। এই অবজেক্টে argsটাইপের মান রয়েছে Map<String, Object>

সুতরাং, আপনি ডকুমেন্টেশনে বর্ণিত হিসাবে একটি ইন্টারসেপ্টার লিখে শুরু করতে পারেন :

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");
    }
}

স্ট্যাটিক পদ্ধতিটি বর্তমান প্রসঙ্গে মেনুগুলি পুনরুদ্ধার করার জন্য কেবলমাত্র একটি সংক্ষিপ্তকরণ। তারপরে Menusঅ্যাকশন ইন্টারসেপ্টারের সাথে মিশ্রিত হওয়ার জন্য আপনার নিয়ামককে টিকিয়ে দিন :

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

অবশেষে, menusআপনার টেমপ্লেটগুলি থেকে মানটি পুনরুদ্ধার করুন :

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

আপনি মেনু পরিবর্তে মেনু মানে? "অন্তর্ভুক্ত ভাল মেনু: সেক [মেনু] = মেনু.ফাইন্ডআল"
বেন ম্যাকক্যান

1
এছাড়াও, যেহেতু আমার প্রকল্পটি এখনই কেবল জাভাতে লিখিত হয়েছে, তাই কি অ্যাকশন রচনা রুটে যাওয়া এবং স্ক্যালায় কেবল আমার ইন্টারসেপ্টর লেখা সম্ভব ছিল, তবে আমার সমস্ত ক্রিয়া জাভাতে রেখে দেওয়া উচিত?
বেন ম্যাকক্যান

"মেনু" বা "মেনু", এটি কোনও বিষয় নয় :), যা গুরুত্বপূর্ণ তা ধরণের: সেক [মেনু]। আমি আমার উত্তর সম্পাদনা করেছি এবং এই সমস্যাটি পরিচালনা করতে একটি জাভা প্যাটার্ন যুক্ত করেছি।
জুলিয়ান রিচার্ড-ফয়ে 23

3
সর্বশেষ কোড ব্লকে, আপনি কল করেছেন @for(menu <- Menus.current()) {তবে Menusকখনও সংজ্ঞায়িত হয় না (আপনি মেনু রেখেছেন (লোয়ার কেস) ctx.args.put("menus", Menu.find.all());))। কোন কারণ আছে? Play এর মতো যা এটিকে বড় হাতের বা কিছুতে রূপান্তরিত করে?
সিরিল এন।

1
@ cx42net এখানে একটি Menusশ্রেণি সংজ্ঞায়িত হয়েছে (জাভা ইন্টারসেপ্টর)। @ এডিস হ্যাঁ তবে আপনি এগুলিকে অন্য জায়গায় এমনকি ক্যাশেও সংরক্ষণ করতে পারবেন।
জুলিয়ান রিচার্ড-ফয়ে

19

আমি যেভাবে এটি করি তা হ'ল আমার নেভিগেশন / মেনুটির জন্য একটি নতুন নিয়ামক তৈরি করা এবং দেখুন থেকে এটি কল করা

সুতরাং আপনি আপনার সংজ্ঞা দিতে পারেন 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>
}

তারপরে আমার মূল দৃষ্টিতে আমি এটিকে কল করতে পারি NavController:

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

জাভায় নাভিকন্ট্রোলারকে কেমন দেখাচ্ছে? এইচটিএমএল ফিরিয়ে আনার জন্য কন্ট্রোলার করার কোনও উপায় আমি খুঁজে পাচ্ছি না।
মিকা

এবং তাই এটি ঘটে যায় যে আপনি কিছু সহায়তা চেয়ে জিজ্ঞাসা করার পরে সমাধানটি ঠিক খুঁজে পান :) নিয়ন্ত্রক পদ্ধতিটি দেখতে এটির মতো হওয়া উচিত। পাবলিক স্ট্যাটিক play.api.templates.Html সাইডবার () {রিটার্ন (play.api.templates.Html) সাইডবার.রেেন্ডার ("বার্তা"); }
মিকা

1
কোনও দৃশ্য থেকে নিয়ামককে কল করা কি এটি একটি ভাল অনুশীলন? আমি স্টিকারার হতে চাই না, তাই আসল কৌতূহল জিজ্ঞাসা করুন।
0fnt

এছাড়াও, আপনি এই ভাবে অনুরোধ উপর ভিত্তি করে কাপড় ব্যবহার করতে পারবেন না, তুমি কি .., ব্যবহারকারী উদাহরণ নির্দিষ্ট সেটিংস .. জন্য
0fnt

14

আমি স্ট্যান এর উত্তর সমর্থন করি। এটি ফলাফল পাওয়ার জন্য খুব দ্রুত উপায়।

আমি কেবল জাভা + প্লে ১.০ থেকে জাভা + প্লে ২.০ এ স্থানান্তরিত করেছি এবং টেমপ্লেটগুলি এখন পর্যন্ত সবচেয়ে শক্ত অংশ এবং আমি বেস টেমপ্লেট (শিরোনাম, শিরোনাম ইত্যাদির জন্য) কার্যকর করার সবচেয়ে ভাল উপায় হ'ল এইচটিপি ব্যবহার করে is .Context।

ট্যাগ সহ আপনি অর্জন করতে পারেন এমন একটি খুব সুন্দর বাক্য গঠন রয়েছে।

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

get.scala.html হ'ল:

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

এবং set.scala.html হ'ল:

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

এর অর্থ আপনি যে কোনও টেম্পলেটটিতে নিম্নলিখিত লিখতে পারেন

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

সুতরাং এটি খুব পঠনযোগ্য এবং চমৎকার।

এই পথেই আমি যেতে বেছে নিয়েছি। স্থির - ভাল পরামর্শ। সমস্ত উত্তর দেখতে নীচে স্ক্রোল করা জরুরী তা প্রমাণ করে। :)

এইচটিএমএল ভেরিয়েবলগুলি পাস করা

এইচটিএমএল ভেরিয়েবলগুলি কীভাবে পাস করবেন তা আমি এখনও খুঁজে পাইনি।

@ (শিরোনাম: STRING টি, বিষয়বস্তু: এইচটিএমএল)

তবে, আমি জানি কীভাবে তাদের ব্লক হিসাবে পাস করতে হয়।

@ (শিরোনাম: স্ট্রিং) (বিষয়বস্তু: এইচটিএমএল)

সুতরাং আপনি এর সাথে set.scala.html প্রতিস্থাপন করতে পারেন

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

এভাবে আপনি এইচটিএমএল ব্লকগুলি পাস করতে পারেন

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

সম্পাদনা: আমার "সেট" বাস্তবায়নের সাথে পার্শ্ব-প্রতিক্রিয়া

একটি সাধারণ ব্যবহারের ক্ষেত্রে এটি প্লেতে উত্তরাধিকারের টেম্পলেট করে।

আপনার একটি base_template.html আছে এবং তারপরে আপনার পেজ_টেম্পলেট। Html আছে যা বেস_টেম্পলেট। Html প্রসারিত করে।

base_template.html এর মতো দেখতে কিছুটা লাগবে

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

পৃষ্ঠার টেমপ্লেটটি দেখতে এমন কিছু লাগবে

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

এবং তারপরে আপনার মতো একটি পৃষ্ঠা রয়েছে (যা ধরে রাখুন লগইন_পৃষ্ঠা html)

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

@page_template()

এখানে লক্ষণীয় গুরুত্বপূর্ণ বিষয়টি হ'ল আপনি দু'বার "বডি" সেট করেছেন। একবার "login_page.html" এবং তারপরে "page_template.html" এ।

দেখে মনে হচ্ছে এটি যতক্ষণ না আপনি set.scala.html প্রয়োগ করেছেন যতক্ষণ না আমি উপরে প্রস্তাব করেছি this

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

পৃষ্ঠাটি দু'বার "লগইন স্টাফ ..." দেখায় কারণ দ্বিতীয় বার যখন একই কী রাখি তখন যে মানটি পপ করে দেয় তা দেয়। (জাভা ডক্সে স্বাক্ষর রাখুন দেখুন)।

স্কেল মানচিত্রটি সংশোধন করার আরও ভাল উপায় সরবরাহ করে

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

যা এই পার্শ্ব প্রতিক্রিয়া সৃষ্টি করে না।


স্কেলা নিয়ন্ত্রকটিতে, আমি চেষ্টা করে দেখি যে play.mvc.Htt.Context.current () এ কোনও পুট পদ্ধতি নেই। আমি কিছু অনুপস্থিত করছি?
0fnt

argsবর্তমানের প্রসঙ্গটি বর্তমানের পরে রাখার চেষ্টা করুন ।
লোক মোগরবী

13

আপনি যদি জাভা ব্যবহার করে থাকেন এবং কোনও ইন্টারসেপ্টর না লিখে এবং @ টিকাটি ব্যবহার না করে কেবলমাত্র সহজতম উপায়টি চান, আপনি সরাসরি টেমপ্লেট থেকে এইচটিটিপি প্রসঙ্গেও অ্যাক্সেস করতে পারবেন।

যেমন আপনার যদি কোনও টেম্পলেট থেকে কোনও ভেরিয়েবলের প্রয়োজন হয় তবে আপনি এটিকে HTTP প্রসঙ্গে যুক্ত করতে পারেন:

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

এরপরে আপনি এটি দিয়ে টেমপ্লেট থেকে অ্যাক্সেস করতে পারবেন:

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

স্পষ্টতই যদি আপনি আপনার পদ্ধতিগুলি HTTP.Context.c اوس ()। আরগস.পুট ("", "") দিয়ে জঞ্জাল করেন তবে আপনি একটি ইন্টারসেপ্টর ব্যবহার করা ভাল, তবে সাধারণ ক্ষেত্রে এটি কৌশলটি করতে পারে।


হাই স্ট্যান, দয়া করে আমার উত্তরে আমার শেষ সম্পাদনাটি একবার দেখুন। আমি সবেমাত্র জানতে পেরেছি যে আপনি যদি একই কী দিয়ে দু'বার আর্গগুলিতে "পুট" ব্যবহার করেন তবে আপনি একটি বাজে পার্শ্ব-প্রতিক্রিয়া পাবেন। পরিবর্তে আপনার ... আরগস (কী) = মান ব্যবহার করা উচিত।
লোক মোগ্রাবি

6

স্টিয়ান এর উত্তর থেকে, আমি একটি ভিন্ন পদ্ধতির চেষ্টা করেছি। এটি আমার পক্ষে কাজ করে।

জাভা কোডে

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

এইচটিএমএল নমুনা হেড

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

এবং পছন্দ মত ব্যবহার করুন

@if(isOk) {
   <div>OK</div>
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.