This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-10
Channels
- # beginners (15)
- # boot (15)
- # cider (6)
- # cljs-dev (231)
- # cljsjs (1)
- # cljsrn (26)
- # clojure (147)
- # clojure-argentina (1)
- # clojure-dev (8)
- # clojure-germany (1)
- # clojure-italy (26)
- # clojure-russia (2)
- # clojure-spec (83)
- # clojure-uk (154)
- # clojurescript (123)
- # conf-proposals (3)
- # core-async (5)
- # cursive (26)
- # datascript (21)
- # datomic (120)
- # emacs (2)
- # graphql (9)
- # hoplon (195)
- # instaparse (16)
- # jobs-discuss (1)
- # leiningen (8)
- # luminus (8)
- # lumo (7)
- # off-topic (17)
- # om (7)
- # om-next (3)
- # parinfer (121)
- # pedestal (5)
- # planck (13)
- # re-frame (11)
- # reagent (21)
- # ring-swagger (2)
- # spacemacs (28)
- # uncomplicate (3)
- # unrepl (7)
- # untangled (34)
- # vim (5)
@thedavidmeister if you have an app, I can fix it for you
@flyboarder did you see the failing test?
in your example, if you have a a b
and change the first a to c, the UI shows c b c
that's not "reording elements" from the user's perspective
if it's "correct behaviour", what's the use case for that?
what i'm asking for is an example for starting with a a b
then changing the first a
to c
and then seeing a b c
Yeah my demo app does that correctly
doesn't in my tests
With the example I posted before
i put your example in the test
I think that's the test failure since it doesn't actually track the cell state just the element
if you can write a better test please do
i thought i pretty faithfully represented your example
did you try literally a a b
in your demo app?
it has to be a a b
it can't be a b z d
as you posted, the bug would not manifest in that
or alternatively, is the demo app somewhere that i can play with @flyboarder ?
I'm working on a test library for hoplon that mimics the HLisp structure
The demo code I posted above should work in anything
I'm testing it with snapshot builds of degree9/meta
@thedavidmeister I tested with all "a" and it still seems to work without the bug you describe
ok then, i'll try with the demo code in a browser
not all a
checking it out
@thedavidmeister do you have a test app?
i’d like to make sure we are looking at the same thing
(ns ^{:hoplon/page "index.html"} pages.index
(:require
hoplon.jquery
[javelin.core :as j]
[hoplon.core :as h]))
(j/defc data ["a" "a" "b"])
(j/defc= sdata (sort data))
(j/defc= idata (into {} (map-indexed vector sdata)))
(j/defc= rdata idata #(reset! data (vals %)))
(prn idata)
(h/defelem testelem [attr kids]
(h/div
(h/for-tpl [[k v] rdata]
(h/input :change #(swap! rdata assoc @k @%) :value v))))
(h/html
(h/body
(testelem)))
@thedavidmeister ok, so I see the issue, let me play with it
:thumbsup:
@thedavidmeister so I found the issue, it’s the -tpl caching
when you change the first input to c
it actually created 2 new elements
one for the reorder of b
and one for the “new” c
Hi, is there a pattern for doing a fetch of data at the top of a defelem
? I have a websocket connection that fetches data for parts of the page, and want to only fetch it when the element is being created. (I can use a click event on a button later, if it must be refreshed.)
Right now, I have a do
at the top of my defelem
(with the fetch code triggered in the do
), but that feels gross.
2nd question: Is there a way to get an index (like in map-indexed
) when using loop-tpl
?
@mudphone we are currently working out the index/sorting thing but you can just map-indexed the data cell
for your data you can just use a let
@flyboarder oh man, thanks, yeah, ha
@flyboarder and the websocket data load call will only happen once? when the element is loaded?
correct, a defelem constructs and returns an element
so later you “call” the returned element
hoplon extends the IFn protocol so elements can be used as functions
@flyboarder ok, thank you. So, my websocket call is made when I call the element fn that I’ve created.
One more question. I wasn’t able to get :load
to work as an on!
attribute on a div
. I thought it would work, since there’s a .load()
jQuery event handler. I tested it by having an anon fn console.log. Should that not work?
@flyboarder oh interesting
@mudphone no, the browser never loads any hoplon elements, it loads a script tag and everything happens from javascript
yeah no problem 🙂
@flyboarder so is there a solution for that? maybe the caching could be smarter somehow?
@thedavidmeister i think the caching should be smarter, but I dont think it really can be, since it’s based on the cell
so why did what i did help?
did i just bypass the cache somehow?
yep, your forcing a new element
which although working, would result in a memory leak if you infinitely change the inputs
thats just a theory tho, you can profile your app and see what happens to confirm
@flyboarder hi! i saw u were talking about using lens. haven't read it in detail but do u have any solution for editing vectors?
something like a for-tpl
but where the (potentially destructured) loop vars are actually lens into the original sequence
@flyboarder also
pls. the latest tag in git is 7.0.0
@flyboarder but i'm not creating a new element? i'm just adding a new watch to an existing cell
@thedavidmeister ah, i just saw u r trying to do the very same thing as i am. i remember i solved this in the past but can't find the code now. but it was not very self-contained / reusable anyway, so probably it worth reconstructing it again anyway
@thedavidmeister right, which I believe is forcing the -tpl to detect a new value and create a new instance
is there some way to measure/detect that?
@thedavidmeister you can profile your page and watch the memory as elements are changed with the inputs
I think this can be fixed by adjusting the approach, instead of tracking the values, we can just track the index
@thedavidmeister you are losing the ordering because of the (into {} ...)
transformation
@onetom no, the order in the data structure is correct, it's the order in the DOM that is wrong
well, maybe in the example above something weird might be going on, but there's another test i wrote
@flyboarder if what you're saying is true, then why does :data-k
have the right value in it in my example?
if the problem is in for-tpl
then i expect read only attributes to break in the same way as read/write attributes like value
https://github.com/hoplon/hoplon/pull/193/files#diff-d2b51acfbf4b936baf9682bbf25061edR35
if i do (for-tpl [[k v] xs] ...)
then i expect k
and v
to behave identically inside the for-tpl
@thedavidmeister let me try it with my click version instead and see if this is specific to the input elements
@thedavidmeister it will get mixed up eventually, eg:
(prn (vals (assoc (into {} (map-indexed vector [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39])) 0 "X")))
("X" 32 1 33 2 34 3 35 4 36 5 37 6 38 7 39 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)
my example has a sort by with no into
@onetom https://github.com/hoplon/hoplon/pull/193/files#diff-d2b51acfbf4b936baf9682bbf25061edR11
@flyboarder actually, scratch that, ks should behave because there are no duplicates
what would be interesting is to see whether v
on a data attribute gives the same results or something different
@thedavidmeister ok, i was talking about the example u pasted above.
in that the change handler is modifying the rdata
right ok
i think that's a fair point for that example, but probably doesn't change much overall here 😕
i gotta duck out and do some errands in a sec
but i'll try to test v
on other attributes later on
then we can see whether the bug lives in the choice of attribute or the template itself 🙂
things to note, this only happens when you modify the first value and it has a matching value later in the list,
the cell value is not actually changing because the new location has been modified instead
does not seem to be specific to the value attribute or input elements
correction! does seem to be limited to input elements, but only when it’t the first element that matches another
using my click version I can change the first element to “c” via a click and they order and update correctly
@onetom what is your take on this?
I think this explanation by Micha still gives the best overview of the situation: https://clojurians-log.clojureverse.org/hoplon/2016-05-08.html#inst-2016-05-08T18:33:49.002601Z
here’s Alan/Micha investigating the same exact issue: https://clojurians-log.clojureverse.org/hoplon/2016-05-06.html#inst-2016-05-06T18:38:16.002089Z
@dm3 Yeah it seems strange that it’s limited to the one case of input
that’s why David’s solution is closer to a generic one (memory leaks aside) - it makes 2-way binding into 1-way binding
This also is only applicable when you want to use hoplon cell data as the element order
we don't necessarily know that yet @flyboarder
it's just the best reproducible scenario we have atm
i just happened to stumble across this one 😛
im expecting to be able to write code like this:
(j/defc users [{:user/name "joe"
:user/email "[email protected]"}])
(defelem ordered-inputs [attr kids]
(h/div
(vec-tpl [[index {:keys [user/name
user/email]
:as item}] users]
(h/input :value name
:change #(reset! name @%))
(h/input :value email
:change #(reset! email @%)))))
i would think it's a fairly common use-case. i would describe it as: edit an ordered list of items
@onetom how would you order by input value with your example?
in reality the data would be more like:
[{:entity/id #uuid "xxxx-yyy-...-1234"
:entity/index 0
:user/name "joe"
:user/email "[email protected]"}
{:entity/id #uuid "xxxx-yyy-...-5678"
:entity/index 1
:user/name "joe"
:user/email "[email protected]"}]
right so our edge case is when you change that order on the client
via the value of the data
I think you can come up with more situations where there’s 2-way databinding and the expected behaviour breaks. Not just order
@dm3 I find this strange because it only happens to the first input element in the example, if you modify the second one instead the correct behaviour happens
oh, im not talking about the bug you observed.
i was just elaborating on my earlier question whether such a vec-tpl
exists yet or not which provides me with lenses
oh sorry my bad
Im not sure what you mean in your lense question
I want to say no, the values only exist as cells currently
i would expect name
and email
to be lenses for convenience which know where to insert themselves back into the original vector
yeah I dont think so, but you may be able to make up a -tpl macro that does that
@dm3 @thedavidmeister so if you use a click event to change the cell value instead of the change event it works correctly
that’s because there’s no more 2-way binding, right? click -> reset value cell -> do! input
right but the order changes, seems strange the browser only updates the first elements value if you typed into one of the elements
not if the change happened from a click or other event
so the browser is migrating state from one element to another, but only under certain cases
with the example above any click event makes everything work correctly, you can also change alpha
at index 1
to omega
and it works, however if you do the same at index 0
the bug will show
you can also see what the cell has as a value and what the input box shows
@flyboarder yes, because one of the conditions for the bug is changing index 0
it has to "jump" over an element with the same value as it
because the element that it "jumps" shifts up one position to take its place, but because the value is the same the do-watch to push the value into the DOM doesn't fire
have to be very careful about start state and the exact user interactions in order to test properly
@flyboarder here's an update from me
(deftest ??sorting-elements
(async done
(let [data (j/cell {:a 1 :b 1 :c 2})
sorted-data (j/cell= (sort-by (fn [[k v]] [v k]) data))
el (h/div
(h/for-tpl [[k v] sorted-data]
(h/input
:data-k k
:data-v v
:value v
:click #(swap! data assoc @k (int @%)))))
read-vals (fn [el]
(map
#(-> % js/jQuery .val)
(-> el js/jQuery (.find "input") array-seq)))
read-ks (fn [el k]
(map
#(-> % js/jQuery (.attr k))
(-> el js/jQuery (.find "input") array-seq)))]
(-> js/document .-body (.appendChild el))
(h/with-dom el
(is (= ["1" "1" "2"] (read-vals el)))
(is (= [":a" ":b" ":c"] (read-ks el "data-k")))
(-> el js/jQuery (.find "input") .first (.val 3) (.trigger "click"))
(is (= {:a 3 :b 1 :c 2} @data)) ; passes
(is (= [":b" ":c" ":a"] (read-ks el "data-k"))) ; passes
(is (= ["1" "2" "3"] (read-ks el "data-v"))) ; passes
(is (= ["1" "2" "3"] (read-vals el))) ; fails with ["3" "2" "3"]!
(done)))))
putting v
on data-v
passes, so it's really only the :value
attribute that has the bug, which supports the 2-way data idea
i moved to the click
event but it hasn't helped my test
@thedavidmeister I wonder if using mutation observers would catch this
@flyboarder potentially, if you can put together an example i can run the tests
Hi, I’m trying to get started with Hoplon using a http-kit server + compojure, and I can’t figure out to which resource folder the generated html/js is compiled to, or how I can set to which folder it should compile.. Anyone who could give me a hint in the right direction?
@freakinruben I believe you just have to use the target
boot task, ie have (target :dir #{"resources/public"})
at some point in your task chain
@jjttjj oh wow, that sounds almost to simple to be true.. @dm3 yeah, but none of the examples seem to explicitly state the resource path 😉
@freakinruben target
is the default folder
for the target
task
@freakinruben yeah there might be a reason to keep the hoplon files separate from the rest of the public resources, and then serving that up with compojure, instead of just dumping them all in the same spot as your static image files etc
but if you put that target line just before the serve
task in your workflow it should work
hi all, i've recently converted over my project from .hl files to .cljs which is pretty awesome, but now that the hoplon task is essentially unnecessary, I've lost the bust-cache functionality. How are other people handling this? do i need to provide something to cljs task in order to get this back?
hm I’m still struggling with this output folder. I now have the following folders:
- assets/ ; static css files
- resources/ ; resource files for server app
in build.boot
I have:
(set-env!
...
:resource-paths #{"resources"}
:asset-paths #{"assets"}
...
)
(deftask run-clj-dev [] ....)
(deftask run-cljs-dev []
(comp
(hoplon)
(reload)
(cljs-repl :nrepl-opts {:port 9009})
(cljs :optimizations :none :source-map true)
(target :dir #{"resources/public"})))
(deftask run-dev []
(comp
(watch :verbose true :include #{#"\.(cljs|cljc|clj|hl|less)$"})
(run-clj-dev)
(run-cljs-dev)))
The problem now is that the files in resources/
are also copied to resources/public
, making the non-public resources, public. If I don’t set :resource-paths
that is fixed, but then my app can’t access the resources (of course).
Second problem is that the script seems to get into an infinite loop copying the resources/
folder (after the generated resources/public
have been added) to resources/public
, causing watch
to compile cljs again and copying the resources/
folder etc..
Changing the output-dir in (target )
will make my generated resources not available to serve with compojure..
😯
So, what I would hope to accomplish is:
- have resources available to clojure-app
- make generated cljs output serveable through compojure
- make static css files serveable through compojurefreakinruben: if you goal is to just run the application - it seems you have a misunderstanding about the way Boot works. You don’t have to actually write the assets into the resource dir. They will be on the classpath. Boot manages that for you via filesets (https://github.com/boot-clj/boot/wiki/Filesets). For most purposes in Boot you shouldn’t need the target
task.
@dm3, I was slowly figuring that out (coming from lein).. How would you recommend running an API (with reload), a systems map, and some cljs compilation and serving?
Most examples are using (serve)
, but it seems like an overkill to run 2 http-servers when developing + I can’t test the entire stack
it should work the same way you do it in Lein. For example, I have a dev.clj
on the classpath which has start/stop/reset
functions and uses tools.namespace
to reload the application.
be aware of a few gotchas with reloading due to the way Boot works: https://github.com/boot-clj/boot/wiki/Repl-reloading
what do you mean by clj-output? Your clojure files will be on the classpath if you register them as sources/resources with Boot
I think this one is quite comprehensive: https://github.com/Deraen/saapas
I was wrong - the Cljs output will be in the fileset, but it seems people write it out via target
to have an easier time serving from within the app
clj-output
should have been cljs-output
😉 the saapas example is quite nice! It looks like it uses (sift
to prevent existing resources to be written to the (target
folder
hm interesting, did you wrap your system like this? https://github.com/Deraen/saapas/blob/master/src/clj/backend/boot.clj
@raywillig it is still useful and needed to generating hoplon html pages
unless you are handling the html page another way
I still use it for the :hoplon/page
metadata
but i'm wondering how to get the cache busting functionality to work now @flyboarder
youll still need the hoplon task for using that metadata
oh sorry, im tracking
oh actually i do still get cache busting for my main app. it just seems to not work when i compile a regular html page with some hoplon mounted to it ala https://github.com/alandipert/embedded-hoplon-example
right
is the mountpoint required?
⚠️ [degree9/material-hl "0.10.0"]
⚠️
New Release:
this version implements almost all of the material components, although documentation is still lacking….
and its a few versions behind MWC master