由 Tapestry 5.4 客户端处理的 Javascript ajax post

问题描述 投票:0回答:1

我正在尝试让 jquery 可排序以在 Tapestry 5.4 应用程序中工作。实际的可排序表正在工作,但是在移动一行后,我无法获取事件来进行客户端调用以实际更新数据库。

任何人都可以帮助确定我可能没有正确使用 $.ajax({}) 来阻止它为 Tapestry 常规页面创建要处理的事件吗? console.log 行正在记录,位置数组包含在客户端完成数据库更新所需的数据。

$(document).ready(function () {
    $('table tbody').sortable({
        update: function (event, ui) {
            $(this).children().each(function (index) {
                if ($(this).attr('data-position') != (index+1)) {
                    $(this).attr('data-position', (index+1)).addClass('updated');
                }
                console.log("tbody update function")
            });

            saveNewPositions();
        }
    });
});

function saveNewPositions() {
    var positions = [];
    $('.updated').each(function () {
        positions.push([$(this).attr('data-index'), $(this).attr('data-position')]);
        $(this).removeClass('updated');

    });
    console.log("saveNewPositions of table update" + positions)

    $.ajax({
        url: "configjquery/tableUpdate",
        method: 'POST',
        dataType: 'text',
        data: {
            update: 1,
            positions: positions
        }, success: function (response) {
            console.log(response);
        }
    });
}

我针对该 URL 尝试了不同的策略,但均无济于事。当我尝试执行以下操作来创建 Tapestry 事件链接并将其用作 ajax 函数中的 URL 时

在 Tapestry Groovy 页面中

String getActionUrl() {
        return resources.createEventLink("tableUpdate").toURI()
    }

Javascript 尝试从 Tapestry 页面引用方法:

function saveNewPositions() {
    var positions = [];
    $('.updated').each(function () {
        positions.push([$(this).attr('data-index'), $(this).attr('data-position')]);
        $(this).removeClass('updated');

    });
    console.log("saveNewPositions of table update" + positions)

    $.ajax({
        url: "${actionUrl}",
        method: 'POST',
        dataType: 'text',
        data: {
            update: 1,
            positions: positions
        }, success: function (response) {
            console.log(response);
        }
    });
}

它导致控制台记录错误:

POST http://localhost:8080/cndc/${actionUrl}
Tapestry 页面中的 actionUrl 未使用 getter 进行翻译。

我尝试在 $(document).ready(function () 中为 actionUrl 创建一个 var

var eventURL = ${actionUrl}
然后将该变量传递给 saveNewPositions(eventURL) 函数,但这也导致 var 没有翻译 actionUrl。

javascript ajax tapestry
1个回答
0
投票

替换 ${...} 表达式仅适用于模板文件

替换

${...}
表达式仅适用于模板 (tml) 文件。也就是说,如果您的
${actionUrl}
直接包含在模板文件中,它将被页面类的属性值替换。因此,将 JavaScript 放入模板文件中的
<script>
块中就可以解决问题,可惜的是,代价是各种缺点,例如(缺乏)可重用性、异步加载等。

让 Tapestry 负责加载 JavaScript

这是解决该问题的 Tapestry 方法。 Tapestry 5.4+ 附带 RequireJS,一个用于异步加载 JavaScript 模块的框架。您可以在模块中组织 JavaScript 逻辑。定义模块通常就像调用 RequireJS 的

define()
函数一样简单。您还可以通过为 Tapestry 的
ModuleManager
服务做出贡献,将整个库添加为模块。定义模块后,您可以让页面类负责渲染指示客户端加载模块的代码。

sortable()
函数由 jQuery UI 提供,与 jQuery 不同,它不随 Tapestry 一起提供,因此需要作为模块添加。一种方法如下。

  1. 下载 jQuery UI 并将其保存到
    src/main/resources/META-INF/assets/jquery-ui/
  2. 在您的
    AppModule
    中,将 jQuery UI 定义为模块:
@Contribute(ModuleManager.class)
public static void addModules(MappedConfiguration<String, JavaScriptModuleConfiguration> conf,
    @Path("classpath:META-INF/assets/jquery-ui/jquery-ui.min.js") Resource jqueryui) {
  
  conf.add("jqueryui", new JavaScriptModuleConfiguration(jqueryui));

}

现在 jQuery UI 可用为

jqueryui
,您现在可以继续并在您自己的模块的定义中引用它。其初步定义在
src/main/resources/META-INF/modules/MyItemSorting.js
中如下:

define(['jquery', 'jqueryui'], function($, qui) {
    
    // The clientId identifies the DOM element to which the sortable
    // widget will be applied. It will be passed by the Tapestry page
    // class.
    return function(clientId) {
        
        $("#" + clientId).sortable(
          // ..
        );
        
    }
});

现在定义了模块的基本版本,您可以指示页面类呈现负责加载模块的客户端代码。

@InjectComponent
Any itemContainer; // Expects <t:any element="div" t:id="itemContainer"> in the template file.

@Environmental
JavaScriptSupport jsSupport;

@AfterRenderTemplate
void requireModules() {
    jsSupport.require("MyItemSorting").with(itemContainer.getClientId());
}

了解了页面类和模块的连接方式后,就可以完成模块定义了。请注意,此处使用了另一个模块

t5/core/ajax
(Tapestry 内置)。

define(['jquery', 'jqueryui', 't5/core/ajax'], function($, qui, ajax) {
    
    return function(clientId) {
    
        $("#" + clientId).sortable({
    
            update: function(event, ui) {
                // (1) Build an array of item identifiers (obtained
                // from the data attributes previously rendered by
                // the template) in the new order 
                var order = [];

                $("#" + clientId).find("div[data-itemid]")
                .each(function(index) {
                    order.push($(this).attr("data-itemid"))
                });
                
                // (2) Send the new order to the page class
                ajax('updateitemorder', {
                    element: null, // null necessary when the page
                                   // (rather than a component)
                                   // is supposed to handle the event
                    
                    data: {order: JSON.stringify(order)},
                    
                    // response.json is the object returned by
                    // the event handler method
                    success: function(response) {
                        console.log(response.json.numUpdated +
                        " items updated on server.");
                    }
                });
            }
            
        });
        
    }
});

我知道更新所有项目与仅更新已更改项目的方法有些不同。然而,它允许在这里提供更简洁的答案。我相信您可以根据您的需要调整我的示例。

剩下要做的最后一件事是确保页面类正确处理由

updateitemorder
函数调用的
ajax()
事件。继续阅读。

在事件处理方法中使用@RequestParameter

假设您使用 Tapestry 5.4.2 或更高版本,请使用

@PublishEvent
注释事件处理程序,这会使其被
ajax()
函数识别。

@RequestParameter
添加到事件处理程序至关重要,否则无法从客户端接收数据。


@Inject
ItemService itemService;

@OnEvent("updateBoatOrder")
@PublishEvent
JSONObject updateItemOrder(@RequestParameter("order") JSONArray order) {

    long numUpdated = itemService.reorder(order);
        
    return new JSONObject("numUpdated", numUpdated);

}

完成!当然,从你开始的地方(在 RequireJS 世界之外)进行了一些重写。但当你已经身处其中时,其实并没有那么复杂。

作为结束语,请注意,从版本 5.5 Tapestry 开始也支持 TypeScript。只需添加

tapestry-webresources
依赖项即可开始。

© www.soinside.com 2019 - 2024. All rights reserved.