0

I am implementing a live search with a drop down containing multiple fields to filter through.It starts with only one search field, a drop down to select what to be searched for and a button to add more filters, when the user click the button, it generate a new field like this:enter image description here

This image sample was done hard coded with the html inside the JavaScript. The problem is that I will use it in a lot of views so I need it to be dynamic as the code I previously done with Ruby to generate the first search field. I tried doing this way, but no success was achieved.

live_search.js.erb

$(function () {

    function search() {
        $.get(window.location.href, { object_columns: $("select#object_columns").val(), search: $("#search").val() }, null, "script");
    };

    $("select#object_columns").change(search);
    $("input#search").keyup(search);

    $('button').on('click',function(){
      column = "<%= j render 'shared/search_engine' %>";
      $('#search-form').after(column);
    });
});

search_engine.html.erb

<div id="search-form">
  <%= form_tag do %>
  <% valid_column_names = target.column_names.reject{|r| r == "created_at" || r == "updated_at" || r == "slug"} %>
  <%= select_tag :object_columns, options_for_select(valid_column_names) %>
  <%= text_field_tag :search, '', autocomplete: :off %>
  <% end %>
  <%= button_tag "+" %>
</div>

I even tried to call the "search-form" in the JavaScript to replicate the code when the button was clicked but I read that it is not possible.

EDIT

I made some changes as @ppascualv suggested, but I still can't render and add another "search_engine" when I click the button. I am getting an error saying undefined method 'render'.

live_search.js.erb

$(function () {

    function search() {
        $.get(window.location.href, { object_columns: $("select#object_columns").val(), search: $("#search").val() }, null, "script");
    };

    $("select#object_columns").change(search);
    $("input#search").keyup(search);

    $('button').on('click',function(){
      $('button').append("<%= escape_javascript(render @search_engine) %>");
    });
});

search_engine.html.erb

<div id="search-form">
  <%= form_tag({controller: "house_activities", action: "index"}, method: "get", remote: true) do %>
  <%  valid_column_names = HouseActivity.column_names.reject{|r| r == "created_at" || r == "updated_at" || r == "slug"} %>
  <%= select_tag :object_columns, options_for_select(valid_column_names) %>
  <%= text_field_tag :search, '', autocomplete: :off %>
  <% end %>
  <%= button_tag "+" %>
</div>

house_activities_controller.rb

class HouseActivitiesController < ApplicationController
  before_action :set_house_activity, only: [:show, :edit, :update, :destroy]

  def index
    @house_activities = HouseActivity.page(params[:page]).per(5).search_for(params[:object_columns], params[:search])
    respond_to do |format|
      format.js
      format.html
    end
  end
end

3 Answers 3

1

You should take a look at Javascript with Rails, for achive your proposit you will need to create a controller that responds with your js.erb, and this action should be called from a link with data-remote=true or from ajax.

Sign up to request clarification or add additional context in comments.

1 Comment

I tried following the tutorial you linked, but I still couldn't achieve success. I made an EDIT section with the new update, if you could kindly take a look at it, thanks.
0

You could do something like:

search_engine.html.erb

<%= form_tag(target_path, method: :get) do %>
    <%= text_field_tag :query, nil, placeholder: "Search by column names...", class: "form-control search-form" %>
<% end %>

live_search.js

$(document).on("change", ".search-form", function() {
    return $(this).parents("form").submit();
});

Then in your target model, you could add a search scope to make it dynamic.

target.rb

class Target < ActiveRecord::Base
    scope :search, -> (query) {
        return if query.blank?;
        where("target.column_name1 ILIKE :query or target.column_name2 ILIKE :query or target.column_name3 ILIKE :query", query: "%#{query}%") 
    }
end

And in your targets_controller.rb

class TargetsController < ApplicationController
    def search_engine
        @targets = Target.search(params[:query])
    end
end

3 Comments

I could try this,but I want to filter the search with a lot of columns, I should use and instead of or in the terget.rb? And the number of columns are dynamic so I don't think I can use only three columns...
Using or will return you all results if any column matches the query. You can use as many columns as you like but naturally this will affect speed of search, the example is purely an illustration.
Maybe I explained wrong. What I am trying to do is different, for example, imagine if I have two columns, name and address, in my search engine, if I type a name it will return me all people with that name, but if I add another filter by address and search for an address, I want it to return all people with that name and that address at same time.
0

I was able to solve my problem. I discovered that you can't render things in assets and you can't use ruby inside a JavaScript file. I did some workaround and got it done, I included the JavaScript code inside the html.erb file using the <script> JavaScript code </script> syntax as shown here:

<script type="text/javascript">

  column =
  '<%= form_tag({controller: "people", action: "index"}, method: "get", remote: true) do %>' +
  '<%  valid_column_names = Person.column_names.reject{|r| r == "created_at" || r == "updated_at" || r == "slug"} %>' +
  '<%= j (select_tag :object_columns, options_for_select(valid_column_names)) %>' +
  '<%= text_field_tag :search, '', autocomplete: :off %>' +
  '<% end %>';

  $('button').on('click',function(){
    $('button').after(column);
  });

</script>

Because the select_tag ruby line generated a sentence with lots of quotation marks, the j used is the same as escape_javascript and it is used to format a sentence so the JavaScript can read it properly.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.