user1738017
user1738017

Reputation: 627

populate jquery autocomplete with data from a database

I'm using jQuery Autocomplete with categories, I've used the demo code which worked fine, now i'm trying to populate the drop down with data from my database. I've used this code within my view:

:javascript
  $(function() {
      var data = [
          - Datasheet.find(:all).each do |ds|
            { label: "#{ds.title}", category: "Data Sheets" },
          - Brochure.find(:all).each do |br|
            { label: "#{br.title}", category: "Brochures" },

        $( "#search" ).catcomplete({
          delay: 0,
          source: data
      });
  });

but I get the error undefined local variable or method 'ds' for #<#<Class:0x00000005c95a18>:0x00000005c8d570>

I'm not sure if it's because i'm mixing haml with javascript? is there another way around this? All I have in my view is a text field called search, which works with demo code.

Upvotes: 0

Views: 411

Answers (1)

matt
matt

Reputation: 79783

Code inside a filter such as :javascript isn’t treated as Haml, it’s just s string that gets fed through the filter, so - and = don’t work as they do in the rest of Haml. You can use interpolation (i.e. #{...} blocks) though. In fact that’s what’s causing your error – in "#{ds.title}" Haml is trying to evaluate the ds, but not in the context of the block passed to Datasheet.find.

#{} blocks can span multiple lines, so you could change your code to something like this:

:javascript
  $(function() {
      var data = [
          #{
          (Datasheet.find(:all).map do |ds|
            "{ label: \"#{ds.title}\", category: \"Data Sheets\" }"
          end +
          Brochure.find(:all).map do |br|
            "{ label: \"#{br.title}\", category: \"Brochures\" }"
          end).join(',')
          }
      ];

      $( "#search" ).catcomplete({
        delay: 0,
        source: data
      });
  });

Here instead of using each to iterate over each array we use map to create a new one, then use + to add the two arrays together and finally use join(',') to combine them into a single string which is inserted into the page.

This is a pretty ugly and unwieldy bit of code however. A better solution in this case would be to extract out the code that creates the array into a helper and call the helper from your Haml.

Helpers:

def datasheet_array
  Datasheet.find(:all).map do |ds|
    "{ label: \"#{ds.title}\", category: \"Data Sheets\" }"
  end
end

def brochure_array
  Brochure.find(:all).map do |br|
    "{ label: \"#{br.title}\", category: \"Brochures\" }"
  end
end

def array_for_js
  "[#{(datasheet_array + brochure_array).join(',')}]"
end

Then your Haml can be the much clearer:

:javascript
  $(function() {
      var data = #{array_for_js};

      $( "#search" ).catcomplete({
        delay: 0,
        source: data
      });
  });

Upvotes: 2

Related Questions