hoplon

The :hoplon: ClojureScript Web Framework - http://hoplon.io/
2018-01-21T00:38:25.000090Z

@chromalchemy i think you need to profile what's actually going on

2018-01-21T00:38:50.000057Z

i'm assuming you're calling filter or remove under the hood in those fns

2018-01-21T00:39:21.000062Z

which just walk the sequence and apply their predicate to each item, which should be fast enough

2018-01-21T00:41:24.000035Z

you could maybe get some minor speed benefits doing a single pass with a combined test, e.g. transducers

2018-01-21T00:41:47.000077Z

but not 5-10s worth i wouldn't have thought...

2018-01-21T00:46:44.000104Z

datascript/datomic/datalog is an example of something more generalised for querying the state of your items

2018-01-21T00:47:26.000050Z

maybe checkout https://github.com/alandipert/intension

2018-01-21T00:58:03.000021Z

@chromalchemy if you're rearranging list items and you have internal state for your items then you'll have a much easier time managing that state with a keyed list https://reactjs.org/docs/lists-and-keys.html

2018-01-21T01:09:06.000014Z

even if you carefully wrap all your own state in shared scopes that you manage properly, there's still browser state like focus, values of inputs, cursor positions, selections, etc. (much of which JS cannot even see) that can get mixed up if you can't lock a specific DOM element to a keyed item

2018-01-21T01:26:54.000064Z

I have a UUID for each item. I've been using this to query the list and get/set/test map vals. I was assuming that this was not great, that constantly scanning the list for item id's was inefficient, and that I should be using the implicit index in the vector. But I'm seeing maybe I was on the right track?

2018-01-21T01:27:25.000055Z

I see that the key does not necessarily have to be a UUID, just locally unique.

2018-01-21T01:29:24.000002Z

Am I correct that since my "items" each have an unique :id, then it is a "keyed list"?

2018-01-21T01:30:41.000059Z

@chromalchemy in the keyed-for-tpl you provide a key fn

2018-01-21T01:30:51.000055Z

if you don't provide one then identity is used

2018-01-21T01:31:16.000039Z

which would really only make sense if your items never changed, but you wanted to rearrange them

2018-01-21T01:31:38.000047Z

the tests use keywords as an example of that, so a list like [:a :b :c :d] the key for an item is itself

2018-01-21T01:31:48.000058Z

for your case, :id would be your keyfn

2018-01-21T01:32:48.000066Z

so the work needed is something like

2018-01-21T01:33:13.000098Z

- map keyfn to the list

2018-01-21T01:33:42.000031Z

- walk this list of keys and lookup to see if we already have an el in the cache or we need a new one

2018-01-21T01:33:55.000105Z

- return a new list of els based on the key lookups

2018-01-21T01:34:23.000036Z

- call merge-kids to actually put the els in the DOM because there's no guarantee they line up with the last iteration

2018-01-21T01:35:03.000082Z

building els and calling merge-kids at the end is probably the slowest parts of that

2018-01-21T01:35:13.000017Z

but its all pretty new!

2018-01-21T01:35:53.000039Z

in the future, merge-kids could potentially even become "key aware" and do smarter/faster diffs based on that

2018-01-21T01:37:19.000056Z

Ok thanks, I'll try to walk through, digest that process.

2018-01-21T01:38:03.000118Z

I'm a bit confused about keyfn though. What does it return? Or does it apply the key/val to each list item?

2018-01-21T01:38:18.000029Z

given an item, return its key

2018-01-21T01:38:31.000063Z

or its "identity" in a sense

2018-01-21T01:38:43.000003Z

you're just telling hoplon what about the item makes it unique

2018-01-21T01:38:54.000005Z

if you have a uuid that's easy, just return that

2018-01-21T01:39:57.000047Z

The id value itself right? Not simply the keyword the value is on?

2018-01-21T01:40:12.000080Z

ah well keywords are fns

2018-01-21T01:40:38.000082Z

(keyfn myitem) => 23

2018-01-21T01:40:40.000098Z

so :id is both the key and the function to lookup the key 😛

2018-01-21T01:40:46.000044Z

yeah exactly

2018-01-21T01:41:28.000054Z

Ok, just wanted to make sure, lol

