0

这是facebox弹出内容

<div class="form_container">
  <% form_remote_tag :url => { :action => 'custom', :d=>params[:day], :h=>params[:hour]  },
        :class => 'general-form',
        :update => 'grid['+params[:day]+']['+params[:hour]+']',
        :success => 'handle_success('+params[:day]+','+params[:hour]+')' do -%>
    <table width="300px" style="border:none">
      <% @availability_hash.each_key do |availability_id| %>
        #some view related stuff
      <% end %>
    </table>
    <input type="submit" class="btn" value="Re-assign Coaches" />
  <% end %>
</div>

这是控制器方法

  def custom
    master_scheduler
    h = params[:h].to_i
    d = params[:d].to_i
    render(:partial => "grid_item" , :locals => {:day=>d, :hour=>h})
  end

这是部分(_grid_item.html.erb)

<div class ="left_inner_element">
  <div class="l_upper_element">
    <div class="coaches_committed"><%= data[:committed_coaches] %></div>
    <div class="coaches_available"><%= data[:available_coaches] %></div>
  </div>
  <div class="l_lower_element"><%= data[:classes] %> : <%= data[:avg_attendance] %>
  </div>
</div>
<a id="link[<%= day %>][<%= hour %>]" rel="facebox" href="coach_selector_popup?(bla bla)" >
  <div class ="right_inner_element right_inner_color_<%= data[:color_code] %>">
    #some ui stuff
  </div>
</a>

这是主页面中使用的脚本

<script type="text/javascript">
  jQuery(document).ready(function($) {
    jQuery('a[rel*=facebox]').facebox()
    $.facebox.settings.opacity = 0.5
  })

  function handle_success(d,h){
    jQuery(document).trigger('close.facebox');
    var link_div = document.getElementById('link['+d+']['+h+']');
    jQuery(link_div).facebox();
  }
</script>

<div class="master_view">
  <table class="master_scheduler_table" id="master_scheduler_table" >
    <% HOURS_IN_A_DAY.each do |hour| %>
      <tr>
        <td><%= time(hour*2) %></td>
        <% DAYS_IN_A_WEEK.each do |day| %>
          <td id="grid[<%= day %>][<%= hour %>]" >
            <%= render(:partial => "grid_item" , :locals => {:day=>day, :hour=>hour, :data=>@data[day][hour]}) %>
          </td>
        <% end %>
      </tr>
    <% end %>
  </table>
</div>

渲染完成后,我想调用一个 javscript。怎么做?我正在使用视图中的 form_remote_tag。

渲染部分是在 Ajax 上下文中完成的,不会发生页面重新加载。form_remote_tag 有一个 :success 方法,我可以在其中调用 javascript。不幸的是,我在成功方法中放置的 javascript 在渲染完成之前被调用。但是,我需要在渲染完成后调用 javascript。

为了清楚起见,我只是在问题中添加了一条警报消息。实际上,我正在渲染的 DIV 元素上调用 facebox() 方法。facebox() (jQuery 的)方法应该在 DIV 元素被渲染之后应用到它,然后它才会生效。

编辑:我已经添加了完整的代码。如果您能看到,我将在 Ajax 返回后调用 javascript 方法 handle_success。(我很抱歉将 :success 方法放在部分中)。在实际渲染完成之前调用 handle_success。那应该是在它完成之后

4

3 回答 3

3

干得好:

 <!-- IN HTML.ERB FILE -->
    <div class="form_container">
      <% form_tag({:action => :custom, :d => params[:day], :h => params[:hour]}, {:class => "general-form"}) do %>
        <table width="300px" style="border:none">
          <% @availability_hash.each_key do |availability_id| %>
            <tr>
              <td width="50%"><b><%= CoachAvailability.find(availability_id).coach_availability_template.coach.display_name %></b> (X/8)</td>
              <td><%= select_tag('template['+availability_id.to_s+']', options_for_select([["Available", 0],["Scheduled", 1]], :selected => CoachAvailability.find(availability_id).status )) %></td>
            </tr>
          <% end %>
        </table>
        <%= submit_tag "Re-assign Coaches", :class => "btn" %>
      <% end -%>


//In your JS file
$(".general-form").live('submit', function() {
    $.post(this.action, $(this).serialize(), "_method=post");
    return false;
})


