ajax调用后视图中未评估Sinatra实例变量



我已经没有什么想法了,在没有任何解决方案的情况下浏览了网络,所以我希望有人能让我摆脱困境,因为我真的,真的很困。

我的一条路由查询数据库,并通过一组实例变量(@campagnes和@emissions)通过erb呈现数据。不用担心,一切都很好。

我设置了一个jQuery函数,它可以帮助我根据下拉选择器筛选表中的数据。因此,如果用户更改了下拉列表中的选定值,jQuery$.ajax方法会重新加载页面,将选定值传递给"get"路由。

这是我没有得到的。调用有效,它成功了,参数被传递到路由,它们用于从数据库中读取,但所有具有新数据集的实例变量都拒绝在视图中进行评估。相反,仍然使用旧的表(在Ajax调用之前使用初始GET评估的表),因此该表仍然是旧表。

为了在视图中再次评估实例变量,我需要在Ajax调用中传递什么?

这是我的路线:

get '/admin/mission' do
# load the appropriate js file in template
@js = "mission.js"
# retrieve list of all campagnes, latest on top
@campagnes = Campagne.all :order=>:id.desc

if !params[:campagne]
#puts "camp id retrieved from normal GET"
camp_id = @campagnes[0].id # first campagne in collection is latest
else
#puts "camp id retrieved from ajax call"
camp_id = params[:campagne] # if submitted via Ajax
end
# retrieve list of missions for selected campaign
@missions = Mission.all :campagne_id => camp_id, :order=> :numero.asc
erb :admin_mission , :layout => !request.xhr?
end

我的观点(编辑为重要内容)

<div id="mission_form">
<form class="cmxform" name="mission" action="/admin/mission" method="post">
<ol>
<li>
  <label for="campagne" id="campagne_label" >Choisir une Campagne</label>
  <select id="campagne" name="campagne">
    <% @campagnes.each do |c| %>
      <option value="<%= c.id %>"> <%=h c.nom %> </option>
    <% end %>
  </select>
</li>
<li>
  <label for="numero" id="numero_label" >Num&eacute;ro</label>
  <input type="text" name="numero" id="numero" placeholder="" size="5"/>
  <label class="error" for="numero" id="numero_error">Champ obligatoire.</label>
</li>
<li>
  <label for="nom" id="nom_label" >Nom de la mission</label>
  <input type="text" name="nom" id="nom" placeholder="" size="50"/>
  <label class="error" for="nom" id="nom_error">Champ obligatoire.</label>      
</li>
<li>
  <input type="submit" name="submit" id="submit_btn" class="button" value="Ajouter" />
</li>
</ol>  
</fieldset>
</form>
</div>
<table div="table_mission" id="hor-minimalist-a" summary="Main Table">
  <!-- Table header -->
  <thead>
  <tr>
  <th scope-"col">Campagne</th>
  <th scope="col">Mission</th>
  <th scope="col">Briefing</th>
  <th scope="col">De-Briefing</th>
 </tr>
</thead>
<!-- Table body -->
<tbody>
<% @missions.each do |m| %>
<tr>
  <td>
    <%=h m.campagne.nom %>
  </td>
  <td>
    #<%=h m.numero %>: <%=h m.nom %>
  </td>
  <td>
    <%=h m.briefing %>
  </td>
  <td>
    <%=h m.debriefing %>
  </td>
  <td>
    <span><a href="/<%= m.id %>">[edit]</a></span>  
  </td>
  <td>
    <class="meta"><%= m.created_at.strftime("Created: %m/%d/%Y") %>
  </td>  
</tr>
<% end %>
</tbody>  
</table>

我的脚本文件(也经过编辑以保留重要的部分):

$(document).ready (function() {
// hide all error and confirm labels
// refresh  mission table if change campagne dropdown
$('#campagne').change(function() {
  var inputs = [];
  $(':input').each(function () {
        inputs.push(this.name + '=' + escape(this.value));
      });
  $.ajax({
    data: inputs.join('&'),
    url: '/admin/mission', // couldhave used: this.action if it was a submit...
    timeout: 2000,
    error: function() {
      console.log("Failed to submit"); // remove when going live
    },
    success: function() { // 
      $('label#campagne_confirm').show(function() {
            console.log("Sucess!");
          });
       }
 });
});

实例变量仅用于从ERB模板创建HTML/JavaScript视图,因此,在不重新加载页面的情况下,再多地更改这些变量的值也不会影响已经呈现为视图的内容。

Ajax调用应该以JavaScript可以用来操作页面DOM的形式返回页面所需的任何新数据。例如,返回一个漂亮的json构建的服务器端块。

此外,您可能还想看看DataTables,这是一个很好的jQuery插件,可以帮助操作表数据。它有一些不错的Ajax处理程序。

经过多次努力,我找到了一种解决方案(我不太喜欢)和对行为的解释(尽管我不能100%确定)。

关于行为,我的Ajax调用不会刷新页面(毕竟这是Ajax的预期行为),这解释了为什么我看不到新值。

我试图通过从我的帖子路由重定向的Ajax帖子找到一个解决方案,但显然Ajax帖子取消了帖子路由中的重定向(我不知道为什么)。

因此,最后我只采用了一种(丑陋的)仅使用ajax的方法,它看起来像这样:

// refresh  mission table if change campagne dropdown
$('select#campagne').change(function() { 
//retrieve value from select tag
var camp_id = $('select#campagne').val();
// pass the parameter in the resource
var uri = "/admin/mission?campagne=" + camp_id;
// GET resource with parameter
// and pass the data returned (the page itself) inside an element
// with some filtering to only get the table from the page
$.get(uri, function(data) {
    console.log("get succesful");
    var $table = $(data).find('tbody');
    console.log($table);
    $('tbody').replaceWith($table);
    });
}); 

我相信有更好的方法可以做到这一点,我只是不知道它是什么。

我的建议是为campagne(活动?)列表提供一条完全独立的路线,例如

def get_campagne_id
  @campagnes = Campagne.all :order=>:id.desc # you might want to cache this
  camp_id = if !params[:campagne] # personally I'd pass the params as arguments, but this will do...
    #puts "camp id retrieved from normal GET"
    @campagnes[0].id # first campagne in collection is latest
  else
    #puts "camp id retrieved from ajax call"
    params[:campagne] # if submitted via Ajax
  end 
end

def mission_by_campaign( camp_id )
  # retrieve list of missions for selected campaign
  Mission.all :campagne_id => camp_id, :order=> :numero.asc
end

现在变成了:

get "/missions_by_campaign", :provides => :json do
  content_type :json
  missions = mission_by_campaign( params["camp_id"] )
  missions.to_json
end
get '/admin/mission' do
  # load the appropriate js file in template
  @js = "mission.js"
  camp_id = get_campagne_id
  # retrieve list of missions for selected campaign
  @missions = mission_by_campaign( camp_id )
  erb :admin_mission
end

然后,您将ajax调用放置到/messions_by_campaign,并使用它来更新页面。你需要写更多的代码,但它让你知道我在说什么。

最新更新