search-lookup

Search lookup module

This is a search input module with autosuggest. At its heart, it lets you search by name, but optionally you can make a call to the Location Services API and enable search by full or partial postcode.

Dependencies

news-vj-search-lookup has 2 hard dependencies, which are automatically included in the module:

Usage

JavaScript

import SearchLookup from '@bbc/news-vj-search-lookup';
import data from './data.json';

new SearchLookup({
    input: '#news-vj-search-lookup__input', // id of the input field
    data:  data, // local lookup data - see next section
    minChars: 2, // the minimum number of chars to enter before the autocomplete suggestions list appears
    vocab: { // internationalised interface text
        language: 'english',
        search_error: "Sorry, we don't recognise this location. Please enter a UK postcode, council name or NI constituency",
        search_screenreader_autosuggest_help: " results are available, use up and down arrow keys to navigate.",
    },
    searchForPostcodes: true, // should be able to search by full postcode
    searchForPartialPostcodes: true, // should be able to search by partial postcode. Note that `searchForPostcodes` can't be false if this is true!
    fullPostcodeLimit: 3, //sets the number of autosuggest results for full postcode searches to 3, default value is 1
    partialPostcodeLimit: 5, //sets the number of autosuggest results for partial postcode searches to 5, default value is 5
    searchType: 'gss-health', // default: 'gss-council', other options: 'gss-seat', etc. This can either take a string or callback function
    clearInput : false, // defaults to true, automatically clears the input element after submission
    /**
     * Function called once result is chosen.
     * @optional
     */
    onSelect: function (gssid, data) {
        document.getElementById('results').innerHTML = `Results for ${data.name}`;
    },
    /**
     * Manipulate results before they're displayed to the user. Add/remove/rename etc.
     * @optional
     */
    overrideResults: function (results, query) {
        return results;
    },
    /**
     * Function called after Ajax response is processed.
     * You may want to resize your iframe or something here
     * Suggestions is an array containing the results.
     * @optional
     */
    onSearchComplete: function (query, suggestions) {},
    /**
     * Function called when input is altered after selection has been made. Useful for resetting.
     * @optional
     */
    onInvalidateSelection: function () {},
    /**
     * Determines whether or not to apply `op=intersect` to the Location Services request.
     * Bespoke endpoints (e.g. `nhs-trust`) can have strange behaviour if `op=intersect` is applied.
     * Defaults to `true` (no checking)
     * @param postcode: string
     * @return boolean
     * @optional
     */
    intersectCallback: function (postcode) {
        return true;
    },
    /**
     * Location Services sometimes return an array of results, only one of which is the type of thing we want. So we can run a check against the GSSID.
     * Defaults to `true` (no checking)
     * @param entityCode: string
     * @return boolean
     * @optional
     */
    entityCodeValidates: function (entityCode) {
        return true;
    },
});

news-vj-search-lookup requires that you provide local lookup data in the following format (it won't work independently of this):

{
    "E07000223": {
        "name": "Adur",
        // you can have as many other properties as you like,
        // but you NEED the GSSID and the name
    }
}

CSS

Include the SASS in your main SASS file, i.e.:

@import '../../node_modules/@bbc/news-vj-search-lookup/lookup/lookup';

HTML

Include the Handlebars template in your HTML, and optionally, a label. i.e.:

{{>search-lookup
    label="Enter your search in the field below"
    standalone-form=true
    search_placeholder="Start typing to search"
    search_submit_text="Search for counties"
    id="news-vj-search-lookup__input"
}}

The label property is optional. If you omit it, you must create a label outside the module, and make sure its for attribute matches the id property you used for the lookup, e.g.

<label for="news-vj-search-lookup__input">SearchLookup</label>

Using Synonyms

In order to use synonyms in the lookup module, you would need to include a synonyms column in your dataset (e.g. search_alternative).

{
    "E07000223": {
        "name": "Adur",
        "search_alternative": "USA"
        //does not have to be straight after the name property
    }
}

The example below shows how you can incorporate the synonyms column into the lookup.

    function prepareSynonyms(data) {
        const keys = Object.keys(data); // returns an array of keys for the data object
        for (let i = 0; i < keys.length; i++) {
            const val = data[keys[i]];
            const separator = ',';
            if (val.search_alternative) {
                val.synonyms = val.search_alternative.split(separator);
                delete val.search_alternative;
            }
        }
        return data;
    }

Changing searchType

To change the default searchType you would need to create a function that passes the user input. An example of this is shown in the code below.

    new SearchLookup({
        input: '#news-vj-search-lookup__input',
        data: data,
        searchType: function (query) {
            var query = query.toUpperCase(); //the regex only recognises uppercase characters
            if (query.match(/^BT/)) { // query is compared to the regex for a NI postcode
                return 'gss-seat';
            }
            else {
                return 'gss-council';
            }
        },
    });

Run the tests

Install dev dependencies: npm i

You'll also need Phantom installed:

brew install phantomjs

And bundler:

gem install bundler

Install gems:

bundle install

Compile CSS/HTML: grunt

Run the server: npm start

(You can now visit http://www.local.bbc.co.uk:8080)

Not all functionality has been implemented yet (i.e. if we run all of our scenarios, some will fail) - so we only want to run the scenarios for which we have completed the functionality:

npm test, which is an alias for: bundle exec cucumber --tags ~@todo

You can of course run individual features:

bundle exec cucumber features/Lookup_Postcode.feature --tags ~@todo

Or individual scenarios:

bundle exec cucumber features/Lookup_Postcode.feature:33