2018-01-21T01:41:45.000001Z

yup, but let's say you needed to combine two things

2018-01-21T01:42:02.000014Z

like um :id and :type or something

2018-01-21T01:42:11.000087Z

you could do (juxt :id :type) for your keyfn

2018-01-21T01:43:02.000012Z

like how a primary key in a db can be a combination of a few fields

2018-01-21T01:44:00.000078Z

So basically the keyfn is the "query" on the list?

2018-01-21T01:44:32.000044Z

uh, it is, but specifically it's the query to tell hoplon how to line things up internally

2018-01-21T01:45:10.000001Z

say i had [{:a 1 :b 2} {:a 3 :b 4}] and i passed that to the loop

2018-01-21T01:45:42.000012Z

the loop needs to build an el for each item

2018-01-21T01:46:15.000057Z

but it also needs to know how to retrieve that same el next time it gets a new version of the list

2018-01-21T01:46:23.000067Z

so if the next iteration of the list looks like

2018-01-21T01:46:33.000092Z

[{:a 1 :b 5}]

2018-01-21T01:46:35.000071Z

what do we do?

2018-01-21T01:47:09.000066Z

if the keyfn is :a then we re-use the first el from before and remove the second el

2018-01-21T01:47:25.000022Z

if the keyfn is :b we need a brand new el and remove all the other els

2018-01-21T01:48:37.000027Z

if the keyfn is (juxt [:a :b]) then we need a new el, and we'll never reuse this new one until we see a new item with both :a 1 and :b 5

2018-01-21T01:49:24.000024Z

if the keyfn is identity (the default) then we'll only reuse the el if we see a new item that is = to the entirety of the current item

2018-01-21T01:52:31.000050Z

