This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-25
Channels
- # admin-announcements (1)
- # aws (1)
- # beginners (52)
- # boot (78)
- # cider (22)
- # cljs-dev (1)
- # cljsrn (6)
- # clojars (23)
- # clojure (51)
- # clojure-austin (2)
- # clojure-china (2)
- # clojure-dusseldorf (2)
- # clojure-russia (101)
- # clojure-sg (2)
- # clojure-uk (2)
- # clojurescript (53)
- # core-logic (14)
- # cursive (1)
- # editors (4)
- # hoplon (324)
- # jaunt (1)
- # juxt (4)
- # leiningen (2)
- # mount (17)
- # off-topic (4)
- # om (15)
- # onyx (15)
- # parinfer (4)
- # proton (5)
- # re-frame (26)
- # reagent (24)
- # ring-swagger (1)
- # slack-help (5)
- # spacemacs (2)
- # untangled (10)
i’m working on a bit of functionality that scrolls an element into view when it gains focus, if it isn’t already
:focusin #(do
(if-not (elem-in-viewport? (.-target %))
(c/with-timeout 0 (c/do! (.-target %) :scroll-to true)))
(in/clear-select! in/conn))
this is what i came up with
but is there a more “hoplon way” to do this than nested do!
?
i was thinking i might stick it in the db too...
maybe i solved my own problem, lol
@thedavidmeister: how did you solve it? 😄
Micha - did you have any plans on opensourcing the components that you've built up on top of Hoplon in Adzerk. I recall you made some gists out of a workflow form, but nothing complete. It seems that the code was pretty generic and Hoplon could use some more code in the category of templates/demos/design principles to attract more following. People usually look for a simple way to write a crud app when evaluating frameworks for some reason
that's my current interest, developing the techniques for separating state machine from ui components
if I'm ever done with the current project I'll have to make a series like modern-cljs
for Hoplon
but like in our application at adzerk the core functionality is all separated into state machine and ui
where the state machine is basically an object which has methods that you can call, and properties that are cells
you make formulas on the cell properties, and that's how you link the ui to the current state of the machine
like the form machine for example, has cells that contain validation error messages from the clientside validation or serverside validation
so when you make the ui form you can just have an element whose text is a formula of that cell
and the form machine has methods you can call, like (submit! the-form-machine)
for instance
we also are developing a technique of using dynamic bindings and macros to create something like what i would call "ui domains" or "ui contexts"
but we need to ship code, so a lot of this is not fully abstracted into clean library form yet
I understand you do something like
(with-form-machine (make-state-machine)
(input-a)
(input-b))
and bind formulas to the values/errors/results produced by the machine using the dynamic scopethe value in the context approach is that elements nested deeply in there have access to the context
yep, I recall seeing this one. It's interesting that dynamic scope in Clojurescript is underused (probably carrying over from Clojure where it's trickier to get right due to concurrency)
yeah there is one thing in cljs that really limits the usability of dynamic vars: cljs doesn't have bound-fn
does it surface when you return a thing from defelem
and then want to apply that Element/fn to additional arguments?
(def ^:dynamic *foo* 100)
(defelem bar [{:keys [foo] :as attr} kids]
(div (text "foo is ~(or foo *foo*)")))
(html
(body
(binding [*foo* 200]
(bar))))
the value of the context is that the (bar)
could be wrapped in layers of divs or whatever and it would still be able to see the *foo*
dynamic var
ok, so if you use a 'dynamic' var in a cell, the evaluation will happen when the cell is propagated and the "dynamic" var is unbound
(def ^:dynamic *foo* 100)
(defelem bar [{:keys [foo] :as attr} kids]
(let [*foo* *foo*]
(div (text "foo is ~(or foo *foo*)"))))
it seems like if you had this capture automatically when constructing cells it could work
(defcontext screen
*foo* 100
*bar* 200)
(defelem bar [{:keys [foo] :as attr} kids]
(with-using-screen
(div (text "foo is ~(or foo *foo*)"))))
the condition is
(defn hoist? [x local]
(and (not (or (local x) (core? x))) (or (*env* x) (not (special? x)))))
like given a symbol is it possible to identify whether it's a reference to a dynamic var
used here: https://crossclj.info/ns/org.clojure/clojurescript/1.8.34/cljs.core.html#_binding
@micha: thanks for the tip on infinite scroll. i had to adapt it slightly differently to trigger on window scrolling but all good
so inside a defelem, i did something like (.on (js/jQuery js/window) “scroll” #(do-stuff with cells in the let block))
i would have thought that since something like (.on is global, by the time the thing fires those cells would be out of scope, but of course i was wrong and it worked just like i hoped it would but feared it wouldn't
it would probably be more efficient to have the scroll handler just attached once and to have it reset a cell when it fires
it doesn't go out of scope because handlers are added to the window object in that case
but the cells that are the arguments to the anonymous function are defined in a let block in defelem
nothing will go out of scope if it's referenced by something that isn't eligable for GC
i got it. so going back to your original point. your suggestion would be to have that on scroll handler just update a cell that anything could hand a formula on?
you could even put it in a delay
so the handler wouldn't be added unless something uses it
@micha: I tried to copy case=
from https://github.com/hoplon/hoplon/pull/93 , but I keep having the same problem
"Failed to execute 'insertBefore' on 'Node': parameter 1 is not of type 'Node'.", https://github.com/hoplon/hoplon/blob/master/src/hoplon/core.cljs#L99
I suppose I need to get the latest from the master branch, instead of 6.0.0-alpha13, don't I?
(ns habarnam.core
(:require
[javelin.core :as j]))
(defmacro ^:private safe-deref [expr] `(deref (or ~expr (atom))))
(defmacro case=
[expr & clauses]
(let [[cases tpls] (apply map vector (partition 2 clauses))
default (when (odd? (count clauses)) (last clauses))
syms (take (inc (count cases)) (repeatedly gensym))]
`(let [~@(interleave syms (map (fn [x] `(delay ~x)) (conj tpls default)))
tpl# (fn [expr#] (safe-deref (case expr# ~@(interleave cases syms) ~(last syms))))]
(-> (j/cell ::none :meta {:preserve-event-handlers true})
(j/set-formula! tpl# [~expr])))))
(page "index.html"
(:require-macros [habarnam.core :refer [case=]]))
(defc ui-state :documents)
(html
(head
(html-meta :name "viewport" :content "width=device-width, initial-scale=1"))
(body
(case= ui-state
:documents (div "Documents")
:customers (div "Customers"))
))
(def thing (case= ui-state
:documents (div "Documents")
:customers (div "Customers")))
(println thing)
if you put case
inside a cell it will craete new elements each time the formula is evaluated
if you do have any kind of local state or anyhting like that you need to explicitly manage the memory yourself
luckily, you can do all the tricky bits of figuring that out at the lower levels of your abstraction
i'd love to elaborate on this, but I don't have much time atm. I confess I was drawn to hoplon by the (apparent) possibility to have your code quite clean and focused on the problem, with the details hidden (or abstracted). I experimented with om and quiescent a little bit and hit some walls which I didn't like.
that means that you end up with all kinds of coupling, because essentially you can't have anonymous anything anymore
and once you define that do!
multimethod dispatch, you can use the :toggle
attribute on any element
yes, the component composition is one of things I ran into. I tried to make a layout component, which needed to insert styles into it's children
when I first saw the idea to have a big atom, I didn't find it bad at first. it's only when I needed to mix by "business" state with the "view" state that I stepped a little bit back
it takes all the glorious inventions of lisp, lexical scope, dynamic extent, closures, etc
javelin solves the problem by creating a new reference type that has the same consistency guarantees as the big atom
well, I wouldn't be so radical. you can hide the big atom, and expose parts of it (e.g. subatom), so you get the illusion you are local
missiles come down from the top of the screen toward your cities and you need to fire missiles at them to blow them up before they land
a human being can't tell that we were updating the course and speed of the missiles at 100ms intervals
so you mean, your computation was slower than the rendering, and the animation library calculated the points in between?
but there are a number of highly tuned animation libraries that will choose the most efficient implrementation for the platform
I have to say, this sounds weird to me (processing slower than animation), but then again I had little contact to graphics so far