main menu

Creating Custom Views

The sol-query component creates a model using SPARQL or triple patterns and then renders the model in a view. In addition to the built-in views shown on the sol-query page (table,rolodex,etc.), users can specify a URL in the view attribute. The URL should be a a javascript file that has the model as input to an exported render function.

The render function

If the view attribute specifies a URL, it should point to a valid ESm module that exports a render function. The function receives:

Data shape

The data argument is the W3C SPARQL 1.1 Query Results JSON envelope:

{
  head: {
    vars: string[]           // column names, e.g. ['name', 'age'] or ['p', 'o']
  },
  results: {
    bindings: Array<{        // one object per result row
      [colName]: {
        type:    'uri' | 'literal' | 'bnode',
        value:   string,     // the string value
        'xml:lang'?: string, // language tag on literals (when present)
        datatype?:   string  // datatype IRI on literals (when present)
      }
    }>
  }
}

Example renderer

What the user sees:

The HTML that combines the model with a custom view:

<sol-query
  endpoint="https://dbpedia.org/sparql"
  sparql="../data/myQueries#TimAdaQuery"
  view="../data/card-renderer.js"
></sol-query>

The custom view's render function ::

export function render(container, data) {
  const vars     = data.head.vars;
  const bindings = data.results.bindings;

  const shorten = v => v?.value
    ? v.value.replace(/.*[/#]([^/]+)\/?$/, '$1') || v.value
    : '';

  const grid = document.createElement('div');
  grid.style.cssText = 'display:flex;flex-wrap:wrap;gap:.75rem;padding:.5rem 0';

  bindings.forEach(row => {
    const card = document.createElement('div');
    card.style.cssText = 'border:1px solid #ddd;border-radius:6px;padding:.75rem 1rem;…';

    vars.forEach(v => {
      const cell = row[v];
      if (!cell?.value) return;
      const line = document.createElement('div');
      // label
      const label = document.createElement('span');
      label.textContent = v + ':';
      line.appendChild(label);
      // value
      if (cell.type === 'uri') {
        const a = document.createElement('a');
        a.href = cell.value;
        a.textContent = shorten(cell);
        line.appendChild(a);
      } else {
        line.appendChild(document.createTextNode(cell.value));
      }
      card.appendChild(line);
    });

    grid.appendChild(card);
  });

  container.appendChild(grid);
}