ok. And this is all in the context of keyed-for-tpl? And "re-use" means the same dom node, but it can have updated values (outside it's key)?

2018-01-21T01:52:55.000008Z

yeah, same DOM node new values

2018-01-21T01:53:51.000044Z

the important difference between a normal for-tpl is that the mapping between items and DOM nodes is based on the "identity/key" of the item rather than the position in the list

2018-01-21T01:56:10.000032Z

which is crucial for re-ordering, because if you think about it, the whole concept of "reorder" is grounded in the idea that we have some "unique things" that can be reordered in the first place 😛

2018-01-21T01:57:02.000110Z

True, sounds obvious in retrospect. So the keyfn returns an item's unique value. And the keyed-for-tpl tests for equality of that value across updates to better manage (diff) the dom.

2018-01-21T01:57:27.000025Z

yes

2018-01-21T01:57:38.000076Z

but currently it's more about ensuring sensible state downstream than efficiency

2018-01-21T01:57:53.000036Z

although i'm sure we could get improvements on the diffing later too 🙂

2018-01-21T01:59:05.000018Z

With the normal for-tpl, I would filter the list outside of the loop, then feed the filtered results in. But my understanding is that each iteration of any outside filtering, generates a whole new list in memory under the hood. Even if you only add/remove one thing? There's no sharing, and potentially a memory overload if you have too many filterings going on.

2018-01-21T01:59:28.000077Z

depends how you do it

2018-01-21T01:59:44.000047Z

subvec for example uses structural sharing, so it's O(1)

2018-01-21T01:59:58.000029Z

but it's not really a filter per se

2018-01-21T02:00:06.000098Z

calling filter yes, that will make a new list each time

2018-01-21T02:00:37.000058Z

actually tbh i'm not even 100% sure of that, lol

2018-01-21T02:00:41.000063Z

I've been using Specter a lot, so not sure what's going on under it's hood.

2018-01-21T02:00:54.000066Z

part of clojure's immutability is they do stuff "under the hood" to make things faster

2018-01-21T02:01:12.000015Z

even if filter currently makes a new list, it might not in a future version...

2018-01-21T02:01:34.000031Z

i'd be surprised if the making of a new list was causing problems

2018-01-21T02:01:37.000004Z

Like changing [:a :b :c] to [:a :c :b] results in 2 lists in memory?

2018-01-21T02:01:58.000104Z

i dunno, i think "it depends"

2018-01-21T02:02:37.000021Z

i think you have to research structural sharing in clojure to find out

2018-01-21T02:02:47.000005Z

Hmm. Ok I assumed some clojure immutable magic was going on. It only just looks like I'm duplicating all over the place.

2018-01-21T02:02:56.000025Z

yeah exactly

2018-01-21T02:03:10.000074Z

i think there's a lot of magic making it safer than it looks 😛

2018-01-21T02:03:25.000087Z

regardless, you can use transducers if you're worried about this

2018-01-21T02:03:56.000054Z

i highly recommend profiling before you go down this road though, it sounds like a micro optimisation to me

2018-01-21T02:04:37.000057Z

e.g. i'd expect the process of walking the list and applying a predicate to every item to decide what to keep is going to be riskier for CPU than the mechanical process of building the resultant list

2018-01-21T02:04:50.000032Z

even if you only remove one item, filter still needs to check every item

2018-01-21T02:05:22.000056Z

What do you think of the cascading formula cells to filter a list, (per above meta-code), before feeding to for-tpl. If I change the params around I get a lot of different versions of the list. But it seemed like you didn't think this would necessarily lead to a memory explosion in the for-tpl.

2018-01-21T02:05:46.000013Z

i do things like that reasonably regularly

2018-01-21T02:05:59.000013Z

i also use tools that have a query language regularly

2018-01-21T02:06:51.000003Z

inside the for-tpl (at least my proposed versions) i don't think there's much you can "blow up"

2018-01-21T02:07:41.000035Z

the for-tpl only sees the final output of your prior manipulations, and then builds item cells based on the key/position of the items list, and maps them to DOM elements based on the key/position

2018-01-21T02:08:31.000050Z

this is where i got to last night with a simplified for-tpl:

2018-01-21T02:08:34.000008Z

(defn loop-tpl*
 [items tpl]
 (let [els (cell [])
       itemsv (cell= (vec items))
       items-count (cell= (count items))]
  (do-watch items-count
   (fn [_ n]
    (when (< (count @els) n)
     (doseq [i (range (count @els) n)]
      (swap! els assoc i (tpl (cell= (get itemsv i nil))))))))
  (cell= (subvec els 0 items-count))))

2018-01-21T02:08:51.000047Z

there's not really a lot to break there...

2018-01-21T02:10:05.000036Z

and walking a list and applying a pred to filter is O(n) so it's not going to "blow up", just get linearly slower as you add more stuff to the list

2018-01-21T02:12:04.000038Z

"i'd expect the process of walking the list and applying a predicate to every item to decide what to keep is going to be riskier for CPU than the mechanical process of building the resultant list. Even if you only remove one item, filter still needs to check every item" I assume this is what's bogging me down more than anything. How can I avoid this constant walking (event to just pick out a single item with a given UUID)? That's why I was thinking I needed to use the implicit vector index. But the react article seemed to warn against that?

2018-01-21T02:12:32.000029Z

ps. I haven't had a chance to get into Datascript yet 😛

2018-01-21T02:12:37.000057Z

well you can't is the short answer

2018-01-21T02:12:40.000048Z

but looking forward to it

2018-01-21T02:12:51.000053Z

because if you have any downstream local state

2018-01-21T02:13:04.000064Z

you'll just need to do the same calculations there, but probably more than once

2018-01-21T02:13:38.000090Z

using my example from the issue i raised

2018-01-21T02:13:41.000048Z

(let [state (cell {})] ; <-- note the additional state _outside_ the defn
 (defn my-item
  [item]
  (let [k (cell= ...) ; <-- get an id from item
          expand? (j/cell= (get state k) (partial swap! state assoc id))] ; <-- e.g. javelin readme
   ...)))

(for-tpl [x my-list] (my-item x))

2018-01-21T02:14:14.000049Z

we're now just applying keyfn ad-hoc and using it to lookup values from a state cell per DOM element

2018-01-21T02:14:41.000066Z

instead of doing it once up front and letting the DOM elements downstream take a consistent view of an item without additional accounting

2018-01-21T02:16:34.000061Z

essentially there's no such thing as "changing a list" in clojure, as lists are immutable values

2018-01-21T02:17:15.000085Z

you make a new list, and if there's any relationship you want to preserve between list A and list B then you need to make that explicit

2018-01-21T02:17:22.000008Z

which is going to involve a walk somewhere

2018-01-21T02:17:29.000001Z

might as well make sure it's only 1 walk and not 50

2018-01-21T02:21:05.000104Z

Yes, ok. I'm in the 50 walks camp right now, lulled by the idea that by mutating a named cell I have a "consistent" list.

2018-01-21T02:22:04.000089Z

you can use a for-tpl and get some (probably minor) speed benefits if:

2018-01-21T02:22:27.000082Z

- your downstream DOM elements are totally read-only, not even a11y browser interactions are allowed, like focus states

2018-01-21T02:22:56.000068Z

- your downstream DOM elements have no internal state that references the identity/key of an item

2018-01-21T02:24:41.000054Z

I don't understand that last one. Can you give an example?

2018-01-21T02:24:59.000062Z

^^ like the expand? above

2018-01-21T02:25:22.000046Z

like "read more" with a popdown showing more info

2018-01-21T02:25:36.000097Z

you want that to be tied to an item, not a DOM element

2018-01-21T02:26:30.000061Z

if i click "read more" on item 1, then reverse my list, after rearranging i want the last item to be expanded, not the first

2018-01-21T02:28:00.000065Z

i guess i'm just saying the same thing twice 😛 which is that you've got internal state of elements to worry about, which could either be cljs/cell state or browser internal state

2018-01-21T02:32:20.000029Z

I really don't want to worry about browser internal state if can avoid it. So by "item" you mean the item map, presumable contained in a cell. So If I have a "read more" link, I walk that cell for the "more" data, to feed to the view (which might create a new dom element)...?

2018-01-21T02:33:45.000047Z

ah so for the purpose of what we're talking about here there is very little difference between a keyed and non-keyed for-tpl

2018-01-21T02:35:00.000039Z

a (cell [ ... ]) goes in, gets turned into [(cell= ... ) (cell= ... ) (cell= ... )] or {k1 (cell= ... ) k2 (cell= ... ) k3 (cell= ... )}

2018-01-21T02:36:00.000015Z

actually that's not quite right lol

2018-01-21T02:36:09.000005Z

hmmm oversimplified too much 😛

2018-01-21T02:36:26.000021Z

it's actually more like

2018-01-21T02:37:29.000063Z

(cell [ ... ]) goes in, then we check to see if there is an appropriate DOM element for each item, if there is not then we make one like (my-el (j/cell= (get items k nil)))

2018-01-21T02:38:30.000022Z

when you change the items list, we just check to see if new individual item cell/DOM mappings need to be made

2018-01-21T02:41:56.000054Z

if you provide a sensible key to keyed-for-tpl you won't need to worry about browser state getting out of sync with your uuids

2018-01-21T02:42:49.000034Z

my point is just that even though there's some internal stuff going on to make that happen, you can't make it faster by avoiding it because either A. you'll have to do equal or greater work downstream or B. you will have subtle bugs caused by stale/inconsistent state

2018-01-21T02:43:24.000013Z

I think I'm doing what you talked about earlier w/ respect to downstream identity:

(defc state 1)

(defc items [{:id 1} {:id 2}])

(for-tpl [x @items]
   (elem :color (cell= (when (= (:id @x) @state) :red))

2018-01-21T02:43:49.000028Z

yes

2018-01-21T02:44:18.000010Z

(defc items [{:id 1} {:id 2}])
(keyed-for-tpl nil :id [x items]
  (elem :colour (cell= (when (= (:id x) 1) :red)))))

2018-01-21T02:46:08.000006Z

^^ looks like this with a key

2018-01-21T02:46:32.000043Z

ignore the first nil in keyed-for-tpl for now 😛

2018-01-21T02:47:29.000026Z

but what's also important, and is hard to see from this example, is that often these things are in different parts of your codebase

2018-01-21T02:48:39.000048Z

your for-tpl might be in some ns calling elem from another ns, and elem might also be called from multiple different places, so it makes it tedious to track all this state across multiple places and contexts

2018-01-21T02:49:51.000042Z

you really don't want your elem to be "reaching out" to global state in order to get the job done 😕

2018-01-21T02:51:18.000035Z

I think I see. But how do you change the 1 (state value) in your example?

2018-01-21T02:51:50.000052Z

you can make it local to elem safely

2018-01-21T02:52:16.000021Z

it's really

2018-01-21T02:52:22.000049Z

(defn my-item
 [item]
 (let [expand? (cell false)]
  ...))

(keyed-for-tpl nil :id [x my-list] (my-item x))

2018-01-21T02:52:23.000061Z

vs

2018-01-21T02:52:31.000023Z

(let [state (cell {})] ; <-- note the additional state _outside_ the defn
 (defn my-item
  [item]
  (let [k (cell= (:id item)) ; <-- get an id from item
          expand? (j/cell= (get state k) (partial swap! state assoc id))] ; <-- e.g. javelin readme
   ...)))

(for-tpl [x my-list] (my-item x))

2018-01-21T02:55:30.000020Z

the boilerplate in the latter needs to be repeated for every single cell that i want to represent state for a given item

2018-01-21T02:55:53.000098Z

I think I'll have to play about a bit to fully appreciate all this. Right now it's still a bit fuzzy cause

(defc items [{:id 1} {:id 2}])

(for-tpl [x items]
  (elem :colour (cell= (when (= (:id x) 1) :red))))) 

looks almost the same as 

(keyed-for-tpl nil :id [x items]
  (elem :colour (cell= (when (= (:id x) 1) :red)))))
