簡體   English   中英

Rails 4:如何使用AJAX更新索引頁面

[英]Rails 4: How to update index page with AJAX

我不敢相信我還沒有找到其他問題來回答這個問題,但是我搜尋了很多東西,找不到任何能真正回答我問題的東西。

基本上,我有一個“費用”頁面,在其中我要在表格中顯示給定月份的所有費用。 我有一個月份和年份選擇,現在我可以通過向URL添加月份和年份參數並使用一些JavaScript轉到該href來工作。 我想避免頁面刷新,而只是在更改選擇框值時更新表。 據我了解,因為我沒有使用表單,所以無法使用:remote => true ,因此必須使用AJAX。 我的研究促使我進行以下設置。

這是我的帶有AJAX調用的JQuery:

$(document).ready(function() {

    $('#monthSelect').change(function() {
        // alert("yay");

        var m = $(this).val();
        var y = $("#yearSelect").val();
        $.ajax({
            type: "GET",
            url: "/expenses",
            data: { month : m, year : y } ,
            success: function(data) {

            },
            dataType: "json"
        });
    });
});

#monthSelect#yearSelect是我的兩個選擇框的ID。 這部分似乎有效。 當我更改month select box的值時,它將GET請求發送到params具有正確的月份和年份的"/expenses"

/expenses自然會轉到我的index操作。 這是我感到困惑的部分。

def index
    @expenses = # Code that gets the expenses that correspond to the month and year in the params.
    # This part works. I've tested it and @expenses are all the records I want

    respond_to do |format|
        format.html
        format.json { render json: @expenses, status: :ok } #?????
    end
end

所以我想我的主要問題是json部分的工作方式,以及是否應該在AJAX中使用json。 我看過的所有教程和視頻似乎都意味着在json中獲取響應是您應該執行的方式,但是我不確定“呈現json”的含義。 我的理解是,傳遞@expenses ,它基本上將呈現@expenses.to_json返回的內容,它只是一堆json,鍵值對。 我該怎么做並做一張桌子?

我的一個做過很多AJAX但沒有Ruby on Rails的朋友說我可以在AJAX成功函數中編寫HTML

...
success: function(data) {
    $("#expenses-table").html("HTML of my Table");
}

但這似乎不像Rails的方式,而是放置一堆將HTML放入字符串的Javascript代碼。 如果我只是將HTML放入AJAX,那么render: json做什么? 我確實在堆棧溢出中看到了一個答案

success: function(data) {
    $("#expenses-table").html(data);
}

那樣很好,因為數據確實具有我想要的所有json。 但是顯然,這不只是那樣。

因此,如果我能對這整個混亂情況有所澄清,或者甚至可以使用JSON進行處理,或者只用AJAX編寫HTML,那將不勝感激。

編輯1:這是我當前的表代碼:

<table id="expenses">
    <thead>
      <tr>
        <th>Description</th>
        <th>Amount</th>
        <th>User</th>
        <th>Date</th>
        <th colspan="3"></th>
      </tr>
    </thead>

    <tbody>
      <% @expenses.each do |expense| %>
        <tr id="expenses-row">
          <td><%= expense.description %></td>
          <td><%= number_to_currency expense.amount %></td>
          <td><%= expense.user.name %></td>
          <td><%= expense.date.strftime("%m/%Y") %></td>
          <td><%= link_to 'Show', expense %></td>
          <% if expense.user == @user %>
            <td><%= link_to 'Edit', edit_expense_path(expense) %></td>
            <td><%= link_to 'Delete', expense, method: :delete, data: { confirm: 'Are you sure?' } %></td>
          <% else %>
            <td></td>
            <td></td>
          <% end %>
        </tr>
      <% end %>
    </tbody>
  </table>

基本上只是標准的腳手架表。 大多數更改只是CSS。 這是一個記錄的json的樣子

[{"id":8,"description":"This is a test","amount":"35.0","user_id":1,"date":"2014-10-01","created_at":"2014-10-03T07:07:53.412Z","updated_at":"2014-10-03T07:07:53.412Z","receipt_file_name":null,"receipt_content_type":null,"receipt_file_size":null,"receipt_updated_at":null}]

