Improve this doc View source

# ``

## SPARQL Faceter - Client-Side Faceted Search Using SPARQL

The module provides a set of directives that work as facets, and a service that synchronizes them.

There are four different built-in facet types:

- `secoBasicFacet` - A basic select box facet with text filtering
- `secoHierarchyFacet` - A basic facet with hierarchy support.
- `secoTextFacet` - A free-text facet.
- `secoJenaTextFacet` - A free-text facet that uses Jena text search.
- `secoTimespanFacet` - Date range facet.

Custom facets can be implemented reasonably easily.

### How it works

Facets are implemented as a directives. Each facet listens on its scope for changes in other facets, and emits its state when its value changes. The facets are responsible for maintaining their own state. In the following, "constraint" means a triple pattern that narrows the resultset down based on a facet value.

`FacetHandler` mediates the facet changes by listening to the facets' change events, and broadcasting the resulting constraints to all facets in the scope.

The facets are configured using the `options` attribute of the directive. Configuration options that are common to all facets are:

- facetId - `{string}` - A friendly id for the facet. Should be unique in the set of facets, and should be usable as a SPARQL variable.
- predicate - `{string}` - The predicate or property path that defines the facet values.
- name - `{string}` - The title of the facet. Will be displayed to end users.
- enabled `{boolean}` - Whether or not the facet is enabled by default.
- priority `{number}` - When the `FacetHandler` broadcasts the constraints, it sorts them based on each facet's priority value (if it is defined), in ascending order. This can be used for better query caching, or to optimize the order of constraints. For most facets, this value is undefined by default. `secoJenaTextFacet` has a default priority of 10 (so it will always be the first constraint by default).

For other options, see the facets' individual documentation.

To make use of the constraints generated by the facets, a controller should listen for the update event `sf-facets-changed` (and possibly for the initial `sf-initial-constraints`). The argument sent with the event is an objectfollowing fields:

- constraint - `{Array}` - The constraints as generated by all the facets, plus any initial constraints (see `FacetHandler`).
- facets - `{Object}` - A collection of facet states where the key is the `facetId` of the facet, and value is the state as emitted by that facet. Presumably, when using the built-in facets, you would not be interested in these values.

## Example

Setup in the controller:

    var vm = this;

    // Define facets
    vm.facets = {
        // Text facet
        name: {
            name: 'Name',
            facetId: 'name',
            predicate: '<http://www.w3.org/2004/02/skos/core#prefLabel>',
            enabled: true
        },
        // Date facet
        deathDate: {
            name: 'Time of Death',
            facetId: 'death',
            startPredicate: '<http://ldf.fi/schema/narc-menehtyneet1939-45/kuolinaika>',
            endPredicate: '<http://ldf.fi/schema/narc-menehtyneet1939-45/kuolinaika>',
            min: '1939-10-01',
            max: '1989-12-31',
            enabled: true
        },
        // Basic facet
        profession: {
            name: 'Ammatti',
            facetId: 'occupation',
            predicate: '<http://ldf.fi/schema/narc-menehtyneet1939-45/ammatti>',
            enabled: true
        },
        // Basic facet with property path
        source: {
            name: 'Source',
            facetId: 'source',
            predicate: '^<http://www.cidoc-crm.org/cidoc-crm/P70i_is_documented_in>/<http://purl.org/dc/elements/1.1/source>',
            enabled: true
        },
        // Basic facet with labels in another service.
        birthMunicipality: {
            name: 'Birth Municipality',
            services: ['<http://ldf.fi/pnr/sparql>'],
            facetId: 'birthplace',
            predicate: '<http://ldf.fi/schema/narc-menehtyneet1939-45/synnyinkunta>',
            enabled: false
        },
        // Hierarchical facet
        rank: {
            name: 'Rank',
            facetId: 'rank',
            predicate: '<http://ldf.fi/schema/narc-menehtyneet1939-45/sotilasarvo>',
            hierarchy: '<http://purl.org/dc/terms/isPartOf>*|(<http://rdf.muninn-project.org/ontologies/organization#equalTo>/<http://purl.org/dc/terms/isPartOf>*)',
            enabled: true,
            classes: [
                '<http://ldf.fi/warsa/actors/ranks/Upseeri>',
                '<http://ldf.fi/warsa/actors/ranks/Aliupseeri>',
                '<http://ldf.fi/warsa/actors/ranks/Miehistoe>',
                '<http://ldf.fi/warsa/actors/ranks/Jaeaekaeriarvo>',
                '<http://ldf.fi/warsa/actors/ranks/Virkahenkiloestoe>',
                '<http://ldf.fi/warsa/actors/ranks/Lottahenkiloestoe>',
                '<http://ldf.fi/warsa/actors/ranks/Muu>'
            ]
        }
    };

    // Define common options
    vm.options = {
        scope: $scope,
        endpointUrl: 'http://ldf.fi/warsa/sparql',
        rdfClass: '<http://ldf.fi/schema/narc-menehtyneet1939-45/DeathRecord>',
        constraint: '?id skos:prefLabel ?name .',
        preferredLang : 'fi'
    };

    // Define a function that handles updates.
    // 'dataService' is some service that fetches results based on the facet selections.
    function updateResults(event, facetState) {
        dataService.getResults(facetState.constraints).then(function(results) {
            vm.results = results;
        }
    }

    // Listen for the update event
    $scope.$on('sf-facet-constraints', updateResults);

    // Listen for initial state
    var initListener = $scope.$on('sf-initial-constraints', function(event, state) {
        updateResults(event, state);
        // Only listen once for the init event
        initListener();
    });

    // Initialize the facet handler:
    vm.handler = new FacetHandler(vm.options);

Setup the facets in the template:

    <seco-text-facet
      data-options="vm.facets.name">
    </seco-text-facet>
    <seco-timespan-facet
      data-options="vm.facets.deathDate">
    </seco-timespan-facet>
    <seco-basic-facet
      data-options="vm.facets.source">
    </seco-basic-facet>
    <seco-basic-facet
      data-options="vm.facets.profession">
    </seco-basic-facet>
    <seco-basic-facet
      data-options="vm.facets.birthMunicipality">
    </seco-basic-facet>
    <seco-basic-facet
      data-options="vm.facets.principalAbode">
    </seco-basic-facet>
    <seco-hierarchy-facet
      data-options="vm.facets.rank">
    </seco-hierarchy-facet>