Search code examples
javascriptjqueryruby-on-railsajaxhaml

Get different html with different buttons with AJAX


I got this menu on my website

%button.dropdown-button
  .current-user{onclick:'showMenu()'}
    %img.current-user-image{src:current_user.picture_url}
    = current_user
    %i.fa.fa-bars{'aria-hidden':true}
  .dropdown-content
    .menu-option{onclick:'showFilters()'}
      Filter Transactions
      %i.fa.fa-paper-plane{'aria-hidden':true}
    .transaction-filters
      .filter-option
        My Transactions
        %i.fa.fa-square-o
    %a{href:'#'}
      .menu-option
        Balance History
        %i.fa.fa-history{'aria-hidden':true}
    %a{href:destroy_user_session_path}
      .menu-option
        Sign Out
        %i.fa.fa-sign-out{'aria-hidden':true}

And I got this timeline with transactions

.timeline-container
  - @transactions.each do |transaction|
    .transaction-container
      .transaction-header-container
        .transaction-kudos-container
          = "+#{transaction.amount}"
          %span.currency
            ₭
        .transaction-avatar-container
          %div
            = image_tag transaction.receiver_image, class:'avatar'
      .transaction-body-container
        .transaction-content
          %span
            = "#{transaction.sender.name}:"
          %span.highlighted
            = "+#{transaction.amount} ₭"
          %span
            to
          %span.highlighted
            = transaction.receiver_name_feed
          %span
            for
          %span.highlighted
            = transaction.activity_name_feed
      %div
        -#%button#like-button
        -#  Like
        %span.post-time-stamp
          = "#{distance_of_time_in_words(DateTime.now, transaction.created_at)} ago"
  = paginate @transactions

They are both rendered on my index.html.haml

So when I click the div .filter-option.sent I want to change the code change from

- @transactions.each do |transaction|

to

- @all_transactions.each do |transaction|

to filter out the transactions of the current user without reloading the page.

These variables are defined in my controller

@transactions = Transaction.order('created_at desc').page(params[:page]).per(20)
@all_transactions = Transaction.all_for_user(current_user)

With in my model the method all_for_user

def self.all_for_user(user)
    Transaction.where(sender: user).or(Transaction.where(receiver: user)).order('created_at desc').page.per(20)
end

I tried a lot of things with AJAX but nothing seems to please me. Somebody can help me?


Solution

  • So if you'd like to replace that @transactions list with AJAX you will need to do a few things..

    1) Move the @transactions block into a partial that takes a local variable.

    #transactions-wrapper
      = render partial: 'transactions/list', locals: {transactions: @transactions}
    

    2) Create a link that submits to a route, that hits a controller action as #js ('data-remote': true ) ( or write a javascript function that triggers $.ajax request: https://www.w3schools.com/jquery/ajax_ajax.asp

    %a.transaction-filter{href: "/transactions/#{transaction_type}", 'data-remote': true}
    

    or ex..

    %a.study{href: "/transactions/recent", 'data-remote': true}
    %a.study{href: "/transactions/past", 'data-remote': true}
    

    3) define the route

    get '/transactions/:type' => 'transactions#filter'
    

    4) re-assign the variable based on the filter, and re-render that partial with the new data in a filter.js.erb file thats in the view directory -> app/views/transactions

    def filter
      @filtered_transactions = Transactions.where(type: params[:type] ).order('created_at DESC')
    
      respond_to do |format|
        format.html
        format.js { render :action => 'filter.js.erb', :layout => false}
      end
    end
    

    $("#transactions-wrapper").html("<%= j render(:partial => 'transactions/list'', :locals => { transactions: @filtered_transactions } ) %>");
    alert('Transactions have been filtered, yo')
    

    Let me know if that makes sense! Except please don't actually javascript alert at the end ;)