Tutorial: Seattle video breakdown (2018 September)

Each segment is less than 60s, broken down second by second in bullets, 8m40s total.

Table of contents


Task: Make a new fiddle, give it a query
Use the video slider to control time, if it is too fast you can also adjust playback rate.
  • Go to http://tank.hyperfiddle.net/ and log in
  • Make a new fiddle with the new button in the toolbar.
  • Read the tooltip on :fiddle/ident to see the docstring and that it is a keyword
  • Please namespace your fiddles with your username since the tank is a shared environment.
  • You will redirect to this new fiddle. The fiddle/ident is in the URL.
  • Inspect the fiddle source with the src link in the toolbar
  • Set the :fiddle/type to :query. Stop and read the tooltip!
  • Change the :fiddle/query: add :neighborhood/name to the where clause.
  • BUG: If you get stuck at loading like at 0:16, refresh. (fix on the way)
  • Add columns to the table by tweaking the :fiddle/pull: :neighborhood/name :neighborhood/district
  • Where are the changes saved? Your edits "stage" to the stage, the yellow button in the toolbar. Nobody else can see your staged changes until you transact them. The stage is backed by in browser local storage.
  • How do URLs work? The URL is "ednish" encoded, which is a URL-safe dialect of not-quite-EDN used by the default router.
  • What is :hyperfiddle/owners? tank.hyperfiddle.net is configured with entity-ownership security, which respects this value if it is present.
  • If you pull * we infer the necessary columns, but this is never idiomatic, your pull should always be explicit.
  • Grey styles? This indicates you don't have permission to edit.
  • BUG: Datomic ids should be grey because you cannot edit them ever.
  • Carefully copy/cut the stage contents to kill your changes.
  • Paste it back.
  • You can edit the stage by hand. If the transaction is invalid, you can fix it by hand.

Link to form

Make a form and link to it from the resultset
  1. Destructure the Datomic result into a collection
  2. Open the link tab. Read the tooltip.
  3. affix a link to your fiddle by clicking the affix button, opening the new-link popover
  4. In the popover, read tooltip for :link/rel
  5. Set :rel to :hf/self. Hyperfiddle interprets this in the context of your collection query, and knows to repeat this link across the collection.
  6. Click stage to stage your form body as a Datomic transaction.
  7. Your table now has a dangling/broken self link in the identity column, because there isn't a fiddle on the other end of it.
  8. Affix a fiddle to the link. When you stage, the self link becomes valid.
  9. Click the link to navigate to the new fiddle, then inspect it's source
  10. Set the :fiddle/type to :pull.
  • Why destructure the Datomic result? This helps you make a simpler link. Semantically, Datomic relations are for tupling more than one related things, like :find ?e ?f. Thus :link/rel :hf/self needs :link/path 0 to specify the find-element index. However no additional information is needed if we destructure.
  • Why is it called "rel"? Links in Hyperfiddle have strong symmetry with links in HTML, which also have semantic rels.
  1. How are :hf/remove and :hf/detach different?
  2. Can you see your form body in the stage (yellow button in toolbar)?
  3. What is the widget in the * ("splat") position? Read the tooltip to find out.

Nested form

  1. Model your form: :neighborhood/name :neighborhood/district
  2. Check the tooltip on :neighborhood/district, note it is a :db.type/ref
  3. Traverse deeper into the ref: {:neighborhood/district [:db/id]}.
  4. Note the view did not change.
  5. Pull :district/name :district/region
  6. Pull {:district/region [:db/id]}
  7. Pull {:district/region [:db/ident]}
  • Why didn't the view change? :neighborhood/district and {:neighborhood/district [:db/id]} are equivalent in Datomic and mean the same thing. You can confirm this by viewing the exact Datomic result in API view (radio button in toolbar)
  • Why is :db/ident special? :db/ident has special meaning in Datomic, it identifies an entity in a similar way to :db/id.
  • So what's the rule for the view? If you only pull one of :db/id or :db/ident, you're talking about an entity, not it's successors.
  1. Try pulling {:district/region [:db/id :db/ident]}. Why does Hyperfiddle only display the db/ident?

