Skip to content
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Build Status

Warning: We do not plan to maintain this library

As of December 2018 we do not plan to maintain this library and it does not reflect the latest version of the code we use on our production systems. Please contact us if you have any questions about this.


A cljs dataview from Ona.


This library is a work-in-progress to package up much of the dataview used in Ona's new product. It provides a set of Om components that can be used to visualize a dataset that has a schema attached to it.


Install via clojars with:

Clojars Project

Terminology used below:

  • data is a vector of records
  • flat-form is a vector of fields
  • Each field is a map, containing keys name, type, full-name, label at the very least.
  • fields with type repeats are special; we will not go into detail about them for now.
  • Each record is also a map. Each key in a record should correspond to the full-name of some field.

General overview of state, shared-state, etc.

app-state has the following structure:

   {:data []
   :map-page {:submission-clicked {:data nil}
              :geofield {}}
    :table-page {:submission-clicked {:data nil}}
    :chart-page {:visible-charts []
                 :chart-data {}}
    :dataset-info {}
    :languages {:current nil :all []}}

The meaning of the state is as follows:

  • :data should be all of the data for this dataset. A list of records, each record being a submission.
  • :dataset-info is what is available via the /forms/ endpoint. Inside here, there should be things like form metadata, num_of_submissions and instances_with_geopoints, enketo_url, enketo_preview_url and such.
  • languages stores the set of languages labels in this form are written in inside of :all, the currently selected language (default English) is store in :current. This part of the app-state is used by the reference cursor language-cursor.
  • :map-page, :table-page, and :chart-page contain the state necessary for each of those pages.
    • :submission-clicked stores data about the record which is clicked.
    • visible-charts is the list of all charts that the user has called up on this page. chart-data is a map that stores the raw chart API data for all of the fields that the user has requested charts on.

User has the responsibility of updating :data, :dataset-info and :flat-form by fetching them; the utility flatten-form is available to convert what you get from Ona into a flat form..

Note: for speed of decoding, it is assumed for now that the keys for data are plain strings, not keywords. data is exceptional in this way; other maps are expected to contain plain clojure(script) keywords.

shared-state needs:

  {:flat-form []
   :view-type :ona-default}

exposed cursors:


To render the dataview into your application, you'll need something like the following. The app-state can be updated once constructed, and generally the right thing will happen. Shared state cannot be updated.

(om/root tabbed-dataview
          {:target ...
           :shared {:flat-form _your-form_
                    :view-type _your-view-type_}})

(Future: flat-form will be moved to app-state, since it does need to be updated sometimes).

Component Hierarchy

  • tabbed-dataview
    • dataview-infobar
    • map-page (cursor: map-page, dataset-info)
      • map-and-markers (cursor: map-page)
      • geofield-chooser (cursor: map-page geo-field)
      • view-by-legend (cursor: map-page view-by, dataset-info)
        • view-by-menu (cursor: dataset-info)
        • view-by-answer-legend (cursor: view-by)
      • submission-legend (cursor: map-page geo-field, map-page submission-clicked)
        • single-submission/submission-view
    • table-page
      • label-changer (cursor: nil, works on shared cursor language-cursor
      • single-submission/submission-view
    • chart-page
      • chart-chooser (cursor: nil)
      • list-of-charts (cursor: chart-page)
        • single-chart (cursor: chart-page chart-data >element)
    • settings-page (cursor: dataset-info)
      • (settings-page will be super basic; it will just display the name / description / active-inactive status, and not allow for any editing of data)

Hatti structure (proposal)

Hatti will primarily provide a set of Om components that are meant to be used in a dataview such as Zebra. All of Hatti's Om components should be over-rideable, you should be able to over-ride any of the Internal Hatti components easily and have a new dataview that incorporates such over-riding. As such, here is the basic proposal for how Hatti's components should be written:

Components in Hatti should be multi-methods. By default, the dispatch value will be :view-type [1] stored in the application shared state.

(defmulti map-page
  (fn [_ owner & _]
    (om/get-shared owner :view-type)))

(defn map-page :ona-default
  [cursor owner]
  ; actual map-page definition

This will allow any user to include the map-page in their view. Now say that they want to change the way the map view-by menu is rendered. They would do this by providing a value to correspond to ::view-type in the om/root call, and then overriding whatever component or subcomponent they want implemented differently.

(derive :my-view :ona-default)
(om/root map-page atom {:target ...
                        :shared {:view-type :my-view}})
(defn view-by-menu :my-view
  [cursor owner]
  ; the view-by-menu definition specific to :my-view

There may be some components which also need some special treatment within other views, eg. a submission-view which is different for the map and the table page. These should be implemented as multi-methods with a different dispatch function that still incorporates the shared ::view-type, An example could be:

(defmulti single-submission-view
  (fn [cursor owner & _]
    [(om/get-shared owner :view-type) (-> cursor :selected-view)]))
(defmethod single-submission-view [:ona-default :map]
  (fn [cursor owner opts]
(defmethod single-submission-view [:ona-default :table]
  (fn [cursor owner opts]

[1] - It will actually be the namespace-qualified ::view-type, but I need to do a bit more research to figure out how to use it properly.


Hatti is released under the Apache 2.0 License.

You can’t perform that action at this time.