Skip to content

Autocomplete Examples using QA

E. Lynette Rayle edited this page Mar 8, 2019 · 2 revisions

Overview

These represent multiple examples using QA with autocomplete. These examples may be dated. It is best to see the documentation for the individual projects in which the autocomplete will be used for the most upto date examples.

Hyrax with jQueryUI >= 1.8

See Hyrax Autocomplete documentation in the samvera/hyrax project for latest recommendations on adding autocompletes to Hyrax.

If you are using jQueryUI >= 1.8 you can use the autocomplete function, for example:

  $(function(){
    $('#some_input').autocomplete({
      source: function (request, response) {
        $.ajax({
          url: "/qa/search/loc/subjects?q=" + request.term,
          type: 'GET',
          dataType: 'json',
          complete: function (xhr, status) {
            var results = $.parseJSON(xhr.responseText);
            response(results);
          }
        });
      },
      autoFocus: true
    });
  });

Sufia 7

One time prep

// Setup assets javascript for autocompletion
mkdir Rails.root/app/assets/javascript/sufia
mkdir Rails.root/app/assets/javascript/sufia/autocomplete

// Copy Sufia.js file from Sufia branch to rails app
cp SUFIA_DIR/app/assets/javascripts/sufia.js Rails.root/app/assets/javascripts/Sufia.js

// Add sufia.js file to add require statement to include autocomplete file
// After //= require sufia/autocomplete/language add
//  //= require sufia/autocomplete/keywords

Add javascript to support autocomplete

Assumes the property name is keywords.

Create a keywords.es6 (Ecmascript6) file in Rails.root/app/assets/javascripts/sufia/autocomplete It should look like this:

export class Keywords {
  constructor(element, url) {
    this.url = url
    element.autocomplete(this.options());
  }

  options() {
    return {
      minLength: 2,
      source: (request, response) => {
        $.getJSON(this.url, {
          q: request.term
        }, response );
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      complete: function(event) {
        $('.ui-autocomplete-loading').removeClass("ui-autocomplete-loading");
      }
    };
  }
}

Copy the autocomplete.es6 file from the Sufia branch to the Rails app

cp SUFIA_DIR/app/assets/javascripts/sufia/autocomplete.es6 Rails.root/app/assets/javascripts/sufia/autocomplete.es6

Edit the autocomplete.es6 file to include the keywords functions. It should look like this:

_NOTE: Only the portions of the code that reference keywords were added. Language and subjects are examples of other autocompleted vocabulary fields.

export class Autocomplete {
  constructor() {
  }

  // This is the initial setup for the form.
  setup() {
      $('[data-autocomplete]').each((index, value) => {
          let selector = $(value)
          switch (selector.data('autocomplete')) {
            case "subject":
              this.autocompleteSubject(selector);
              break;
            case "language":
              this.autocompleteLanguage(selector);
              break;
            case "based_near":
              this.autocompleteLocation(selector);
              break;
            case "keywords":
              this.autocompleteKeywords(selector);
              break;
          }
      });
  }

  // attach an auto complete based on the field
  fieldAdded(cloneElem) {
    var $cloneElem = $(cloneElem);
    // FIXME this code (comparing the id) depends on a bug. Each input has an id and
    // the id is duplicated when you press the plus button. This is not valid html.
    if (/_based_near$/.test($cloneElem.attr("id"))) {
        this.autocompleteLocation($cloneElem);
    } else if (/_language$/.test($cloneElem.attr("id"))) {
        this.autocompleteLanguage($cloneElem);
    } else if (/_subject$/.test($cloneElem.attr("id"))) {
        this.autocompleteSubject($cloneElem);
    }  else if (/_keywords$/.test($cloneElem.attr("id"))) {
         this.autocompleteKeywords($cloneElem);
    }
  }

  autocompleteLocation(field) {
      var loc = require('sufia/autocomplete/location');
      new loc.Location(field, field.data('autocomplete-url'))
  }

  autocompleteSubject(field) {
      var subj = require('sufia/autocomplete/subject');
      new subj.Subject(field, field.data('autocomplete-url'))
  }

  autocompleteLanguage(field) {
      var lang = require('sufia/autocomplete/language');
      new lang.Language(field, field.data('autocomplete-url'))
  }

