This section will lead you through the migration of the address book application from the basic one in the initial app folder to the complete one in the finished app folder.

We will need to do some data modeling in order to update the address book application.  You will be faced with new RDF terms such as vcard:locality to identify a person's city and foaf:phone to identify their phone number.  These terms may look strange at first, but they are very useful because they constitute a social agreement that exists across the Web.  The terms expand to full URIs (e.g. foaf: expands to http://xmlns.com/foaf/0.1/) so you can look them up in their specifications.  Try it :)

Callimachus keeps track of the vocabularies that are used in any RDF data that is uploaded to it.  You can find the list of stored vocabularies in /callimachus/profile?view.

Of course, you don't need to limit yourself to these terms; you can make up your own if you want to.  However, using common vocabularies is a way to help Linked Data applications interlink more easily.  It also helps people new to your application to understand your intent.

If you haven't already, this would be a great time to read the About RDF section in the Callimachus documentation.  That section provides a list of some commonly used RDF vocabularies and discusses what they are good for.  Another good source of commonly used vocabularies is chapter 2 in the book Linked Data: Structured Data on the Web.  That chapter also covers creating your own vocabularies.

Adding More Fields

We will start by updating the Person class's create template.  This will allow us to collect more information about a person when one is created.

The first step is to change the labels for the person's name and description to be more meaningful.  We will add some layout and a birthday field while we are at it.  The table below shows the difference:

First changes to the Person create template
initial app finished app
Initial app - Person create template Finished application - Person create template (partial)

The HTML changes look like this:

initial app finished app

<fieldset class="col-sm-4">
  <div class="form-group">
      <label for="label">Label</label>
      <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required" autofocus="autofocus" />
  </div>
  <div class="form-group">
      <label for="comment">Comment</label>
      <textarea id="comment" class="form-control">{rdfs:comment}</textarea>
  </div>
...
</fieldset>

<div class="row">
  <fieldset class="col-sm-4">
    <legend>Personal</legend>
    <div class="form-group">
      <label for="label">Name (Required)</label>
      <input type="text" class="form-control" id="label" value="{rdfs:label}" required="required" autofocus="autofocus" />
    </div>
    <div class="form-group">
      <label for="comment">Description</label>
      <textarea id="comment" class="form-control">{rdfs:comment}</textarea>
    </div>
    <div class="form-group">
      <label for="bday">Birthday</label>
      <input type="date" class="form-control" id="bday" value="{foaf:birthday}" />
    </div>
  </fieldset>
...
</div>

There is not much magic there. Only three things changed:

  • A <legend> was added to the HTML <fieldset>
  • Two labels were changed:  "Label"->"Name (Required)" and "Comment"->"Description"
  • A birthday field was added.  The birthday field uses the foaf:birthday RDF term.

Most of the new Contact and Social sections in the create template are added in a similar way.  The RDF terms used were:

Field RDF term
Phone foaf:phone
Email foaf:mbox
Street address vcard:street-address
City vcard:locality
State/Region vcard:region
Postal code vcard:postal-code
Country vcard:country-name
Callimachus account foaf:account
FOAF profile page (a URL) foaf:homepage

The most complicated part of the create template is associated with the Person's image:


<div class="form-group">
     <div id="thumbnail" dropzone="link string:text/uri-list" ondrop="return calli.insertResource(event)">
         <label for="thumbnail">Profile Picture <a href="../images/?view" title="Select or upload profile picture" onclick="return calli.selectResource(event)" class="glyphicon glyphicon-picture" /></label>
         <div rel="foaf:depiction">
             <span resource="?thumbnail" typeof="foaf:Image">
                 <img src="{?thumbnail}" style="max-width:100%" />
                 <a href="{?thumbnail}" title="Remove" onclick="return calli.removeResource(event)" class="glyphicon glyphicon-remove" />
             </span>
         </div>
     </div>
</div>

There are a number of things going on in this block of code, but you don't need to master them all now.  For now, notice that there is a JavaScript onclick() handler for the image upload link.  The JavaScript for that is provided by Callimachus, so this is just a pattern you can reuse.  There is another handler that allows you to remove an image after it is added.

Creating Concepts 

There is only one part of the finished app's create template that we haven't covered yet:  The select (pulldown) menu indicating a person's online status.  That select widget is dynamically populated with a list of items.  We commonly create lists of items in Callimachus using concepts.

Formally, concepts in Callimachus are SKOS Concepts.  You don't need to know that for the purposes of this tutorial, but you might want to know it later.

To create the concepts you will need for the status select widget:

  1. Go to the initial app directory.
  2. Create a folder called "concepts" with a subfolder called "status" using the Create menu on the folder view. The status folder will contain all concepts related to a person's status, or availability.
  3. Create three separate concepts within the status folder (you will only need to fill out the "Label" field in the New Concept form, although you can experiment with the others):
    1. Available
    2. Busy
    3. Away
  4. Note the file path in which these concepts are saved as they will be needed in the next step.

Remember that you can always look in the finished app folder tree to see what we intended if you get lost.

Linking Concepts to Templates via HTML Form Controls

The status component defines a directly connected property to the new Person (foaf:status) and a nested property (calli:hasComponent) that must come from a pre-defined list of values.  The list of acceptable values in located in the app/concepts/status/ folder.  Each acceptable status is a SKOS Concept created in Callimachus using the Create menu option called Concept.  Try making your own status types by adding new ones to that folder!  They will show up in the create template's status pull down menu.

Now that the concepts have been created they can be included in create and edit templates in order to create an association between an instance of the Person class and the concepts. To create this connection:

  1. Insert a <select> element into both the create and edit template of the Person class. Make sure to include the appropriate RDFa as detailed below in order to establish the relationship.
HTML Code HTML Rendered

<div class="form-group">
    <label for="status">Status</label>
    <select id="status" rel="foaf:status" class="form-control">
        <option selected="selected" about="?status" rev="calli:hasComponent" 
                resource="../concepts/status/" property="skos:prefLabel" />
    </select>
</div>

For more information see the full documentation on selection patterns

Wrap Up & Review

Whether you're adding a simple text field or or a custom controlled vocbulary selection the process is the same. The RDFa must create the appropriate relationship between the two resources via particular markup. It is important to note here that this markup can live in either the create template, the edit template, or both. Some workflows may call for the ability to create a piece of data the first time that is no longer editable, or for more options to be available only after a resource is first created. This is easily achieved with the separation of the create and edit templates. In the same vein, not all data has to be surfaced in the view template. Some data can be used for other queries or analytics and never shown to the end user.