Membuat Form's Output dengan AJAX
Latar Belakang
Tujuannya menggunakan AJAX untuk menampilkan hasil tanpa perlu mereload tempate berulang kali. Cukup sekali panggil dan yang berubah adalah pada bagian hasilnya saja.
Gambar 1. Kotak merah adalah satu-satunya bagian yang berubah, sedangkan bagian lain tidak
Cara yang umum, untuk menampilkan output seperti di atas, adalah seperti ini.
1class StocksController < ApplicationController2 def index3 @tracked_stocks = current_user.stocks4 end56 def search7 if params[:stock].present?8 @stock = Stock.new_lookup(params[:stock].upcase)9 if @stock10 render 'users/my_portfolio'11 else12 flash[:alert] = 'Please enter a VALID symbol to search'13 redirect_to my_portfolio_path14 end15 else16 flash[:alert] = 'Please enter a symbol to search'17 redirect_to my_portfolio_path18 end19 end20end
1Rails.application.routes.draw do2 root 'welcome#index'3 devise_for :users45 get 'my_portfolio', to: 'stocks#index'6 get 'search_stock', to: 'stocks#search'7end
1<h3>Search Stocks</h3>2<%= form_tag search_stock_path, method: :get do %>3 <div class="input-group">4 <%= text_field_tag :stock, params[:stock],5 class: "form-control form-control-lg",6 placeholder: "Stock ticker symbol",7 onkeyup: "this.value = this.value.toUpperCase();",8 autofocus: true %>9 <div class="input-group-append">10 <%= button_tag type: :submit, class: "btn btn-success" do %>11 <%= fa_icon "search 2x" %>12 <% end %>13 </div>14 </div>15<% end %>1617<% if @stock %>18 <div class="alert alert-success">19 <div class="row d-flex justify-content-between">20 <div class="col-sm-9 align-self-center">21 <strong>Symbol: </strong><%= @stock.ticker %>22 <strong>Name: </strong><%= @stock.name %>23 <strong>Price: </strong><%= @stock.last_price %>24 </div>25 <div class="col-sm-3">26 <%= link_to "Add to Portfolio", stocks_path(user: current_user, ticker: @stock.ticker),27 method: :post,28 class: "btn btn-success btn-block mx-2" %>29 </div>30 </div>31 </div>32<% end %>3334<% unless @tracked_stocks.empty? %>35 <table class="table table-borderless table-hover my-3">36 <thead>37 <tr>38 <th>Ticker</th>39 <th>Name</th>40 <th>Price</th>41 <th>Action</th>42 </tr>43 </thead>44 <tbody>45 <% @tracked_stocks.each do |stock| %>46 <tr>47 <td><%= stock.ticker %></td>48 <td><%= stock.name %></td>49 <td><%= stock.last_price %></td>50 <td>'Action Placeholder'</td>51 </tr>52 <% end %>53 </tbody>54 </table>55<% end %>
Setelah form diinputkan, dan hasil ditampilkan, akan mendapatkan URL seperti ini.
http://localhost:3000/search_stock?stock=AMZN&button=
Apabila kita menginputkan nilai yang lain, maka template akan ikut dirender untuk menampilkan hasil pencarian yang baru.
http://localhost:3000/search_stock?stock=GOOG&button=
Nah, pada catatan kali ini, saya akan membuat template dirender sekali saja dan hanya pada bagian yang menampilkan hasil pencarian yang dirender berkali-kali.
Pemecahan Masalah
Pertama-tama, saya akan merubah output di stocks_controller pada action search menjadi format Javascript.
1class StocksController < ApplicationController2 def index3 @tracked_stocks = current_user.stocks4 end56 def search7 if params[:stock].present?8 @stock = Stock.new_lookup(params[:stock].upcase)9 if @stock10 respond_to do |format|11 format.js { render partial: 'users/result' }12 end13 else14 respond_to do |format|15 flash.now[:alert] = 'Please enter a VALID symbol to search'16 format.js { render partial: 'users/result' }17 end18 end19 else20 respond_to do |format|21 flash.now[:alert] = 'Please enter a symbol to search'22 format.js { render partial: 'users/result' }23 end24 end25 end26end
Kemudian, pada bagian view, pisahkan bagian result, menjadi render partial, saya beri nama _result.html.erb
.
1<% if stock %>2 <div class="alert alert-success">3 <div class="row d-flex justify-content-between">4 <div class="col-sm-9 align-self-center">5 <strong>Symbol: </strong><%= stock.ticker %>6 <strong>Name: </strong><%= stock.name %>7 <strong>Price: </strong><%= stock.last_price %>8 </div>9 <div class="col-sm-3">10 <%= link_to "Add to Portfolio", stocks_path(user: current_user, ticker: stock.ticker),11 method: :post,12 class: "btn btn-success btn-block mx-2" %>13 </div>14 </div>15 </div>16<% end %>
Pada bagian yang kita pindahkan (kode di atas) di view stocks/index.html.erb, kita ganti dengan <div id=results>
.
1...2...34<div id="results"></div>
Kita akan meletakkan hasil yang diberikan oleh controller pada div denga id=result tersebut.
Kita akan atur di dalam file javascript, buat file _result.js.erb.
1document.querySelector('#results').innerHTML = "<%= escape_javascript(render 'users/result.html', stock: @stock) %>"
Terakhir, tinggal menambahkan asynchronous form pada form pencarian dengan remote: true
.
1<h3>Search Stocks</h3>2<%= form_tag search_stock_path, remote:true, method: :get do %>3 <div class="input-group">4 <%= text_field_tag :stock, params[:stock],5 class: "form-control form-control-lg",6 placeholder: "Stock ticker symbol",7 onkeyup: "this.value = this.value.toUpperCase();",8 autofocus: true %>9 <div class="input-group-append">10 <%= button_tag type: :submit, class: "btn btn-success" do %>11 <%= fa_icon "search 2x" %>12 <% end %>13 </div>14 </div>15<% end %>1617...18...
Hasilnya,
Gambar 2. Hasil jadinya
Kalau diperhatikan pada bagian address bar, alamat tidak berubah. Karena kita tidak merender template lagi untuk menampilkan hasil, namun hanya merubah bagian yang memiliki <div id=results></div>
.
Pesan Penulis
Sepertinya, segini dulu yang dapat saya tuliskan.
Mudah-mudahan dapat bermanfaat.
Terima kasih.
(^_^)