Proposing results from a remote API

This documentation is optionnal, but it is complementary with all other documentation. It aims advanced users.

Consider a social network about music. In order to propose all songs in the world in its autocomplete, it should either:

  • have a database with all songs of the world,
  • use a simple REST API to query a database with all songs world

The purpose of this documentation is to describe every elements involved. Note that a living demonstration is available in test_remote_project, where one project serves a full database of cities via an API to another.

Example

In test_remote_project/remote_autocomplete, of course you should not hardcode urls like that in actual projects:

from cities_light.contrib.autocompletes import *

import autocomplete_light


autocomplete_light.register(Country, CountryRestAutocomplete,
    source_url='http://localhost:8000/cities_light/country/')

autocomplete_light.register(Region, RegionRestAutocomplete,
    source_url='http://localhost:8000/cities_light/region/')

autocomplete_light.register(City, CityRestAutocomplete,
    source_url='http://localhost:8000/cities_light/city/')

Check out the documentation of RemoteCountryChannel and RemoteCityChannel for more.

API

Javascript fun

Channels with bootstrap=’remote’ get a deck using RemoteChannelDeck’s getValue() rather than the default getValue() function.

var RemoteAutocompleteWidget = {
    /*
    The default deck getValue() implementation just returns the PK from the
    choice HTML. RemoteAutocompleteWidget.getValue's implementation checks for
    a url too. If a url is found, it will post to that url and expect the pk to
    be in the response.

    This is how autocomplete-light supports proposing values that are not there
    in the database until user selection.
    */
    getValue: function(choice) {
        var value = choice.data('value');

        if (typeof(value)=='string' && isNaN(value) && value.match(/^https?:/)) {
            $.ajax(this.autocompleteOptions.url, {
                async: false,
                type: 'post',
                data: {
                    'value': value
                },
                success: function(text, jqXHR, textStatus) {
                    value = text;
                }
            });

            choice.data('value', value);
        }

        return value;
    }
}

$(document).bind('yourlabsWidgetReady', function() {
    // Instanciate decks with RemoteAutocompleteWidget as override for all widgets with
    // autocomplete 'remote'.
    $('body').on('initialize', '.autocomplete-light-widget[data-bootstrap=rest_model]', function() {
        $(this).yourlabsWidget(RemoteAutocompleteWidget);
    });
});