Fork me on GitHub
#fulcro
<
2017-11-24
>
tony.kay00:11:35

Oh man…totally off-topic: Just made the best pecan pie ever…probably on the planet. Hand-toasted some pecans, used duck eggs and goat butter plus a CUP of maple syrup, and a dash of salt = pie bliss…

wilkerlucio00:11:38

sounds delicious 🙂

wilkerlucio00:11:48

can you send a picture?

tony.kay01:11:30

I thought that might be overkill. I am gluten-free as well, so the crust is made of almonds.

tony.kay01:11:38

It sorta got partially eaten before photographed…

tony.kay07:11:30

Turns out there was a bug in Om Next’s code on master related to refresh under adv optimizations. It is unreleased code in Om Next, but those of you using Fulcro 1.0, beware if Om bumps without a patch. The problem is how mounted? is implemented. Just pushed a fix to 2.0.0-SNAPSHOT.

tony.kay07:11:57

Issue submitted to Om

tony.kay07:11:23

Just pushed Fulcro CSS 2.0.0-SNAPSHOT to clojars. Works with Fulcro 2.0 without pulling in Om Next now.

tony.kay07:11:41

Fulcro SQL 0.3.0-SNAPSHOT also pushed without Om Next dependency

tony.kay07:11:42

Fulcro 2.0.0-alpha4-SNAPSHOT is the actual version of Fulcro pushed 🙂

tony.kay08:11:23

@wilkerlucio Finally got a chance to try the new fulcro-inspect. Very nice indeed 🙂

tony.kay08:11:49

can’t wait for that “click on component to focus” feature 😉

LL10:11:04

@tony.kay Need help, I just want use fulcro-datomic in fulcro-template, when (go), get a fatal log: Transaction function failed to return a list of transactions! fulcro-template.migrations.initial-20171124

LL10:11:44

I had checked the code, and found the problem is come from all-migrations* in fulcro-datomic.datomic.schema.

LL10:11:30

because the txn is like

