【问题标题】:Using Unobtrusive JavaScript to Update an Element使用不显眼的 JavaScript 更新元素
【发布时间】:2011-03-09 15:09:05
【问题描述】:

如您所知,当您从 Rails 2 升级到 3 时,您会替换:

link_to_remote "more", :url => {...}

用这个:

link_to "more", {...}, :remote => true

但是如何处理 link_to_remote 中的 :update 选项?在Railscast #205 Ryan Bates 中演示了link_to:remote 以及一个服务器响应,其中包含用于更新页面中特定元素的JavaScript 代码,但这种做法对我来说似乎是错误的。我希望我的服务器的响应是一个简单的 HTML 片段,它易于测试并且可以由不同的页面(客户端)以不同的方式使用。我认为服务器不必知道请求页面上目标元素的 ID,因为它将操作与页面(迷你客户端)联系起来,因此使其不那么通用(它也比纯 HTML 更难看)回应)。

所以,明确地说,有没有办法做这样的事情:

link_to_remote "more", :url => {...}, :update => "products-list"

使用 Rails 3 和 UJS?还是我必须编写 JavaScript 来捕获服务器的 HTML 响应并将其插入到页面上的正确元素中?

如果是后者,请描述最佳方法(可以使用link_to:remote 选项吗?)。

【问题讨论】:

    标签: jquery ruby-on-rails ajax ruby-on-rails-3 unobtrusive-javascript


    【解决方案1】:

    我不能 100% 确定这是 Rails 认可的方法,但我找到了一个可行且看起来很干净的解决方案。假设我们有一个页面列出了我们数据库中最受欢迎的十种产品。最后是通过 AJAX 加载所有剩余产品的链接:

    <ul id="products-list">
      <li>...</li>
      <li>...</li>
      <li>...</li>
      ...
    </ul>
    <%= link_to "more...", "/products/all", :id => "load-more", :remote => true %>
    

    服务器返回纯 HTML(以便链接可以在许多不同的页面上使用,并且不绑定到特定的 DOM ID)。我们使用由 Rails UJS 驱动程序(这里我使用 jQuery)触发的 ajax:x 事件来获取服务器的响应并将其插入到页面上的正确元素中:

    <%= javascript_tag do %>
      $("#load-more").bind("ajax:complete", function(et, e){
        $("#products-list").html(e.responseText);
      });
    <% end %>
    

    如果需要,我们还可以使用ajax:loading 事件来显示“微调器”:

    <%= javascript_tag do %>
      $("load-more").bind("ajax:loading", function(et, e){
        $(this).hide();
        $("#products-spinner").show();
      });
    <% end %>
    

    Rails UJS 驱动程序还触发其他四个事件:ajax:successajax:failureajax:beforeajax:after。有关详细信息,请参阅您的应用程序 (public/javascripts/rails.js) 中包含的驱动程序。

    【讨论】:

      【解决方案2】:

      在js视图/apps/views/product/index.js.erb可以写JS代码如下

      原型:

      $("products-list").update("<%= escape_javascript(render(@products))%>");
      

      jquery:

      $("products-list").html("<%= escape_javascript(render(@products))%>");
      

      $("products-list").append("<%= escape_javascript(render(@products))%>");
      

      请求成功后执行

      【讨论】:

      • 这正是我说我不想做的,因为它将服务器的响应与页面上的一个元素(“产品列表”)联系起来。这使我无法使用相同的 URL 更新另一个页面,在该页面中我可能希望将相同的内容插入到具有不同 ID 的元素中。
      • 所以将要更新的元素的 id 传递给控制器​​并让它在视图中使用它
      【解决方案3】:

      是的,您可以使用 link_to :remote 应用后一种方法(编写自定义 JS 以获取服务器响应)。

      你也可以选择获取一个json响应,然后使用JS更新页面上的数据。无论如何,请记住只渲染部分页面,而不是整个页面。

      编辑:

      一个示例代码,当单击 id 为“更多”的内容时应该会调用 AJAX,然后更新页面中的 #product-list 元素:

       $("#more").click(function() {
       // make a POST call and replace the content
          $.post(, function(data) {
            $("#products-list").html(data);
          });
        });
      

      你不需要更多的代码,你可以编写一些帮助程序来生成这个 JS,而不是在视图中编写代码。顺便说一句,这还是 UJS

      【讨论】:

      • 你能给一些示例代码吗?如果我使用:remote =&gt; true 选项,如何捕获服务器的 HTML 响应并将其插入到页面中?
      • 感谢您的代码,但这看起来像是我会使用而不是 :remote =&gt; true,或者我错过了什么? :remote =&gt; true 不处理 POST/GET 请求吗?我需要的是一种从发起请求的代码(在 Rails UJS Prototype 或 jQuery“驱动程序”中)拦截服务器响应的方法。这有意义吗?
      猜你喜欢
      • 2014-01-02
      • 2012-04-06
      • 2011-06-10
      • 1970-01-01
      • 2012-10-10
      • 1970-01-01
      • 2011-05-16
      • 2013-04-05
      • 1970-01-01
      相关资源
      最近更新 更多