Play 2.x:如何使用普通按钮发出 AJAX 请求

Posted

技术标签:

【中文标题】Play 2.x:如何使用普通按钮发出 AJAX 请求【英文标题】:Play 2.x: How to make an AJAX request with a common button 【发布时间】:2012-06-23 09:16:49 【问题描述】:

所以我之前已经成功地让 AJAX 请求工作,但我总是不得不使用一个表单,然后在提交结束时返回 false,这样它就不会刷新页面。

我最近也将我的 javascript 移动到一个单独的文件中,这导致我的 @ 命令失败。因此,我不知道如何将我的 URL 设置为我的路由?

html

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

Playframework 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;
    );

我确信有办法做到这一点,但我只是没有运气找到任何东西。

【问题讨论】:

【参考方案1】:

对于这项工作,您应该使用javascriptRoutes,因为它会根据您的 routes.conf 生成正确的 JS 路径。您可以在 Zentask sample 中找到使用示例

无论如何,现在您可以通过将 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)

当然,你至少需要在Application控制器中创建这三个动作:

getItem(Long id) ... newItem() ... updateItem(Long id) ...

2。创建一个将公共路由转换为 JS 的操作

把它放在某个地方,即。在您的 Application 控制器中 我们就叫它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

&lt;head&gt; 中查看/views/main.scala.html 的一部分

<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-like语法将记录(或其他参数)的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();

【讨论】:

非常感谢马库斯。我确实看过 zen 任务示例,但由于我刚刚回到 web 开发,所以刷新了我的 html、css、javascript 知识。当那个例子用咖啡脚本完成时,它让我有点反感。当我尝试它时,我无法让它工作。 如果在我的操作中我做了一些服务器端验证然后返回 badRequest("Incorrect data sent");成功后,我还在我的 javascript 中添加了错误捕获:error : function(data) setError('Make call failed');我如何访问我传递的字符串。当我将错误消息放入接收中时,我得到结果“对象 [对象]”。或者您知道我可以调试/检查这些信息的方法吗? 官方文档中的javascript路由:playframework.com/documentation/2.1.1/JavaGuide6 不是每个人都愿意使用 CoffeScript.. 这就是官方文档的内容。 @biesior 我从答案中不明白的一件事是,使用url : '@routes.Application.getItem()', 的ajax 调用理论上是否应该有效。我在这里尝试过,但没有,play 指责该论点缺失。我问的原因是因为我正在考虑以类似于here 的方式将它与 jqGrid 结合起来【参考方案2】:

我喜欢“老好”简单的方式:

1在页面中,用JQuery,

在一些偶数处理程序中

 $.get('/giveme', 'arg': value, function(data) 

                                    window.alert(data);

                                  
 );

2在服务器/播放端

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)【参考方案3】:

打电话时要注意的事情……

Routes.javascriptRouter("myJsRoutes",

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

我在实现这段代码时出错,因为我认为它来自 api(显然我错了)。 除此之外,一切都很好~!!

【讨论】:

【参考方案4】:

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

<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 获取网址。 more information.

【讨论】:

【参考方案5】:

Marcus 的回答非常好,所以遇到这个问题的其他人应该可以使用它。

我确实遇到了一个问题,但在尝试让它工作时,我花了一点时间才开始工作。当我发出我的 ajax 请求时,它路由到了错误的方法。

这是因为在我的路线文件中,我有以下内容:

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

通过具有相同位置 / 的两个 post 方法。它似乎总是去打电话。所以只是给任何人的提示,不要这样做,否则它不会起作用。

我只需要将其更改为:

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

希望这对某人有所帮助。

【讨论】:

这很正常,如果routes文件中包含两条规则,方法和路径相同,只会使用第一个。

以上是关于Play 2.x:如何使用普通按钮发出 AJAX 请求的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Play 2.2.x 的 dist 任务中禁用 ScalaDoc 生成(使用 project/build.scala)?

如何在构建定义中更改 Play 2.3.x 中的默认端口 9000?

在发出初始ajax请求后,Ajax请求无法发送 - 试图找出导致冲突的原因

循环形式的 AJAX 请求

Selenium 在按钮单击后获取 http 请求 ajax url

向 Flask 应用程序发出 AJAX 请求