#In your controller
def custom
    master_scheduler
    h = params[:h].to_i
    d = params[:d].to_i
    @day = d
    @hour = h
    respond_to do |format|
      format.xml
    end
end

<!-- IN custom.xml.erb -->
<taconite>
    <append select="#div_changed_content">

         What ever changes you want to make. Your code is bit confusing. So i won't go deep into what should come here. You know what changes you want to make. :)

         Maybe you wanted to add this? How did you get data[:commited_coaches] and data[:available_coaches] without passing it through the partial?? 

         Anyways if you want to pass it now you can do so from the controller itself. By creating a @data_commited_coaches and @data_available_coaches and storing the above in that.



    <div class ="left_inner_element">
  <div class="l_upper_element">
    <div class="coaches_committed"><%= data[:committed_coaches] %></div>
    <div class="coaches_available"><%= data[:available_coaches] %></div>
  </div>
  <div class="l_lower_element"><%= data[:classes] %> : <%= data[:avg_attendance] %>
  </div>
</div>
<a id="link[<%= day %>][<%= hour %>]" rel="facebox" href="coach_selector_popup?(bla bla)" >
  <div class ="right_inner_element right_inner_color_<%= data[:color_code] %>">
    #some ui stuff
  </div>
</a>


    </append>   

    <eval>
       // You can call the handle_success here: If i guessed right, this is what you want to do.
       handle_success(<%= @day %>,<%= @hour %>);
    </eval>

</taconite>

我怀疑你添加了&hourand &date。如果您检测到 firebug 抛出异常,我建议您将其删除,因为它可能不是有效的 xml。如果您确实在 firebug 中遇到 XML Parsing 错误(在 firebug 控制台中执行 AJAX Post 时请参阅 XML 选项卡),只需使用错误编辑您的问题。我会调查的。你也可以向我解释一下这段代码: :update => 'grid['+params[:day]+']['+params[:hour]+']'?您要更新页面上的哪个元素?同样如您所见,custom.xml.erb 包含一个<taconite>标签。它有<append>一个 id 的标签div_changed_content。您必须在.html.erb文件中使用该 id 创建一个 div 标签才能使其正常工作。

于 2010-06-21T06:03:42.170 回答
2

渲染是在服务器端完成的,一旦整个页面组成,生成的 HTML 就会返回给客户端。所以在这种情况下你不能执行客户端脚本。要在页面加载后调用一些 javascript,您可以使用onload事件处理程序:

<script type="text/javascript">
window.onload = function() {
    // put your code here
};
</script>

或者如果你使用jQuery

<script type="text/javascript">
$(function() {
    // put your code here
});
</script>

或者如果您使用Prototype

<script type="text/javascript">
document.observe("dom:loaded", function() {
  // put your code here
});
</script>
于 2010-06-20T09:43:53.830 回答
1

你那里有点不对劲:

“提交标签有一个 :success 方法,我可以在其中调用 javascript。不幸的是,我在成功方法中放置的 javascript 在渲染完成之前被调用。”

:success方法用于提交成功时。不适用于提交后发生的任何事件!您需要在部分渲染后执行成功方法,而不是在单击提交按钮时执行!如果您熟悉 jquery,我建议您采用不显眼的方式。我从不依赖内置助手,因为它缺乏灵活性,而且我讨厌使用内联 javascript.. 你将无法缓存它。我会将我的所有 javascript 放在一个缩小的 js 文件中,该文件可以缓存一次,而不是到处传播代码。无论如何,我只是离题了。

其次,您不应该为 ajax 调用渲染部分内容。这将始终刷新您的页面。相反,您应该为该特定控制器操作创建一个.js.erb或一个文件。.xml.erb

由于您没有给出您在部分中呈现的确切内容,因此我将为您提供一般性答案。请与我们分享您的部分代码,以便我们知道您到底想要什么。还提供selector id/class您想要在成功时修改的 HTML 标记(在呈现之后)。

如果您想要更好的解决方法,我将为您提供我用于 ajax 的配置:


在您的 application.js 中:

$.ajaxSetup({
  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/xml")}
});