Tweak the view

  1. Open the "view" tab
  2. Read the tooltip and play with the default renderer, note that this is responsible for rendering the markdown.
  3. Add .container-fluid to the :div (this is a Twitter Bootstrap class that adds margins)
  4. Comment out ui/result with the comment-form reader macro: #_
  5. [hyperfiddle.ui/field [:db/id] ctx hyperfiddle.ui/hyper-control]
  6. hyperfiddle.ui/hypercontrol is the field renderer
  7. Repeat for :neighborhood/name and :neighborhood/district, and comment out :db/id
  • Can I get rid of Bootstrap? Not yet, but we're in the process of writing it out.
  • Can I load external css assets? Yes, that's out of scope of this tutorial.
  • What is ctx? It is a historical impl detail and a scar. The hyperfiddle.ui namespace is unfinished and we're still figuring out the clearest way to do it. Any ideas?
  1. Disable the markdown renderer, printing the raw string into a :pre instead. (with-out-str (cljs.pprint/pprint foo))
  2. Instead of rendering your fields with hyper-control, replace it with: #(pr-str %)
  3. Also try (fn [val ctx props] (str val)) and (fn [val ctx props] [hyperfiddle.ui/hyper-control val ctx props])
  4. View props are the optional final argument: [hyperfiddle.ui/field [:db/id] ctx hyperfiddle.ui/hyper-control {:class "alert-success"}] (a random Bootstrap class)

Form inside table

  1. Back to the neighborhoods table (I recommend you close out any dangling sources, they are easy to reopen)
  2. Pull deeper into :neighborhood/district [*], to see what's there
  3. Get rid of the magic splat field by pulling exactly what you need: :db/id :district/name district/region

Table view

Warning, below is under construction 9/23
  1. Replace ui/result with an explicit ui/table. This is quite awful to type and we're working on it.
    • [hyperfiddle.ui/table fields-fn ctx]
    • [hyperfiddle.ui/table (fn [ctx] [[hyperfiddle.ui/field [:db/id] ctx hyperfiddle.ui/hyper-control]]) ctx]
    • No they are not the same ctx.
  2. Enumate the ui/fields in the table
  • What's with the ctx? It keeps track of where we are as we traverse the Datomic result, including metadata like the parsed query. We have technical debt here.

Table column join

  1. Clean up by nesting directly into the district/region as a column
  2. Pull {:district/region [:db/ident]} instead of db/id
  1. Hyperfiddle understands that Datomic treats db/ident like :db/id
  2. When you address an entity by reference, Hyperfiddle will choose the most idiomatic way to identify it that you pulled
  3. When you path to :db/id or :db/ident, you are no longer talking about the entity, but it's identity as a value
  4. The forms library will never generate UI that lets you edit db/ident (you can override the hyper-control to a regular keyword editor though).

Region view

  1. affix a :link/rel :hf/self, and affix a fiddle
  2. Set :link/path to the region entity: :neighborhood/district :district/region
  3. Navigate to the region and inspect source
  4. Set the fiddle/pull to [:db/ident]
  5. Tweak the view with .container-fluid

Filter so there's less on the page for this next bit

  1. [> ?name "C"], just so there's less on the page

Picklists, part one: :hf/iframe

  1. Affix a link, :hf/iframe
  2. Switch to data mode to see this link, iframes are not shown in the view by default, you have to place them.
  3. See the error link/fiddle required
  4. Affix a :link/fiddle
  5. alt-click to inspect the iframe's source (or alt-middle-click / alt-cmd-click)
  6. query the districts
  7. If the view gets stuck loading, refresh, it's a regression

Picklist, part two: coordinate the view

  1. Pull [:db/id :district/name]; db/id here is coordinated between the picklist and the selected value which also pulled :db/id.
  2. Use a FindColl rather than a FindRel also for coordination with the selected value. The types need to align!
  3. Back to the table
  4. Add a column :neighborhood/district
  5. Add view props to the renderer, {:options :districts}
  6. observe the picklist can't find the link
  7. set a link/class :districts
  8. The picklist finds the link by class
  9. Add view prop {:option-label :district/name}, maybe also try pr-str (watch out, pr-str is really slow).

Clean up the table view

  1. Fix the query back to query the whole list

Production, server rendering, etc