Play 2.x:如何使用通用按钮进行AJAX请求

60

我之前已经成功地使用过AJAX请求,但是我一直需要使用一个表单,然后在提交结束时执行return false以防止页面刷新。

最近我还将我的JavaScript代码移到了一个独立的文件中,这导致我的@命令失败了。因此,我不知道如何将我的URL设置为我的路由?

HTML:

<button id="saveAsDefaultButton">Save as default</button>

Play框架Java代码:

public static Result saveDefaultPhoneForUser(String handset) {
    User currentUser = User.findByName(session("name"));
    currentUser.lastControlledHandset = theHandset;
    currentUser.save();
    return ok();
}

路由:

POST    /                           controllers.Application.saveDefaultPhoneForUser(handset : String)

JavaScript:

$('#saveAsDefaultButton').click(function(evt) {
        $('#errors').hide();
        $.ajax({
            type : 'POST',
            url : "controllers.Application.saveDefaultPhoneForUser",
            data : $('#controlledPhone option:selected').text(),
            dataType : "text",
            success : function(data) {
                //setError('Call succedded');
                //$('#test1').attr("src", data)
            },
            error : function(data) {
                setError('Make call failed');
            }
        });
        return false;
    });

我相信有一种方法可以做到这一点,但我找不到任何东西。

5个回答

123

对于这个任务,你应该使用javascriptRoutes,因为它可以根据你的routes.conf生成正确的JS路径。你可以在Zentask的示例中找到用法示例。

无论如何,现在你可以通过更改url来修复你的AJAX调用。

url : '@routes.Application.saveDefaultPhoneForUser()',

这种方式要求将整个JS代码放在模板中,这是错误的。可以或者应该将其移动到单独的JS文件中,为此您需要使用javascriptRoutes。
更多内容...
javascriptRoutes尚未在官方文档中描述,但以下是逐步介绍。尽管描述看起来很复杂,但实际上使用这种方式带来了很多好处。
1. 创建常规路由
首先,您需要在conf/routes文件中创建常规路由:
GET     /item/:id     controllers.Application.getItem(id: Long)
POST    /item/new     controllers.Application.newItem
PUT     /item/:id     controllers.Application.updateItem(id: Long)

当然,您需要在应用程序控制器中创建至少这三个操作:

  • getItem(Long id){ ... }
  • newItem() { ... }
  • updateItem(Long id) { ... }

2. 创建一个将通用路由转换为JS的操作

  • 将其放置在某个位置,例如您的应用控制器中
  • 我们称其为javascriptRoutes()

在该操作中,您将指向conf/routes文件中的现有路由。

public static Result javascriptRoutes() {
    response().setContentType("text/javascript");
    return ok(
        Routes.javascriptRouter("myJsRoutes",
            routes.javascript.Application.getItem(),
            routes.javascript.Application.newItem(),
            routes.javascript.Application.updateItem(),
            //inside somepackage
            controllers.somepackage.routes.javascript.Application.updateItem()
        )
    );
}

注意:不要在括号中设置任何参数。

3. 创建一个javascriptRoutes动作的路由,并将其包含在您的模板中

路由:conf/routes

GET     /javascriptRoutes     controllers.Application.javascriptRoutes

查看 /views/main.scala.html 文件中的 <head> 部分。

<script type="text/javascript" src='@routes.Application.javascriptRoutes()'></script>

4. 在需要的时候使用javascriptRoutes

从现在起,您可以在JS中使用路由来获取正确的路径而无需指定urltype。例如,不需要这样做:

 $('.getAjaxForThisContainer').click(function(e) {
    var idToGet = $("#someField").val();
    $.ajax({
        type : 'GET',
        url : '@routes.Application.getItem()',
        data : {
            id: idToGet
        },
        success : function(data) {
            // ... some code on success
        }
    });
    return false;
});

您可以使用简化版本(myJsRoutes 来自点2):
myJsRoutes.controllers.Application.getItem(idToGet).ajax({
    success : function(data) { ... some code ... }
});

或者
myJsRoutes.controllers.Application.newItem().ajax({
    success : function(data) { ... some code ... }
});
  • 您不需要指定type: "POST"——JS路由将根据conf/routes规则使用正确的方法
  • 您可以使用纯JS中的类似于routes的语法,将记录的id(或其他参数)设置为GETPUT(或其他方法)
  • 如果您的路由规则包含所有必需的参数,则可以真正将JS最小化:

对于路由:

GET   /some/:a/:b/:c    controllers.Application.getABC(a: String, b: Integer, c: String)

JS:

myJsRoutes.controllers.Application.getABC("a", 1, "b" ).ajax({});

2
非常感谢你,马库斯。我确实看了一下禅任务的例子,但是由于我刚刚重新开始进行Web开发,所以需要恢复我的HTML、CSS和JavaScript知识。当这个例子用CoffeeScript完成时,它让我有些沮丧。而且当我尝试它时,我无法让它工作。 - user1434177
2
Marcus,我有一个快速的问题。如果在我的操作中进行了一些服务器端验证,然后返回badRequest("Incorrect data sent"); 我还在成功之后的javascript中加入了错误捕获:error : function(data) { setError('Make call failed'); }。我该如何访问我传递的字符串?当我将错误消息放入接收器中时,我得到的结果是'object [Object]'。或者你知道我可以调试/检查这些信息的方法吗? - user1434177
2
JavaScript路由在官方文档中的链接:http://www.playframework.com/documentation/2.1.1/JavaGuide6 - ChuanRocks
5
并不是每个人都喜欢使用CoffeeScript,这正是官方文档想要表达的内容。 - ses
2
@biesior 我没有理解答案中的一件事,那就是如果使用 url : '@routes.Application.getItem()' 的 ajax 调用在理论上是否可行。我在这里尝试了一下,但是 Play 报错说缺少参数。我之所以问这个问题,是因为我想以类似于 这里 的方式将其与 jqGrid 结合起来。 - Thomas

9
我喜欢“老好”的简单方法:
1. 在页面中,使用 JQuery, 2. 在某个事件处理程序内部,
 $.get('/giveme', {'arg': value}, function(data) {

                                    window.alert(data);

                                  }
 );

在服务器/游玩方面:
2.1 路由: GET /giveme controllers.Application.giveme(arg) 2.2 Scala动作:
object Application extends Controller { 

      def giveme(arg:String) = Action {
        Ok(Json.toJson("hello," + arg ))
      }

    }

我可以在function(data)中使用多个参数,例如function(data, data1) - Hitesh Vaghani

7

需要注意的是,在调用时...

Routes.javascriptRouter("myJsRoutes",

Routes是从play.Routes导入的,而不是play.api.Routes。

当我实现这段代码时遇到了一个错误,因为我以为它来自api(显然我错了)。除此之外,一切都很棒~!


2

有一个更简单的解决方案,使用嵌入式路由器生成Javascript路由器。您可以使用@javascriptRouter辅助指令生成Javascript路由器,将以下代码放置在您的html页面head标签内(可能在主装饰模板内)。

<head>
    <title>Saeed Title</title>
    <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
    <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
    <script src="@routes.Assets.at("javascripts/jquery/v1.12.4/jquery.min.js")" type="text/javascript"></script>
    @helper.javascriptRouter("jsRoutes")(
        routes.javascript.MyController.getById,
        routes.javascript.MyController.getByName
    )
</head>

不用担心语法错误(在Intellij中),并且不要在您的操作名称后面使用括号。 现在,在您的ajax调用代码中,您可以使用jsRoutes.controllers.MyController.getById(id)

$.ajax(jsRoutes.controllers.MyController.getById(id))
   .done( /*...*/ )
   .fail( /*...*/ );

或者使用jsRoutes.controllers.MyController.getById(id).url来获取URL。 更多信息


1
Marcus的回答非常好,所以其他遇到这个问题的人应该能够使用它。
不过我在尝试让它工作时遇到了一个问题,花了我一点时间才解决。当我进行ajax请求时,它会路由到错误的方法。
这是因为在我的路由文件中有以下内容:
POST    /                           controllers.Application.makeCall()
POST    /                           controllers.Application.saveDefaultPhoneForUser(handset : String)

当具有相同位置“/”的两个POST方法时,似乎总是会进行调用。因此,对于任何人来说,只是一个提示,不要这样做,否则它将无法正常工作。

我只需要将其更改为:

POST    /                           controllers.Application.makeCall()
POST    /saveDefaultPhoneForUser    controllers.Application.saveDefaultPhoneForUser(handset : String)

希望这能对某人有所帮助。


4
如果“routes”文件包含两个具有相同方法和路径的规则,那么只会使用第一个规则。这是正常的情况。 - biesior

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接