[{:db/index false, :db/unique :db.unique/value, :db/valueType :db.type/string, :db/noHistory false, :db/isComponent false, :db.install/_attribute :db.part/db, :db/fulltext false, :db/cardinality :db.cardinality/one, :db/doc "", :db/id #db/id[:db.part/db -1000221], :db/ident :file/path} {:db/index false, :db/unique :db.unique/value, :db/valueType :db.type/string, :db/noHistory false, :db/isComponent false, :db.install/_attribute :db.part/db, :db/fulltext false, :db/cardinality :db.cardinality/one, :db/doc "", :db/id #db/id[:db.part/db -1000222], :db/ident :file/name} ]

LL10:11:29

and

(if (contains-lists? txn)
              (let [data-fn (meta txn)]
                (vector (migration-keyword nspace) (merge {:txes txn} data-fn)))
              (do
                (timbre/fatal "Transaction function failed to return a list of transactions!" nspace)
                []))

LL10:11:07

the

;; need this for testing..fatal is a non-mockable macro
(defn contains-lists? [l]
  (every? sequential? l))

LL10:11:56

will check if the element is sequential, but the map is not,

LL10:11:07

How should I do?

LL11:11:04

@tony.kay Sorry, I think I know the reason.

LL11:11:26

I miss a

[]
in transactions fn in the .migration.initial-* clj file.

wilkerlucio12:11:19

@tony.kay thank you 🙂, we are getting there, I'm still completing the network tab, yesterday I the table designs and details, but currently there is no way to know which network triggered the request, finishing that the next is the element 🙂

uwo18:11:21

if I’m getting “no app connected” with fulcro-inspect, what am I likely missing?

uwo18:11:46

oh. I see it failed during install because fulcro/register-tool wasn’t defined

uwo18:11:58

(bumping to fulcro 1.2.0 fixed)

tony.kay18:11:59

@tpliliang Yeah, the nesting is a bit strange on that one…

uwo20:11:47

I assume it’s not possible to get computed properties within ident, since it’s a static method? e.g.

static om/Ident
  (ident [this props]
         (let [{:keys [::option-key]} (om/get-computed this)]
           [:option/by-key (option-key props)]))
no way to do this dynamically?

tony.kay20:11:18

So, ident is mostly called within the context of a static component

tony.kay20:11:47

during normalization…where the only thing available is the cold hard props of the incoming data (from the network)

tony.kay20:11:30

ident is also used during UI refresh..but at that point the identity has to have already been established, so it makes no sense.

tony.kay20:11:18

the ident can’t change based on parent ideas….it is already in the database at some specific ident 🙂

uwo20:11:06

right, makes sense. I’m building a select widget, and I don’t always know the shape of the queried options, so I allow the consumer of the widget to specify their own option key function, but this is known at compile time so there must be some way to accomplish, no?

tony.kay20:11:50

So, if you want a reusable widget, then you want well-known structure of some kind. I recently added a demo with cascading dropdowns

tony.kay20:11:50

it uses the bootstrap dropdown that is part of Fulcro

tony.kay20:11:36

I’d give the select widget itself a schema (e.g. namespaced props that are spec’d) and map the server data onto that…

tony.kay20:11:07

I was lazy and just made the server understand the prop names the widget wanted, but you could also use a post-mutation or something to morph it

uwo20:11:26

I mean I know that I could force options to always have a :db/id, for sure

tony.kay20:11:50

doesn’t have to be a :db/id…just something unique within the selection

tony.kay20:11:03

you have to have that no matter what…how else would you know what was picked?

uwo20:11:17

well that’s the only thing that I know for sure. because the select widget is used again tons of different things

tony.kay20:11:24

but you can also choose not to normalize the items if you want

uwo20:11:59

I was going the direction of not normalizing initially, but I’d like to set :focused? on the options individually, and it seemed like an ident would be the way to get that address without iterating over them all

tony.kay20:11:09

So, do you want your real database entities to be the target of selection, or are these for selecting some crap in the UI that you invent as you invent the UI?

tony.kay20:11:15

or perhaps both?

uwo20:11:41

ah, hmm. I don’t want the real database entities to be the target of selection. good point

tony.kay20:11:47

they can be

tony.kay20:11:51

that is not my point

tony.kay20:11:02

I’m asking what level of generality are you programming to?

tony.kay20:11:14

because it is perfectly fine to put your entities in a selection list

uwo20:11:34

I think this is “selecting some crap in the UI”. I’m setting the focused option in the dropdown so that when, say, a person presses arrow down/up I can update (move focus)

tony.kay20:11:21

Ah, so you’re making a more interactive thing…ok. So your select control itself needs to keep track of either an offset index or the identity of the item focused

tony.kay20:11:45

the latter lets the item draw the highlight, the former lets the parent do it

uwo20:11:08

nicely put. thx

tony.kay20:11:09

actually, the former could be used by the parent to pass in computed data to tell the child to do it…lots of options

uwo20:11:46

when I designed this previously (in quiescent) I just set a focused index on the parent, however this forces every option to update when that changes. So I was thinking I’d try setting focused on the actual option

tony.kay20:11:28

but the data model is central:

{ :select-box/id :which-thing-you-want
  :select-box/focus-index 0
  :select-box/items [ [:select-item/by-id :thing-1] [:select-item/by-id :thing-2] ]}

tony.kay20:11:04

VDOM diff will keep the children that have not changed from updating…for that matter, Fulcro’s built-in shouldComponentUpdate won’t refresh anything that didn’t have data changes

tony.kay20:11:46

I prefer the index for a single-select, and a per-item data field for multi-select

uwo20:11:03

oh, in the approach I was describing I’d be passing in the focused-index to each option, so when it changed shouldComponentUpdate would trigger

tony.kay20:11:04

so, the latter is more general purpose, since it just becomes an invariant based on type (single or multi)

tony.kay20:11:31

oh right…sure…that’s true, but still VDOM diff would make it lightweight

tony.kay20:11:11

if you put the data in the item, then you’re goign to either have to clear it on all and set it on one, or remember where it was set…easy source of bugs

uwo20:11:14

but no reason to do that, derp. I can just compute :focused? while mapping over the options before passing them their props, no?

tony.kay20:11:42

sure, and pass as computed

uwo20:11:11

ah, even better. I was just going to assoc a property

tony.kay20:11:18

so they get true/false…only two yupdate

tony.kay20:11:28

no, use computed, or it will break in weird ways

uwo20:11:41

groovy. thanks as always, Tony

tony.kay20:11:08

as you get better at this you’ll continue have these “derp” moments. I certainly have

tony.kay20:11:20

I’m still shocked at times at how easy this stuff has gotten

uwo20:11:44

I’ve had a couple of satisfying “aha”, alternatively “derp”, moments recently. good fun

tony.kay22:11:27

So, this is cool: I am working on cleaning up the dynamic queries, and found a pretty easy way to make them not require any source changes from 1.0 -> 2.0 🙂

tony.kay22:11:47

they still behave slightly differently, but this is a general win in my books

uwo22:11:52

hmm. so when I use the computed approach, newly focused options are updated, however previously focused options do not update. Am I missing a follow on read or something?

tony.kay22:11:31

you’re mapping over all of the options from the parent, with a computed that gives them t/f for focused?

tony.kay22:11:08

Ah, are you using a callback to the parent to change the focus? (e.g. is the key event going to the parent, and the transact happening there?)

tony.kay22:11:15

(mapv (fn [option] (ui-option (computed option {:focused? (= (:index option) current-selection-index)}))) options)

uwo22:11:06

yes to 1, no to 2. my transact to change focus is getting passed this from the option. So i should make the focus fn a computed as well

uwo22:11:49

I also think I’m being stupid about not composing queries + using assoc

tony.kay22:11:51

you’re changing parent state (selected index), so the parent should run that transact!…send an onSelect via computed

uwo22:11:01

makes total sense. derp

tony.kay22:11:40

UI Refresh rules are rather simple: - The component running transact! will re-render - If the component has an ident, anything on the UI with the same ident value with refresh (I think that’s true) - Otherwise, follow-on reads.

uwo22:11:27

omg this approach to ui development is so glorious

tony.kay22:11:02

spread the word 🙂

uwo22:11:28

cool. I’ve got it working with computed. however all options are rerendering, not just the two that need the change

tony.kay22:11:02

shouldComponentUpdate on them should short-circuit unless you’re actually changing data being sent to them

tony.kay22:11:28

you’re sending a boolean to them, not an index, right?

tony.kay22:11:38

cause if you’re sending an index, they’re all seeing a change in data

uwo22:11:40

hmm. I’m passing indices to the options via map-indexed lol

uwo22:11:51

I figured it would be stable

tony.kay22:11:54

should be…unless you’re reordering

tony.kay22:11:04

also, how do you know they’re re-rendering?

uwo22:11:49

printing from with each options render fn

tony.kay22:11:15

k…was just making sure you didn’t have the print at the factory level 🙂

uwo22:11:16

I’ve always used map-indexed for this sort of this (in quiescent). not sure how to approach

tony.kay22:11:23

It should be fine…I would ask why you’re worried about a VDOM diff on something so small? Or is it like 1000's of options?

tony.kay22:11:56

There could be a bug in Om…but if the data, state, and computed don’t change, then render should not get called.

uwo22:11:31

oh, well I guess i never was in the past, however since I’m redoing widgets that I’ve written before I thought I might try for improvements. Also i figured whatever approach caused the fewest renders might be more idiomatic anyway.

tony.kay22:11:43

The rendering should take care of itself if you take care of the data model.

tony.kay22:11:15

The only app I’ve seen with speed problems so far in the Om Next universe has more to do with writing inefficient queries. That can kill you.

tony.kay22:11:09

it is why the UI routers and dynamic queries exist, so you don’t end up with over-querying to feed the “current screen” of UI. That will be where your optimization effort will go. Don’t worry about shouldComponentUpdate stuff. If there’s a bug there, it’ll get fixed.

tony.kay22:11:22

I mean…if you find a bug, report it 🙂

uwo22:11:25

right. yeah. I mean our old quiescent app isn’t terrible, and our render loop is literally recursive calls to .requestAnimationFrame. so this will already be much better

tony.kay22:11:23

Fulcro 2.0.0-alpha4 on clojars. Removes the need for IDynamicQuery, makes your Fulcro 1.0 app API compatible with 2.0 for queries on components. The set-query! API still uses the (optional) new qualfiers based on factories…but this fixes composition as well, and was fairly easy to do…mostly I deleted code (added like 2 lines, removed like 20).

tony.kay23:11:54

put index and react-key in computed

tony.kay23:11:09

never modify anything you got from a query

uwo23:11:32

oh wow. even react-key. interesting

tony.kay23:11:32

so here’s why: What happens if we re-render an Option by itself? I can query for it’s props via the database, and re-run JUST the render of that component…where will ::index and :react-key come from? Select isn’t involved…

tony.kay23:11:14

That is why computed exists…If it didn’t come from the database, you need to let the system know it is extra data that has to be kept around should the component get updated (via a mutation/re-render) in isolation

tony.kay23:11:28

it will render right the first time, but then you could see weirdness on refresh

uwo23:11:16

ah, I see. I thought computed was just to get around the fact that passing functions props would always cause rerenders, but, as the name suggested, it’s computing and storing data

tony.kay23:11:40

right…you’re telling it that you’re adding in some parent-calculated data

tony.kay23:11:01

maybe we should rename it include-parent-calculated-data 😜

uwo23:11:25

moving react-key doesn’t appear to work, however. I’m not specifying a keyfn when buildng the ui-option factory, and I was using react-key to pass it in. Now it’s barking at me for not providing a key

tony.kay23:11:30

the callback stuff is true as well, but that can never come from the database ::)

tony.kay23:11:48

you’re destructuring let

tony.kay23:11:58

oh right. :react-key is special

tony.kay23:11:43

so, if you put that on props, it will end up being your key. Let me think about the targeted refresh on that one…

tony.kay23:11:53

I mean, to be clean, it should just be on your factory

tony.kay23:11:17

the targeted refresh calls forceUpdate, so I don’t knwo that the key would even get checked

tony.kay23:11:10

you can pass it in as computed and put it as key on the top-level element, right?

tony.kay23:11:21

I think React is OK with that

uwo23:11:56

I though that functioned slightly differently, but that’s a vague memory

tony.kay23:11:04

me too…vague

tony.kay23:11:15

yours isn’t a real thing on the DOM

tony.kay23:11:22

but don’t remember if VDOM cares

tony.kay23:11:44

I always use the factory, so I’m grasping a bit in the dark on that one

uwo23:11:58

we previously allowed people to provide their own key-function when invoking a widget like this, but I like your idea of just ensuring that there is some known structure at design time. be that a :db/id, or some client namespaced key that the server is sure to provide

uwo23:11:20

I’m going to just drop the react-key in preference to keyfn

tony.kay23:11:25

it always pays to have that kind of clean data model. So much easier to reason about too

uwo23:11:07

so, were you saying that passing in the index would be causing a rerender in all options. like i have it in the example above?

tony.kay23:11:40

it should not

tony.kay23:11:47

if the key was unstable it would

tony.kay23:11:56

or if the react key of the parent was unstable it would

tony.kay23:11:02

hot code reload DEFINITELY will

tony.kay23:11:24

if a react key changes in any element, that entire subtree is guaranteed to be fully re-rendered

tony.kay23:11:52

React throws out any DOM (and VDOM) whose key has changed

uwo23:11:39

I follow on the hot code reload. but this is triggering rerender in all options between code reloading

uwo23:11:48

err. not during code reloading

uwo23:11:06

I realize the vdom diff is still giving me perf, but now I’m just obsessing about how to potentially prevent render from being called on each option 🙂

tony.kay23:11:18

shouldComponentUpdate will return false if props and state have not changed. So, log your props and state and see what’s changing

tony.kay23:11:35

if neither, then some react key in some parent is changing (or isn’t set?)

uwo23:11:44

and also take account of the return value of computed props?

tony.kay23:11:03

yes, computed is passed through props, just in a way Om can record

tony.kay23:11:38

If you dump (om/props this) you’ll see the computed key I think

uwo23:11:31

hmm. when I dump state I don’t see any stored state for the Option ui at all 😊

tony.kay23:11:51

isn’t that expected? You didn’t set any did you? (I assume you’re talking about component-local state, i.e. (get-state))

uwo23:11:05

oh, I was dumping app-state

tony.kay23:11:23

Another note to those that might be interested (@wilkerlucio @gardnervickers @mitchelkuijpers @currentoor?) That long-standing issue of the compiler hack that breaks adv compilation…I have an idea how to fix it and get rid of the compiler hack 🙂 https://github.com/fulcrologic/fulcro/issues/67