我想我更願意在ERB / ruby​​中編寫代碼,因為我對此更加熟悉。 盡管擁有json幾乎沒有任何意義,因為@expenses是我在當前表代碼中已經使用的。 但是,不會渲染:file“ expenses_table.html.erb”刷新整個頁面嗎? 或者,它怎么知道只在哪里渲染該表並替換以前的表? 響應format.js並創建index.js.erb聽起來似乎比較容易,因為我知道我可以用我的局部替換html。 但是我還沒有嘗試過,因為我看到的所有示例都響應format.json 如果聽起來我很困惑,不知道發生了什么,那是因為我在。 我只需要澄清一下。 謝謝你的幫助!

如果我什至應該在AJAX中使用json。

您可以使用所需的任何類型的String。 問題是在javascript端解析字符串以提取每條數據。 例如,您可以使用以下字符串進行響應:

"exp1=10, exp2=20, exp3=30"

然后,您的javascript代碼可以將字符串拆分為“,”,然后拆分為“ =”,然后使用片段創建對象,然后可以使用對象來引用數據。 另一方面,如果數據以JSON字符串形式發送,那么您在javascript中要做的就是:

var obj = JSON.parse(data);

...和obj將類似於ruby Hash,您可以在其中查找鍵以獲取值。

所以我想我的主要問題是json部分是如何工作的...我的理解是傳遞@expenses,它基本上將呈現@ expenses.to_json返回的內容,這只是一堆JSON鍵值對。 我該怎么做並做一張桌子?

沒錯 您可以利用自己的編程技能來制作表格。

我的一個做過很多AJAX但沒有Ruby on Rails的朋友說我可以在AJAX成功函數中編寫HTML

可以,但是訣竅仍然是以編程方式獲取json中的數據並將其插入到html表中。 如果您要走那條路線,可以返回一個完整的表作為響應,以便可以在服務器端使用ERB / Nokogiri / ruby​​將數據插入表中。 然后,您將編寫如下內容:

@expenses = ....
render :file "/some/dir/expenses_table.html.erb"

另一種方法可能是給表中的每個<td>一個id屬性,該屬性等於json數據中的一個鍵。 然后,您可以使用javascript遍歷json數據中的每個鍵,查找具有該ID的<td> ,然后將該條目替換為與該鍵對應的json數據中的值。

如果您需要更具體的建議,則必須發布表HTML的小示例以及@ expenses.to_json的外觀。

順便說一下,jQuery ajax()函數具有太多功能,因此所有常見的ajax請求都具有快捷鍵功能,其中為您填寫了相關選項,例如getJSON() ,您只需指定url,data,和成功功能。 在這種情況下,這不會為您節省很多工作,但是函數名稱可能比'ajax'更具描述性。

對評論問題的回應:

我想我的困惑是,這是哪個JavaScript? 這是原始的AJAX通話嗎?

是。 那是您唯一需要編碼的javascript。

那應該在js.erb文件中,然后讓我調用一些ruby代碼嗎?

否。如果要使用ruby創建某些js(這是erb的目的),並且要返回js代碼作為響應,則可以使用js.erb文件。 我們已經確定您不想返回javascript作為響應。 但是,使用rails設置ajax非常令人困惑,因此我可能不太了解您的問題的要點。 不使用rails生成ajax javascript要簡單得多。

據我了解,如果您在創建html表單時在rails html幫助remote: true放置了remote: true ,則在提交表單時,會使用text/javascript的Accept標頭將請求發送到Rails應用程序。 這意味着,如果您的操作包含帶有format.js行的format.js塊,則該行將執行,並且您可以將一些JavaScript發送回瀏覽器,例如,一個.js.erb文件,其中包含執行ajax請求以獲取您的代碼的代碼費用數據。 您的瀏覽器將立即執行返回的js,這將把ajax請求發送回服務器以詢問費用數據。 請注意,rails方式效率低下:瀏覽器必須向服務器發送兩個請求以完成一個ajax請求:將一個請求發送至服務器以獲取將對費用數據進行ajax請求的js代碼,然后瀏覽器執行ajax代碼,該代碼向服務器發送另一個請求以獲取費用數據。

還是可以在響應中調用JavaScript文件?

在我看來,您想用一個全新的表替換現有表,即您沒有在現有表中更改兩個或三個<td>'s ,這應該使事情變得很容易。 實際上,據我所知,您可以使用與創建現有表相同的erb代碼來創建新表。 但是,索引操作對ajax請求的響應應僅返回表,而不是整個頁面。 這建議您將創建表的代碼放入單獨的模板中,該模板應為部分模板:

views/shared/_table.html.erb

<table id="expenses">
<thead><th>Description</th><th>Amount</th><th>Date</th></thead>
<% @expenses.each do |expense| %>
<tr> 
  <!-- I used an abbreviated Expense model: -->
  <td><%= expense.description %></td>
  <td><%= number_to_currency expense.amount %></td>
  <td><%= expense.date %></td>
</tr>
<% end %>
</table>

然后,將局部views/expenses/index.html.erb包含在views/expenses/index.html.erb

<h1>Expenses#index</h1>
<p>Find me in app/views/expenses/index.html.erb</p>

<div>
<select id='expense_day'>
<option value="all">All</option>
<option value="2014-10-5">10/5/14</option>
<option value="2014-10-6">10/6/14</option>
</select>
</div>

<%= render "shared/table" %>   <!-- HERE -->

默認情況下,render()將在app / views目錄中shared/_table.html.erb名為shared/_table.html.erb的部分目錄。

合並后的兩個文件(插入到應用程序布局中)構成index.html.erb視圖。 因為該表現在是一個單獨的模板,所以僅可以響應ajax請求來呈現該表:

class ExpensesController < ApplicationController

  def index
    respond_to do |format|
      if request.xhr?  #Is this an ajax request?
        target_date_str = params['target_date']

        if target_date_str == "all"
          @expenses = Expense.all
        else
          @expenses = Expense.where(date: Date.strptime(target_date_str, "%Y-%m-%d"))
        end

        #Render just the table for the ajax request:
        format.html { render partial: "shared/table" }

      else  #then not an ajax request
        @expenses = Expense.all
        format.html   #By default renders index.html.erb 
      end
    end

  end

end

respond_to()查看請求中的Accept標頭,並根據該標頭選擇匹配的格式:

format.html
format.json
format.xml
etc.  

我檢查了jQuery的.get()ajax函數發送的請求,並以最高優先級發送了帶有text/html的Accept標頭的請求,因此將在response_to塊中選擇format.html。 編輯:我最初寫索引操作以為ajax請求有一個format.json行,而一個非ajax請求有一個format.html行。 但是由於在兩種情況下index操作現在都返回html,因此不需要response_to()塊:

class ExpensesController < ApplicationController
  def index
    if request.xhr?  #if an ajax request...
      target_date_str = params['target_date']

      if target_date_str == "all"
        @expenses = Expense.all
      else
        @expenses = Expense.where(date: Date.strptime(target_date_str, "%Y-%m-%d"))
      end

      render partial: "shared/table"  #Overrides rails default operation which renders index.html.erb

    else  #then not an ajax request
      @expenses = Expense.all  #rails defaults to rendering index.html.erb
    end

  end

這是我使用的JavaScript:

<script>

$( document ).ready(function() {
  $("#expense_day").on("change", function() {

    var selected_date = $(this).val();

    $.get( 
      "/expenses", 
      { target_date: selected_date }, 
      function(table) {
        $("#expenses").replaceWith(table)  
      }
    );

  });
});

</script>

    <h1>Expenses#index</h1>
    <p>Find me in app/views/expenses/index.html.erb</p>

    <div>
    <select id='expense_day'>
    <option value="all">All</option>
    <option value="2014-10-5">10/5/14</option>
    <option value="2014-10-6">10/6/14</option>
    </select>
    </div>

    <%= render partial: "shared/table", expenses: @expenses %>

我將javascript放在index.html.erb視圖中,這應該清楚表明javascript是html頁面的一部分。 但是,您可以從index.html.erb中刪除javascript並將其放在另一個文件中-但最終js必須找到返回index.html.erb文件的方式。 以下是一些討論javascript備用位置的鏈接:

Rails為什么不呈現.js.erb文件?

在Rails 3應用程序中添加頁面特定javascript的最佳方法?

Rails有一種稱為asset pipeline的方法,它是一種通過刪除所有空白將所有javascript和css塞入盡可能少的行的方法。 由於文件較小,因此瀏覽器可以更快地加載它們。 要采取縮小文件的優勢,你必須把你的assets ,即你的JavaScript和CSS文件,為某些目錄。 實際上,您無需擔心,因為您的javascript代碼不超過數千頁。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM