Overview

In this chapter we will explore four patterns for making data selection easier:

Large Hierarchical Selection

Intent

To choose from a large set of finite possible concepts.

Motivation

When categorizing resources the number of categorizes is often too large for a flat list and requires the ability to browse through possible concepts.

Applicability

Use for object relationships that have a large set of finite possible objects.

Implementation

Create a single top concept with skos:narrower and skos:related of the hierarchical concepts that are valid objects for this relationship. The user will be able to navigate among the concepts using broader and narrower relationships. When the user navigates to the concept they want they can click the select button.

Sample Code


<div id="medium" class="form-group" ondrop="calli.insertResource(event)">
 <label>Medium <a href="/scheme/medimus/top" title="Browse Mediums"
     onclick="calli.selectResource(event)" class="glyphicon glyphicon-folder-open" /></label>
  <div rel="dcterms:medium">
   <span resource="?medium" typeof="skos:Concept" class="label label-info">
     <span property="skos:prefLabel" />
     <a href="{?medium}" title="Remove relationship" onclick="calli.removeResource(event)" class="glyphicon glyphicon-remove" />
   </span>
 </div>
</div>

Limited Selection

Intent

To provide the user with a small set of possible relations to choose from.

Motivation

Some relationships are limited to small set of target objects, that are curated separately. For this it is important to provide the user with a list of possible selections inline.

Applicability

Use when the number of possible target objects in a relationship is limited, doesn't change often, and can be shown to the user all together.

Implementation

Create a folder containing the concepts that should be presented to the user. Use the calli:hasComponent relationship from the folder to the concepts in an RDF Named Query to select the possible set.

Within an edit template page, add XInclude directive of the ?radio pragma as shown below.

Sample Code


# mediums-list.rq
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX calli:<http://callimachusproject.org/rdf/2009/framework#>

SELECT ?concept ?label {
    </scheme/mediums/> calli:hasComponent ?concept .
    ?concept skos:prefLabel ?label
} ORDER BY ?label

Horizontal radio buttons are best used when the relationship is functional (only one object) and the concepts can be listed in a single line.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?radio&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

Horizontal checkboxes are best used when the relationship is non-functional (can have multiple objects) and the concepts can be listed in a single line.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?checkbox-inline&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

Vertical checkboxes is best used when the relationship is non-functional (can have multiple objects) and all concepts should visible to the user at once.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label>Medium</label>
  <xi:include href="mediums-list.rq?checkbox&amp;rel=dcterms:medium&amp;name=medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.checkEachResourceIn('#medium')).remove();
  </script>
</div>

Range Relationships

Intent

Allow the user to lookup or create resources by type.

Motivation

Many relationships between resources are open ended, requiring only particular resource types. The user may link to a large possible set of objects or create a new one.

Applicability

Use for object relationships that have a open ended set of possible objects.

Implementation

Use the selectize.js library, integrated into Callimachus, to create an auto-complete input. The @rel/@resource will be used to populate existing entries in edit forms, while the calli.updateResource call will establish the relationship for new entries. Create an RDF Named Query to search for existing resource. Use the function calli.createResource to create new resources in a modal dialogue.

Sample Code


<div class="form-group">
  <label>Knows</label>
  <select id="knows" class="form-control" multiple="multiple"
      onchange="calli.updateResource(event,'foaf:knows')">
    <option selected="selected" rel="foaf:knows" resource="?knows" value="{?knows}">{foaf:name}</option>
  </select>
</div>

# person-search.rq
PREFIX foaf:<http://xmlns.com/foaf/0.1/>

SELECT ?resource ?label {
    ?resource a foaf:Person; foaf:name ?label
    FILTER regex(?label, "$q")
} ORDER BY ?label LIMIT 100

$('#knows').selectize({
    load: function(query, callback) {
        if (!query) return callback();
        var url = 'person-search.rq?results&tqx=out:sparql-json&q=' + encodeURIComponent(query));
        calli.getJSON(url).then(function(json){
            return json.results.bindings.map(function(bindings){
                return {
                    value: bindings.resource.value,
                    text: bindings.label.value
                };
            });
        }).then(callback, function(error){
            callback();
            return calli.error(error);
        });
    },
    create: function(label, callback) {
        calli.headText(calli.slugify(label)).then(function(){
            return calli.slugify(label); // already exists
        }, function(xhr) {
            if (xhr.status != 404) return calli.reject(xhr);
            return calli.createResource('#knows', './?create=Person');
        }).then(function(resource){
            return resource && {
                value: resource,
                text: resource.replace(/.*\//,'')
            };
        }).then(callback, function(error){
            callback();
            return calli.error(error);
        });
    }
});

You may need to change the path of person-search.rq and the Person class to match your folder structure.

Scroll Through Selection

Intent

To provide the user with a limited set of possible relations to choose from.

Motivation

Some relationships are limited to a set of target objects, that are curated separately. For this it is important to provide the user with a list of possible selections to choose from.

Applicability

Use when the number of possible target objects in a relationship is limited and small enough that the user can scroll quickly through all of them.

Implementation

Create a folder containing the enumerated concepts that should be presented to the user. Use the calli:hasComponent relationship from the folder to the concepts to link all possible relationships.

Within a edit template page, add one of the following markup patterns.

Sample Code


# mediums-list.rq
PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
PREFIX calli:<http://callimachusproject.org/rdf/2009/framework#>

SELECT ?concept ?label {
    </scheme/mediums/> calli:hasComponent ?concept .
    ?concept skos:prefLabel ?label
} ORDER BY ?label

Drop down list is best used when the relationship is functional (only one object) and the list of concepts should be hidden by default.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label for="medium">Medium</label>
  <xi:include href="mediums-list.rq?select&amp;rel=dcterms:medium&amp;id=medium" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.selectEachResourceIn('#medium')).remove();
</div>

Select box is best used when the relationship is non-functional (can have multiple objects) and the user should be able to scroll through the list of concepts.


<div xmlns:dcterms="http://purl.org/dc/terms/" class="form-group">
  <label for="medium">Medium</label>
  <xi:include href="mediums-list.rq?select&amp;rel=dcterms:medium&amp;id=medium&amp;multiple=multiple" />
  <div rel="dcterms:medium" resource="?medium" />
  <script type="text/javascript">
    $('div[rel="dcterms:medium"]').filter(calli.selectEachResourceIn('#medium')).remove();
</div>