How to pass a variable that is an array in JavaScript to a controller that takes List [String] as a parameter?

Setup:

Using Play! framework v 2.0.4

Controller:

def javascriptRoutes = Action { implicit request => Ok( Routes.javascriptRouter("jsRoutes")( routes.javascript.Admin.approve ) ).as("text/javascript") } def approve(user: List[String]) = SecureAction('admin) { implicit ctx => Logger.debug("Admin.approve: " + user.foldLeft("")(_ + "::" + _)) user map { u => User.approve(u) } Ok(Json.toJson(user)) } 

View:

  function get_selected() { return $.makeArray($(".user-selector").map(function (ind, user){ if(user.checked) return user.name; })); } $("#button-approve").click(function(){ jsRoutes.controllers.Admin.approve(get_selected()).ajax({ success: function(data, status) { console.log("Users activated: " + data) for(i = 0; i < data.length; i++) { id = "#" + data[i]; $(id + " > td > i.approved").removeClass("icon-flag").addClass("icon-check"); } $(":checked").attr("checked", false); } }); }); 

Routes:

 PUT /admin/users controllers.Admin.approve(user: List[String]) GET /admin/jsRoutes controllers.Admin.javascriptRoutes 

I also used the code mentioned in this question to allow List[String] binding as a parameter.

Problem

Parameters are passed in the request specified as follows:

 PUT /admin/users?user=506b5d70e4b00eb6adcb26a7%2C506b6271e4b00eb6adcb26a8 

The encoded character %2C is a comma. The controller interprets it as a single line, because the debug line from the above code looks like this:

 [debug] application - Admin.approve: ::506b5d70e4b00eb6adcb26a7,506b6271e4b00eb6adcb26a8 

(the default use of List.toString was misleading why I used the foldLeft trick).

So

How to transfer the list of flags to the selected users on the controller so that it is interpreted as a list of lines, rather than a list of one line?

+1
source share
1 answer

Ok The problem was the old QueryBinders implementation, which lacked a piece of JavaScript. The correct version is:

 package models import play.api.mvc.{JavascriptLitteral, QueryStringBindable} //TODO: remove when updating to 2.1 object QueryBinders { /** * QueryString binder for List */ implicit def bindableList[T: QueryStringBindable] = new QueryStringBindable[List[T]] { def bind(key: String, params: Map[String, Seq[String]]) = Some(Right(bindList[T](key, params))) def unbind(key: String, values: List[T]) = unbindList(key, values) /////////////// The missing part here...: override def javascriptUnbind = javascriptUnbindList(implicitly[QueryStringBindable[T]].javascriptUnbind) } private def bindList[T: QueryStringBindable](key: String, params: Map[String, Seq[String]]): List[T] = { for { values <- params.get(key).toList rawValue <- values bound <- implicitly[QueryStringBindable[T]].bind(key, Map(key -> Seq(rawValue))) value <- bound.right.toOption } yield value } private def unbindList[T: QueryStringBindable](key: String, values: Iterable[T]): String = { (for (value <- values) yield { implicitly[QueryStringBindable[T]].unbind(key, value) }).mkString("&") } /////////// ...and here private def javascriptUnbindList(jsUnbindT: String) = "function(k,vs){var l=vs&&vs.length,r=[],i=0;for(;i<l;i++){r[i]=(" + jsUnbindT + ")(k,vs[i])}return r.join('&')}" /** * Convert a Scala List[T] to Javascript array */ implicit def litteralOption[T](implicit jsl: JavascriptLitteral[T]) = new JavascriptLitteral[List[T]] { def to(value: List[T]) = "[" + value.map { v => jsl.to(v)+"," } +"]" } } 

Now the request looks like this:

 PUT /admin/users?user=506b5d70e4b00eb6adcb26a7&user=506b6271e4b00eb6adcb26a8 

And finally, everything works.

Final Note:

On Play! Framework 2.1+ it should work without adding code to the sources of the project. Actually the code is borrowed as from Play20/framework/src/play/src/main/scala/play/api/mvc/Binders.scala

0
source

Source: https://habr.com/ru/post/923194/


All Articles