$(document).ready(function() {
    //  All non-GET requests will add the authenticity token
    //  If not already present in the data packet
    $("body").bind('ajaxSend', function(elm, xhr, s) {
      if (s.type == "GET") return;
      if (s.data && s.data.match(new RegExp("\\b" + window._auth_token_name + "="))) return;
      if (s.data) {
        s.data = s.data + "&";
        } else {
            s.data = "";
            // if there was no data, $ didn't set the content-type
            xhr.setRequestHeader("Content-Type", s.contentType);
        }
        s.data = s.data + encodeURIComponent(window._auth_token_name) + "=" + encodeURIComponent(window._auth_token);
    });
  });

在 IE 和 SAFARI 中,接受标头默认为 text/html 而不是 text/xml 或 text/javascript。要更正此问题,请将其添加到您的 application.controller.rb;处理所有跨浏览器问题:

  def correct_safari_and_ie_accept_headers
    ajax_request_types = [ 'text/javascript', 'application/json', 'text/xml']
        request.accepts.sort!{ |x, y| ajax_request_types.include?(y.to_s) ? 1 : -1 } if request.xhr?
  end

在您的布局your_layout.html.erb中将其添加到标题中:

<% if protect_against_forgery? %>
    <script type="text/javascript" charset="utf-8">
        //<![CDATA[
            window._auth_token_name = "#{request_forgery_protection_token}";
            window._auth_token = "#{form_authenticity_token}";
        //]]>
    </script>
<% end %>
<%= javascript_include_tag 'jquery.taconite.js','application.js', :cache => true %>

我建议你获取 JQuery taconite 插件!如果您想在您的应用程序中处理 ajax,它就太好了!它可以一次执行多个 DOM 修改。

Malsup 的 JQuery 铁燧石

稍后将解释如何使用它。


现在将其添加到您的 application.js 文件中:

$("form").live('submit', function() {
   $.post(this.action, $(this).serialize(), "_method=post");
   return false;
 })

现在在您用于渲染部分render(:partial => "grid_item")的操作中,将操作更改为此

   def your_action_here

      # CODE GOES HERE:
      # @instance_variable_to_store_stuff = some_stuff
      respond_to do |format|
        format.html {redirect_to :action => :index}
        format.xml #EXTREMELY IMPORTANT. THIS CORRESPONDS TO your_action_here.xml.erb
      end
   end

现在在你views/your_controller/创建一个your_action_here.xml.erb文件。在此文件中,您可以添加在渲染发生后执行的 javascript 代码。此操作将以两种方式响应。如果用户在他的浏览器中禁用了 javascript,它将以 html 数据响应,否则它将默认为 xml 数据。现在这就是铁燧石出现的地方。taconite 的美妙之处在于它将所有基于 jquery 的 DOM 修饰符转换为符合 XML 的标记。

而不是这样做,$("#div").append('<div>YO!</div>')你可以这样做:

<append select="#div">
  <div>YO!</div>
</append>

您还可以进行多次 DOM 修改!忘记链接 100 种不同的修饰符和混乱你的视图代码。使用 rails helpers 作为简单的标记感觉更自然。.js.erb我停止使用文件的主要原因之一。

在您的视图中说您有一个 div 标签<div>,其 id 为“div”

在 your_action_here.xml.erb 中,

<taconite>
  <append select="#div">
    <%=h @instance_variable_to_store_stuff %>
  </append>
</taconite>

如果你想做多个 DOM 更新,你可以这样做,例如:

<taconite>
  <replace select="#div">
    <%=h @instance_variable_to_store_stuff %>
  <replace>

  <append select="#someotherelement_id">
    <div>I got appended to #someotherelement_id</div>
  </append>

  <slideUp select=".someelementwithaclass" />

  <slideDown select=".someelementwithanotherclass" />
</taconite>

您还可以使用 eval 标记在 your_action_here.xml.erb 中运行 javascript,如下所示:

<taconite>
  <append select="#div">
    <%=h @instance_variable_to_store_stuff %>
  </append>

    <eval>
            alert("HO! HO! HO!"); 
            setTimeout(($("#flash").effect("highlight", {}, 3000).slideUp("slow")), 5000);
        $("form")[0].reset();

    </eval>
</taconite>

您应该记住的一件事是所有 xml 标记都应该关闭,并且不应该保持打开状态。严格符合 xhtml。

我忘了提:Taconite 还为您提供了 firebug 中的调试日志记录。如果您想在开发过程中跟踪 ajax 请求所做的更改,这是一个很好的功能。


于 2010-06-21T03:10:49.793 回答