But I understand that this example is overly stripped down.

2018-01-21T02:56:40.000028Z

well actually your example works in both for-tpl and keyed-tpl 😛

2018-01-21T02:56:58.000054Z

because your cell attached to :colour is using part of the value of item

2018-01-21T02:57:00.000010Z

that works

2018-01-21T02:57:25.000013Z

expand? is different because you can't read it from item

2018-01-21T02:57:45.000067Z

it is related to item but it isn't part of that data structure

2018-01-21T02:59:42.000058Z

more like this

2018-01-21T02:59:45.000007Z

(defn elem [item]
 (let [toggle? (cell false)]
   (div
    :color (cell= (if toggle? :red :blue))
    :click #(swap! toggle? not))))

(defc items [{:id 1} {:id 2}])
(keyed-for-tpl nil :id [x items]
  (elem x))

2018-01-21T03:00:26.000050Z

when you click the elem it swaps between red and blue

2018-01-21T03:01:04.000076Z

so if i click :id 2 it goes red, if i then reverse the list so that :id 2 is at the start of the list, do i want the first DOM element or the second one to be red?

2018-01-21T03:01:27.000066Z

for-tpl would keep the second element red, so :id 1 would be red now

2018-01-21T03:01:48.000084Z

keyed-for-tpl would make sure the item with :id 2 is red, so the first element would be red now

2018-01-21T03:07:18.000028Z

I think I see now. I think in that situation I would have tried to create a permenant {:id 1 :toggled? true} attribute to get/set/test. But that seemed verbose and redundant and more walking..😬 Using that local state looks a lot more elegant.

2018-01-21T03:07:49.000021Z

yes of course you can keep injecting all this state into item

2018-01-21T03:08:12.000062Z

but you're going to end up with dozens or hundreds of very similar looking keys quite fast >.<

2018-01-21T03:10:13.000071Z

and none of those extra keys really add value to item tbh

2018-01-21T03:10:57.000027Z

toggled? has nothing to do with the fundamental definition of the item, it has to do with the internal state of a particular DOM element that is rendering that item in a certain way

2018-01-21T03:13:27.000064Z

Yes, that's the feeling I was getting. My semantic data was getting littered with view-state complexity! I want to compute the view stuff implicitly, but was searching for an efficient means.

2018-01-21T03:13:34.000057Z

Well thank you for taking the time to explain it in depth. This will help me tremendously. My app is all about filtering and sorting a list, and this clarifies where I need to head, and free's me from some gloom about feeling I was plodding down a dead end path.

2018-01-21T03:15:04.000058Z

I am currently trying to update to Hoplon 7.1 but getting some .spec errors. Do I need 7.1 to use the keyed-for-tpl? or could I plug it into 7.0.3?

2018-01-21T03:15:42.000009Z

actually keyed-for-tpl is not available in anything yet 😛 waiting on @flyboarder to push a snapshot when he's available 🙂

2018-01-21T03:15:59.000055Z

but it would be in 7.2-SNAPSHOT getting ready for the 7.3 release

2018-01-21T03:16:38.000032Z

what errors are you getting from spec?

2018-01-21T03:17:52.000031Z

I got the one about serializing the error message, but I was able to follow your trick of inserting (prn) code into boot.cljs

2018-01-21T03:18:23.000043Z

ah yeah, well that error just hides another error

2018-01-21T03:19:07.000050Z

now I'm getting stuff like

{ :cause 
     "Call to clojure.core/defn did not conform to spec:\nIn: [1 0] val: {:keys [url open-new?], :or {:open-new? false}, :as attr} fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-n :bodies :args] predicate: vector?\r\nIn: [1 0] val: ({:keys [url open-new?], :or {:open-new? false}, :as attr} kids) fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-1 :args] predicate: (cat :args (* :clojure.core.specs.alpha/binding-form) :varargs (? (cat :amp #{(quote &amp;)} :form :clojure.core.specs.alpha/binding-form))),  Extra input\r\n"
  :data 
     {:clojure.spec.alpha/problems , 
        ( 
          {:path [:args :bs :arity-1 :args], :reason "Extra input", :pred (clojure.spec.alpha/cat :args (clojure.spec.alpha/* :clojure.core.specs.alpha/binding-form) :varargs (clojure.spec.alpha/? (clojure.spec.alpha/cat :amp #{(quote &amp;)} :form :clojure.core.specs.alpha/binding-form))), :val ({:keys [url open-new?], :or {:open-new? false}, :as attr} kids), :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/arg-list :clojure.core.specs.alpha/arg-list], :in [1 0]}
          
          {:path [:args :bs :arity-n :bodies :args], :pred clojure.core/vector?, :val {:keys [url open-new?], :or {:open-new? false}, :as attr}, :via [:clojure.core.specs.alpha/defn-args :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/args+body :clojure.core.specs.alpha/arg-list :clojure.core.specs.alpha/arg-list], :in [1 0]})
      :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x13d54144 "clojure.spec.alpha$regex_spec_impl$reify__2436@13d54144"], :clojure.spec.alpha/value , 
        (link [{:keys [url open-new?], :or {:open-new? false}, :as attr} kids] (elem :td :underline :tc :blue :m :pointer :click (fn* [] (.open js/window url (if (not open-new?) "_self"))) (dissoc attr :url :open-new?) kids))
      :clojure.spec.alpha/args 
        (link [{:keys [url open-new?], :or {:open-new? false}, :as attr} kids] (elem :td :underline :tc :blue :m :pointer :click (fn* [] (.open js/window url (if (not open-new?) "_self"))) (dissoc attr :url :open-new?) kids))}
  :via
    [{:type clojure.lang.ExceptionInfo
      :message 
            "src\\elements\\misc.cljs [line 90, col 1] Call to clojure.core/defn did not conform to spec:\nIn: [1 0] val: {:keys [url open-new?], :or {:open-new? false}, :as attr} fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-n :bodies :args] predicate: vector?\r\nIn: [1 0] val: ({:keys [url open-new?], :or {:open-new? false}, :as attr} kids) fails spec: :clojure.core.specs.alpha/arg-list at: [:args :bs :arity-1 :args] predicate: (cat :args (* :clojure.core.specs.alpha/binding-form) :varargs (? (cat :amp #{(quote &amp;)} :form :clojure.core.specs.alpha/binding-form))),  Extra input\r\n"}]}
But haven't had a chance to dig into it yet.

2018-01-21T03:19:26.000014Z

{:keys [url open-new?], :or {:open-new? false}, :as attr}

2018-01-21T03:19:32.000053Z

Call to clojure.core/defn did not conform to spec

2018-01-21T03:19:58.000085Z

yeah looks like that's clojure itself complaining about some of your syntax

2018-01-21T03:20:16.000082Z

you probably just got bumped up a few versions of cljs to support 7.1

2018-01-21T03:23:43.000016Z

Yeah, I think so. Hopefully I wont hit a wall with it 😅

2018-01-21T03:23:56.000051Z

My current codebase is in Hoplon.UI, which hasn't been updated in a while. I'm not sure If i can update to 7.2 if there are breaking changes, at least until a major refactoring. Can I cut and paste the keyed-for-tple stuff on top of a 7.1 base. Or does it depend on 7.2 internals?

2018-01-21T03:23:59.000071Z

well if you get stuck let us know

2018-01-21T03:24:14.000075Z

yeah you can paste it in

2018-01-21T03:24:29.000034Z

the only thing is that it is so new that it will probably evolve a bit

2018-01-21T03:24:41.000003Z

so don't get too attached to the version you paste

2018-01-21T03:25:55.000032Z

in theory there aren't breaking changes in 7.2, it was a big refactor internally but the idea was to keep the external APIs the same or extended with new things only

2018-01-21T03:26:47.000003Z

Sure. I think anything might help me out right now. Especially just learning how to orient to that keyed internal state you so eloquently demonstrated.

2018-01-21T03:26:54.000056Z

Ok I'll give it a try

2018-01-21T03:27:07.000037Z

What about using a 7.0.3 base, just in case?

2018-01-21T03:27:34.000083Z

ah actually hmmm

2018-01-21T03:27:37.000009Z

i lied

2018-01-21T03:27:47.000066Z

it won't totally work without the new version of merge-kids

2018-01-21T03:27:49.000037Z

😕

2018-01-21T03:27:54.000052Z

i forgot about that

2018-01-21T03:28:37.000075Z

since for-tpl never re-arranges anything, hoplon doesn't actually support re-arranging >.<

2018-01-21T03:28:53.000005Z

i had to add that support while i was working on keyed-for-tpl

2018-01-21T03:28:53.000072Z

dang

2018-01-21T03:29:20.000032Z

which also sucks for me because it means i can't use it either until the snapshot goes up, lol

2018-01-21T03:30:03.000140Z

on that note i think i'm going to go get a ☕

2018-01-21T03:31:21.000040Z

don't stress too much about 7.1 -> 7.2 though, i don't see that being a major hurdle at all

2018-01-21T03:32:15.000071Z

Ha. Lifestyle of the bleeding edge! I'll probably refactor and catch up to 7.2/7.3 asap either way. Thank you for the help, and all your recent work!!!

2018-01-21T03:32:37.000068Z

np, glad to help

2018-01-21T03:33:05.000053Z

and also it's great if other ppl start using what i'm writing so i can get feedback and make sure its rock solid

2018-01-21T03:34:17.000006Z

Sure. I'll test and give some feedback as soon as I'm able. Later

2018-01-21T03:34:24.000012Z

:thumbsup: catch

flyboarder 2018-01-21T03:38:29.000014Z

@thedavidmeister I’ll get it in snapshot soon I promise

flyboarder 2018-01-21T03:38:47.000031Z

Nice explanation! This is a great enhancement!

2018-01-21T04:19:30.000036Z

@flyboarder hah, all good, i've got plenty of other things to keep me busy 😉

2018-01-21T04:29:11.000052Z

i think this also fits well with the "easy interop with 3rd party libs" principle, as they will often have their own internal state that hoplon shouldn't damage or need to know about - imagine a WYSIWYG editor attached to an item, we don't want to be thrashing a setData() method on every reorder, that could be very expensive as it would internally trigger a parse/render cycle on the editor for every item

2018-01-21T04:31:41.000068Z

@chromalchemy https://www.youtube.com/watch?v=6mTbuzafcII <-- good watching if you're concerned about lots of list rebuilding

2018-01-21T04:33:06.000010Z

you're basically doing what he describes at around 6:00

ntzanos 2018-01-21T21:40:01.000024Z

Hi all. I am new to hoplon as well as clojure(script) so please excuse my naive question

ntzanos 2018-01-21T21:40:53.000077Z

I am trying to get the value of a plain text input field and create dynamically a number of text input fields based on the number I will get. I am not sure how to get this number.

ntzanos 2018-01-21T23:27:05.000133Z

Fixed 🙂

2018-01-21T23:52:20.000141Z

(let [c (cell 0)]
 (input :value c :input #(reset! c @%))
 (for-tpl [i (cell= (range (int c)))]
  (input)))

2018-01-21T23:52:30.000037Z

@corelon ^^ something like this