  autocompleteKeywords(field) {
      var keywords = require('sufia/autocomplete/keywords');
      new keywords.Keywords(field, field.data('autocomplete-url'))
  }
}

Create a custom edit field for the form element which will use the QA autocomplete Create file Rails.root/app/views/records/edit_field/_keywords.html.erb with the following text

<%= f.input key,
   as: :multi_value,
   input_html: {
      class: 'form-control',
      data: { 'autocomplete-url' => "/qa/search/linked_data/agrovoc?q=",
              'autocomplete' => key }
      },
required: f.object.required?(key) %>

_NOTE: You will want to replace the autocomplete-url with the url for the qa vocabulary you are using.


Sufia 6

One time prep

Create file app/javascripts/sufia/file_vocabularies.js

Add javascript to support autocomplete

NOTE: Examples assume the field name is generic_file_corporate_name. Method names include CorporateName. This convention allows multiple fields to use autocomplete.

For a single value field...

In app/javascripts/sufia/file_vocabularies.js, add initializer method to onLoad function.

onLoad: function() {
    this.setInitialCorporateNameAutocomplete();
},

# called when page loads to add autocomplete to field with generic_file_corporate_name id
setInitialCorporateNameAutocomplete: function() {
  $('#generic_file_corporate_name').autocomplete({
    minLength: 3,
    source: function (request, response) {
      $.ajax({
        url: '/qa/search/linked_data/oclc_fast_all?q=' + request.term + '&maximumRecords=5',
        type: 'GET',
        dataType: 'json',
        complete: function (xhr, status) {
          var results = $.parseJSON(xhr.responseText);
          response(results);
        }
      });
    }
  })
},

For a multiple value field...

onLoad: function() {
    this.setEventOnAddButton("all");
    this.setInitialCorporateNameAutocomplete();
},

# called when page loads to add autocomplete to all fields with generic_file_corporate_name id
setInitialCorporateNameAutocomplete: function() {
$('input.generic_file_corporate_name').each(function () {
   $(this).autocomplete({
      minLength: 3,
      source: function (request, response) {
         $.ajax({
            url: '/qa/search/linked_data/oclc_fast_all?q=' + request.term + '&maximumRecords=5',
            type: 'GET',
            dataType: 'json',
            complete: function (xhr, status) {
               var results = $.parseJSON(xhr.responseText);
               response(results);
            }
         });
      }
   })
},

# called when Add button is clicked to add autocomplete to all fields with generic_file_corporate_name id AND
# call setEventOnAddButton to add javascript to call this method to all Add buttons associated with generic_file_corporate_name 
initCorporateNameAutocomplete: function() {
   $('input.generic_file_corporate_name').each(function() {
      $(this).autocomplete({
         minLength: 3,
         source: function(request, response) {
            $.ajax({
               url: '/qa/search/linked_data/oclc_fast_all?q=' + request.term + '&maximumRecords=3',
               type: 'GET',
               dataType: 'json',
               complete: function(xhr, status) {
                  var results = $.parseJSON(xhr.responseText);
                  response(results);
               }
            });
         }
      })
   })
   setFileVocabularies.setEventOnAddButton("corporate_name");
},


# called when page loads and from initCorporateNameAutocomplete when Add button is clicked to make all Add buttons including 
# the new one for all generic_file_corporate_name fields call function initCorporateNameAutocomplete when an Add button for 
# this field is clicked
setEventOnAddButton: function(target) {
  $('button.add').each(function() {
    if ( target == "corporate_name" || target == "all" ) {
      if ( $(this).closest('div').attr('class').indexOf('generic_file_corporate_name') >= 0 ) {
        $(this).click(function() {
          setTimeout(setFileVocabularies.initCorporateNameAutocomplete,500);
        })
      }
    }
  })
},

To add autocomplete to a second multi-valued field, duplicate setInitialCorporateNameAutocomplete and initCorporateNameAutocomplete. Modify CorporateName, generic_file_corporate_name, and corporate_name to be consistent with the new autocomplete field. Also, extend setEventOnAddButton function to duplicate the if ( target... ) block and change the target "corporate_name" to be consistent with the new autocomplete field.

NOTE: This javascript was tested in a Sufia 6 app. Additional configuration is required to add a field to a Sufia app. See Sufia's documentation for more information on that process.

Clone this wiki locally