untangled

NEW CHANNEL: #fulcro
adambros 2017-02-23T00:00:01.003935Z

so for example, we have :workers, that just shows all the workers, but you could have an :exceptional-workers view that showed only the top x% of workers

adambros 2017-02-23T00:00:27.003936Z

you would query at Root for {:exceptional-workers (om/get-query WorkerRow)} and then pass that to ui-exceptional-workers

adambros 2017-02-23T00:00:47.003937Z

you then have to filter that list in ExceptionalWorkers/render, but you can do whatever you need to in that method

adambros 2017-02-23T00:02:52.003938Z

im slightly doubting myself, but i think the alternative is not really provided to you in untangled. ie in just om next you would write a parameterized read method that would filter the workers list as it was de-normalizing but with untangled weโ€™ve made the decision that that is not worth the cost in having to understand and maintain parsing code (which can get quite complicated) instead you just massage the data as you need to in your components

adambros 2017-02-23T00:06:23.003941Z

id have to think a bit more, whereas @tony.kay could just tell you, but there are more techiniques for having and updating those views

adambros 2017-02-23T00:07:13.003942Z

i think what untangled pushes you towards is that when you load your workers from the server, you would have a post-mutation that would create another view of that data based on your filter/logic

adambros 2017-02-23T00:07:49.003943Z

but all you are doing is creating pointers (idents) to the same table of data

adambros 2017-02-23T00:08:14.003945Z

anyway, wall of text alert!

urbank 2017-02-23T00:08:47.003947Z

I like walls of text. Lots of information ๐Ÿ™‚

adambros 2017-02-23T00:08:48.003948Z

before you go thinking im right, i would read the devguide until @tony.kay confirms or adjusts my statements

urbank 2017-02-23T00:11:06.003949Z

Right, I will. What I understand of the framework, I like what I see. There's going to be a pretty big rewrite over here, and I've been agonizing for a while on what to use

urbank 2017-02-23T00:11:11.003950Z

this seems very promising

adambros 2017-02-23T00:11:52.003951Z

whatโ€™s the rewrite from?

urbank 2017-02-23T00:13:29.003952Z

A horrible mess of global listeners via jquery. And a bunch of plugins which are really expensive to load. It's quite painful, but they made it in a hurry (for some reason)

urbank 2017-02-23T00:14:51.003953Z

For the main part of the app, there's one big HTML file and one big JS file.

adambros 2017-02-23T00:15:42.003954Z

are you debating between languages, or cljs libraries?

urbank 2017-02-23T00:17:55.003955Z

The HTML is basically this giant empty form. The javascript then inits a punch of plugins. Adding dynamic elements is done by cloning the initial ones on the page (emptying them if needed)

urbank 2017-02-23T00:18:55.003956Z

Anyway, we're mostly settled on clojurescript at this point. Not completely discounting other languages though.

adambros 2017-02-23T00:18:57.003957Z

sounds nasty, like anything would be better but i would say that you will find subtler and more pervasive problems in any other libraries

adambros 2017-02-23T00:19:45.003958Z

personally i would go with untangled or re-frame

adambros 2017-02-23T00:19:57.003959Z

re-frame mainly because its a well established pattern and used by a lot of cljs devs (as far as i know)

adambros 2017-02-23T00:20:49.003961Z

but if you are ok with some minor turbulence and a work in progress, untangled is much more geared towards helping you create a solid enterprise level application

adambros 2017-02-23T00:21:27.003962Z

i dont think iโ€™ve seen a better fleshed out full stack framework in clj(s)

adambros 2017-02-23T00:22:46.003965Z

is your app just client side right now?

urbank 2017-02-23T00:23:14.003967Z

Well, after fighting with the current mess, I'm not too worried about some turbulence here and there. The main thing is that the core concept is solid

adambros 2017-02-23T00:23:45.003968Z

youโ€™ll get plenty of that (solid foundations) with @tony.kayโ€˜s stewardship

qqq 2017-02-23T00:25:22.003970Z

make the back end support GAE pls ๐Ÿ™‚

adambros 2017-02-23T00:26:30.003973Z

@qqq what does that mean?

adambros 2017-02-23T00:26:46.003975Z

iโ€™ve written a more modular way to build an untangled-server, but what exactly does supporting GAE mean?

qqq 2017-02-23T00:27:28.003979Z

I'e like the backend to be based on datastore + easy to deploy to GAE, rather than based on datomic

qqq 2017-02-23T00:27:40.003981Z

client side -- probably nothing needs to be changed

adambros 2017-02-23T00:27:47.003983Z

thereโ€™s no hard dependency on datomic on the backend

qqq 2017-02-23T00:28:10.003985Z

yeah, but there's no trivial one-line support for GAE either (I'm working on this myself right now)

qqq 2017-02-23T00:28:22.003987Z

right now, I'm trying ot get the untangled-todomvc to run on GAE by changing the server side

urbank 2017-02-23T00:28:49.003989Z

Hm... so I'm not quite sure what you mean by "is my app just client side right now". If I'm only testing out the clientside of untangled? If so, yes. Unfortunately I have much more say over the clientside than I do over the server. So I'm not very confident if I'll be able to push that one through ๐Ÿ™‚

adambros 2017-02-23T00:29:17.003990Z

it seems you are more talking about supporting whatever persistence layer GAE uses with the way weโ€™ve structured the server it should just be a component that you put in the parser-injections and use in your reads and mutations

adambros 2017-02-23T00:29:56.003992Z

I more meant is there a server side you are trying to port over to something else

adambros 2017-02-23T00:31:51.003993Z

do you need something else that isnโ€™t currently supported by untangled? I dont think that we have the man power to directly write that layer for you, but I can try to help get what you might need from untangled-server into our schedule

urbank 2017-02-23T00:32:35.003996Z

Oh that. Well, the server code is not nearly as much of a mess, so I think it's pretty likely going to stay as is. At least there's not going to be a huge overhaul.

adambros 2017-02-23T00:33:15.003997Z

gotcha, well you should be able to make that work by tweaking the untangled-client :networking, iโ€™m assuming its a REST server? ie: /workers /workers/:id /workers/:id/edit

qqq 2017-02-23T00:34:18.004Z

@adambros: maybe it's best if I just post questions as I run into problems porting it to GAE

qqq 2017-02-23T00:34:25.004002Z

I don't think I currently know enough to even know what to ask for

adambros 2017-02-23T00:35:03.004004Z

well, do you have a link to something that might give an overview on how to use gae?

qqq 2017-02-23T00:35:23.004006Z

yeah, I have a clojure gae setup working fine

qqq 2017-02-23T00:35:35.004008Z

I also have the untangled-todomvc client+server working fine; I just need to mash the two code bases togehter

urbank 2017-02-23T00:35:39.004010Z

Yeah, It's a REST server. Transitioning to a bit of a cleaner API, so it should be good

qqq 2017-02-23T00:36:25.004011Z

so I started writing my app in gae, using clj on server side + reframe/cljs on client side: -- then I realized "hmm, this om/next thing makes sense since communicating between server/client is a bitch" -- then I stumbled across untangeld and it seems like you guys solved precisely the communication problem I was dealing with

adambros 2017-02-23T00:36:41.004013Z

well so om.next (& therefore untangled) just talk to an /api route by sending it data/queries

adambros 2017-02-23T00:37:29.004014Z

so reads are [:key {:join [:a :b]}], and mutations are similar [('launch-rockets! {:id 23})]

adambros 2017-02-23T00:38:36.004016Z

so if the cleaner api is still rest, you will have to write (or find) some translator layer but iirc some people here might have more to say on that

adambros 2017-02-23T00:39:49.004017Z

yeah untangled does a lot on top of om.next to help you make an application

adambros 2017-02-23T00:40:12.004019Z

well let me know if you have a specific, or even abstract, question about untangled regarding the server interaction

qqq 2017-02-23T00:42:56.004021Z

this is very very very minor; but I think untagngled docs can be improved if, for eacy devguide devcard, thre was a link to a github repo *.clj sfile

urbank 2017-02-23T00:43:16.004022Z

Yes, I thought it would be something like that. I would look into not using REST, and just going with this full-stack, but I'm not really in charge of that. I do need something flexible and well thought-out on the client. And there aren't that many requests. Most of the complexity, as far as the client-side is concerned, is in this input form.

adambros 2017-02-23T00:47:02.004024Z

@qqq sounds nice, feel free to file an issue on it

urbank 2017-02-23T00:48:51.004025Z

Well, it's getting really late over here. Looking forward to exploring this further tomorrow.

adambros 2017-02-23T00:50:28.004027Z

nearly 2am kinda late, europe?

urbank 2017-02-23T00:50:47.004028Z

Yup ๐Ÿ™‚

adambros 2017-02-23T00:51:26.004029Z

look out for a message from tony, heโ€™ll likely write something about my earlier comments

adambros 2017-02-23T00:52:18.004030Z

oh and g'nite

urbank 2017-02-23T00:54:13.004031Z

Great, will do! Good night, and thanks again for the help/discussion! (telling someone about the mess that is the current code I'm maintaining was cathartic as well ๐Ÿ™‚ )

โœŒ๏ธ 1
adambros 2017-02-23T01:40:02.004033Z

@tony.kay I can confirm that I can fix my problem by having the post-mutations transacted, instead of used just for their :action

adambros 2017-02-23T01:41:32.004034Z

whether thatโ€™s a good idea ๐Ÿ˜•

qqq 2017-02-23T02:07:00.004035Z

1) I already have a basic untangled/devcard/defcard setup working. 2) I have inserted the code

(defui ^:once Counter
  static uc/InitialAppState
  (uc/initial-state [this {:keys [id start]
                           :or   {id 1 start 1}
                           :as   params}] {:counter/id id :counter/n start})
  static om/IQuery
  (query [this] [:counter/id :counter/n])
  static om/Ident
  (ident [this props] [:counter/by-id (:counter/id props)])
  Object
  (render [this]
    (let [{:keys [counter/id counter/n]} (om/props this)
          onClick (om/get-computed this :onClick)]
      (dom/div #js {:className "counter"}
        (dom/span #js {:className "counter-label"}
          (str "Current count for counter " id ":  "))
        (dom/span #js {:className "counter-value"} n)
        (dom/button #js {:onClick #(onClick id)} "Increment")))))
3) Now my question is -- how do I create a minimal devcard which shows the above? (In the devguide, we ahve to create something like 5 more components before we can display any of them). I just want to interact with this one component NOW.

qqq 2017-02-23T02:22:40.004036Z

does untangled provide CRDTs (or things similar) or is this something users have to make their own decisions on

adambros 2017-02-23T02:22:56.004037Z

what are the 5 more components you are talking about?

adambros 2017-02-23T02:26:18.004039Z

having not heard of those before in any untangled conversation, I would say itโ€™s up to you

adambros 2017-02-23T02:27:11.004041Z

not sure if itโ€™s related, but one of our teams are using hazelcast...

qqq 2017-02-23T02:28:44.004043Z

At minute 11:30 of https://www.youtube.com/watch?v=IeIyQDg9gBc it talks about "merging data"

qqq 2017-02-23T02:29:10.004046Z

the only method I know of is: https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type -- (which Phoenix Presence also uses)

adambros 2017-02-23T02:31:50.004049Z

not sure i understand, what are you wanting to replicate, and across what?

adambros 2017-02-23T02:32:44.004051Z

this sounds like something your db/persistance layer uses/implements

qqq 2017-02-23T02:33:45.004053Z

can we discuss this over DM ? I understand you don't want to clustter the main channe, but this threading UI is really weird to use on my laptop

qqq 2017-02-23T02:35:25.004055Z

http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.A_Quick_Tour -- CounterPanel, Root, SampleApp, "5" may have been an overestimate

adambros 2017-02-23T02:37:15.004057Z

iโ€™d rather keep it in the channel

adambros 2017-02-23T02:37:29.004059Z

so the example you gave you should be able to just plop in a card

adambros 2017-02-23T02:37:43.004060Z

you dont really need a panel or sampleapp

qqq 2017-02-23T02:38:02.004061Z

okay, so I've done that

qqq 2017-02-23T02:38:06.004062Z

I now ahve the following problem

qqq 2017-02-23T02:38:15.004063Z

are "id" and "n" supposed to be numbers or Objects or what?

qqq 2017-02-23T02:38:29.004064Z

when I do

(. js/console log (str "id: " id))
the js console prints it out as:

qqq 2017-02-23T02:38:39.004065Z

id: [object Object]

qqq 2017-02-23T02:38:47.004066Z

so it seems like somehow I'm not getting the value

adambros 2017-02-23T02:39:21.004067Z

weird, not sure about that, maybe try prn?

qqq 2017-02-23T02:41:53.004068Z

that did not fix it: however, commenting out the: static uc/InitialAppState static om/IQuery static/omIdent lines did fix it I must ahve some type of error in one of those lines

adambros 2017-02-23T02:42:16.004069Z

ah its not

adambros 2017-02-23T02:42:26.004070Z

static uc/InitialAppState (uc/initial-state

adambros 2017-02-23T02:42:38.004071Z

but static uc/InitialAppState (initial-state ...

adambros 2017-02-23T02:42:53.004072Z

you dont namespace the method names

qqq 2017-02-23T02:43:16.004074Z

wait, so there's a bug in http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.A_Quick_Tour ?

adambros 2017-02-23T02:43:46.004075Z

maybe? does that fix it or was i wrong?

qqq 2017-02-23T02:44:06.004076Z

err, currently trying to fix shy the Increment button throws an error

qqq 2017-02-23T02:45:56.004077Z

okay, changing uc/initial-state to initial-state fixed it

qqq 2017-02-23T02:48:33.004078Z

these two lines:

(let [onClick (om/get-computed this :onClick)] ...)
^^ how that does line cause onClick to increment?

noonian 2017-02-23T02:52:05.004079Z

That is just getting a reference to a prop and calling it onClick. This is where it is using it as an onClick handler: (dom/button #js {:onClick #(onClick id)} "Incrementโ€)

qqq 2017-02-23T02:52:37.004080Z

right, so where is the #(+ 1 %) or inc ?

qqq 2017-02-23T02:52:43.004082Z

where does the actual "inrementing" occur?

noonian 2017-02-23T02:53:10.004083Z

It is assuming that the parent component is passing in a function for that prop that will actually do the incrementing.

qqq 2017-02-23T02:53:17.004084Z

ah

noonian 2017-02-23T02:53:45.004085Z

In CounterPanel: (map #(ui-counter (om/computed % {:onClick click-callback})) counters)

qqq 2017-02-23T02:53:47.004086Z

oh right, i see it now

qqq 2017-02-23T02:54:02.004087Z

click-callback (fn [id] (om/transact! this `[(counter/inc ....

noonian 2017-02-23T02:54:09.004088Z

Yep

noonian 2017-02-23T02:56:00.004089Z

The actual increment function implementation is defined near the beginning: (defn increment-counter [counter] (update counter :counter/n inc))

qqq 2017-02-23T03:01:35.004090Z

sure, let's kill threading though; the window is too narrow on my mbp

adambros 2017-02-23T03:03:25.004092Z

you can view it full screen by clicking on All Threads above your starred channels

qqq 2017-02-23T03:34:03.004094Z

where do I get untangled-devguide.tutmacros from ?

noonian 2017-02-23T03:40:41.004095Z

Its in the repo for the devguide: https://github.com/untangled-web/untangled-devguide/blob/master/src/devguide/untangled_devguide/tutmacros.clj Just a single macro and its specific to devcards.

qqq 2017-02-23T03:50:59.004098Z

(:require [....
[untangled.client.data-fetch :as df]])
^^ this causes a a cljs analyzer error

qqq 2017-02-23T04:13:26.004100Z

woot, got QuickTour example working

qqq 2017-02-23T04:21:34.004101Z

What does "static" mean in the context of defui ?

qqq 2017-02-23T06:06:40.004103Z

devcards / untangled / :history / :insert-data is amazing

qqq 2017-02-23T06:55:06.004104Z

in (dom/... ) how do I generate a checkbox?

qqq 2017-02-23T06:55:13.004105Z

I tried (dom/input {:type "checkbox"})

urbank 2017-02-23T08:24:21.004106Z

@qqq I think you have to say (dom/input #js {:type "checkbox"}) so that the dom attributes is a javascript object

๐Ÿ‘ 1
qqq 2017-02-23T08:39:53.004108Z

@urbank: ah right, thanks!js could really give me a more helpful debug msg than a 20-frame deep react stackframe

qqq 2017-02-23T08:40:34.004109Z

btw, the untangled devguide exercises are awesome

qqq 2017-02-23T08:40:44.004110Z

whoever wrote that guide deserves to have their salary doubled

adambros 2017-02-23T08:41:06.004111Z

https://github.com/r0man/sablono

qqq 2017-02-23T08:41:56.004113Z

@adambros: is that useable with om/untangle? I actually like the reframe style hiccup more than om/untangle's dom thingly,

adambros 2017-02-23T08:42:11.004114Z

definitely

adambros 2017-02-23T08:46:15.004115Z

afaik the only reason we dont use it in untangled is tony is against exporting extraneous dependencies

adambros 2017-02-23T08:46:38.004116Z

imo we should just all be using it, but iโ€™m not in charge ๐Ÿ˜…

qqq 2017-02-23T08:47:44.004118Z

you also like hiccup style [:ul [:li ...] [:li ...}} more than om style (dom/ul nil (dom/li nil ...) (dom/li nil ...) ?

adambros 2017-02-23T08:47:55.004119Z

yup

qqq 2017-02-23T08:48:20.004120Z

you know, the biggest obstacle with me working through the guide right now is precisely the (dom/ul, dom/span, dom/li) stuff

qqq 2017-02-23T08:48:29.004121Z

what is a good guide on using sablano / hiccup / reframe style gui in untangle?

qqq 2017-02-23T08:48:37.004122Z

this would drastically incease my productivity

adambros 2017-02-23T08:48:43.004123Z

i dont think there is one, but it should be very easy to use

adambros 2017-02-23T08:49:07.004124Z

iirc when i tried using it you just have to wrap each render method with sablono.core/html

qqq 2017-02-23T08:50:27.004125Z

I'm being greedy here now

qqq 2017-02-23T08:50:37.004126Z

Is ther a way to use https://github.com/Day8/re-com with untangled?

qqq 2017-02-23T08:50:41.004128Z

that'd complete my stack

adambros 2017-02-23T08:52:22.004129Z

see this section of the devguide http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.M10_Advanced_UI

adambros 2017-02-23T08:52:30.004130Z

it covers using react components in untangled, should at the very least point you in the right direction

qqq 2017-02-23T09:08:38.004133Z

i'm surprised untangled isn't more well known

qqq 2017-02-23T09:08:54.004134Z

I suspect part of the problem is that it requires cljs/clj on client/server, and at that point, many ppl have rolled their own framework

qqq 2017-02-23T10:40:19.004135Z

how do I solve this line:

qqq 2017-02-23T10:40:29.004138Z

in particular, how do I pass the "onDelete" into the people object ?

urbank 2017-02-23T10:50:27.004139Z

@qqq Do you know about om/computed ? I think you have to call om/computed on the props that you pass to the child component. (your-child-component (om/computed props {:onDelete ...})) and use om/get-computed on the props of the child component within its render method.

urbank 2017-02-23T10:51:19.004140Z

'props' in the call to om/computed being the props that you're sending the component anyway

qqq 2017-02-23T10:51:58.004141Z

@urbank: yeah, looking at another exampke, looks like I have to use om/computed

qqq 2017-02-23T10:52:10.004142Z

let me try some stuff out, it looks like thing that is hairy to explain, but easy to get to work

urbank 2017-02-23T10:54:13.004143Z

I think it's quite elegant, because it keeps the callbacks and such separate from the actual data the component needs to display.

qqq 2017-02-23T10:57:12.004145Z

I think I should write 10k untangled loc before responding to that ๐Ÿ™‚

qqq 2017-02-23T10:57:43.004146Z

I can assure you taht my current untangled code is NOT elegant by any means, but it's mostly due to my n00biness

qqq 2017-02-23T10:59:41.004147Z

alright, I finished devguide-B onto devguide-C now

qqq 2017-02-23T10:59:55.004148Z

reading the first paragraph -- does untangled purposely choose it's own format, and thus datascript can't be used as the db?

qqq 2017-02-23T11:02:29.004149Z

hmm, so the entire untangled method is to use tables to denormalize and to make sharing explicit ?

urbank 2017-02-23T11:02:45.004150Z

Haha, yeah I'm just learning it as well. I just like the idea that there's a box you put stuff like :onDelete in that separate from data such as :person/name . I think it's mostly an aesthetic preference ๐Ÿ™‚

urbank 2017-02-23T11:03:47.004151Z

Don't really feel qualified to answer the last two question though...

qqq 2017-02-23T11:04:11.004153Z

opinion is fine, at this hour, my choices are : someone else's intuition vs nothing

urbank 2017-02-23T11:08:22.004154Z

Ok, though someone will hopefully correct me if I mislead you. I think untangled has a preset format because it enables a lot of cool automatizations. So I don't think it's meant to be used with datascript. Perhaps it's possible to hack it together somehow, but that might defeat the purpose

qqq 2017-02-23T11:09:22.004155Z

http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.C_App_Database is saying something similar

qqq 2017-02-23T11:09:30.004156Z

but I don't understand it well enough yet

qqq 2017-02-23T11:09:49.004157Z

this is so exciting though; it's like learning programming for the first time

qqq 2017-02-23T11:10:06.004158Z

it's like going from qbasic to scheme, when you realize you have been doing all this wrong all this time

urbank 2017-02-23T11:10:52.004159Z

Yeah, it is exciting!

qqq 2017-02-23T11:12:59.004160Z

okay, I get it now it's definitely NOT datascript compatible

qqq 2017-02-23T11:13:29.004161Z

all data in untangled db is of the following format, it has a "2-level key" and the value

qqq 2017-02-23T11:13:40.004162Z

the key is of the format [keyword id], where keyword has to be a keyword, and id can be anything

qqq 2017-02-23T11:13:59.004163Z

so the [keyword id] "pair" serves as the "key" (called an "ident")

qqq 2017-02-23T11:14:20.004164Z

the db is a bunch of (ident, value) pairs, though it's stored as a 2-level table indexed first on keyword, then on id

qqq 2017-02-23T11:14:35.004165Z

then there's somet function which takes this "tree" and converts it into a "db" (if you have shared components)

qqq 2017-02-23T11:14:43.004166Z

this solves the "diamond" problem mentioned ealier in the devguide

urbank 2017-02-23T11:16:20.004167Z

The one thing I'm confused by is if every [:keyword id] in the db is necessarily an [Ident id] value.

qqq 2017-02-23T11:16:38.004168Z

I don't understand you rquestion.

qqq 2017-02-23T11:16:49.004169Z

type ident = vector of length 2, where first elem = keyword, second elem = anything

urbank 2017-02-23T11:18:00.004170Z

right. so [:keyword id] is in ident. But what if the db stores something which is a [:keyword some-value], but it shouldn't be treated as an Ident

urbank 2017-02-23T11:18:14.004171Z

I mean, I'm not sure if that would even come up, but still

qqq 2017-02-23T11:18:26.004172Z

I think the answer is: don't do that

qqq 2017-02-23T11:18:34.004173Z

the way I think about this is as follows:

qqq 2017-02-23T11:18:37.004174Z

keyword = maps to the name of the table

qqq 2017-02-23T11:18:47.004175Z

id = maps to the "key" in the table

qqq 2017-02-23T11:18:58.004176Z

this an ident = [keyword id] = saying in table XYZ, item ABC

qqq 2017-02-23T11:19:19.004177Z

^^ this may be entirely wrong but it's my urrent mental model

qqq 2017-02-23T11:20:04.004178Z

this also maps amazingly well to gae/datastore, so I'm very happy

urbank 2017-02-23T11:22:01.004179Z

Yeah, I think that's the right way to look at it.. and "don't do that" probably is the answer with regards to storing stuff that just looks like idents ๐Ÿ™‚

qqq 2017-02-23T11:22:48.004180Z

you can store stuff that looks like idents

qqq 2017-02-23T11:22:54.004181Z

they get resolved in the normalization process

qqq 2017-02-23T11:23:18.004182Z

for example, section "Everything in Tables"

{ :lists/by-category { :friends { :list/id :friends :people [ [:people/by-id 1] [:people/by-id 2] ] }
                       :enemies { :list/id :enemies :people [ [:people/by-id 5] [:people/by-id 9] ] }}
  :people/by-id { 1 { :db/id 1 :person/name "Joe" :person/mate [:people/by-id 2]}
                  2 { :db/id 2 :person/name "Sally" :person/mate [:people/by-id 1]} ... }}

qqq 2017-02-23T11:23:38.004183Z

i'm happy to hash this out, because I think we each understand 80% of what's going on

qqq 2017-02-23T11:23:44.004184Z

and this gives us a chance to debug each other's understanding

urbank 2017-02-23T11:24:58.004185Z

Yes, I think that's correct. I was talking about storing stuff that looks like an Ident but isn't, and so you don't want it to get resolved

qqq 2017-02-23T11:25:40.004186Z

hmm; I haven't considered that

qqq 2017-02-23T11:26:02.004187Z

so your point is, suppose we ahve an indent [:programmer "Rich-Hickey"]

qqq 2017-02-23T11:26:18.004188Z

but then suppose we wanted to store the data tuple [:programmer "Rich-Hickey"] -- and how do we tell it to not resolve it?

urbank 2017-02-23T11:27:47.004189Z

Yeah, basically. Not sure when you'd want to do that. I'm more wondering whether untangled would try to treat it as an ident

qqq 2017-02-23T11:28:14.004191Z

this is a great question

qqq 2017-02-23T11:28:48.004192Z

I don't think it's answered in Section C exercises; when I get to it in seciton D, E, F, or G, I'll let you know ๐Ÿ™‚

urbank 2017-02-23T11:29:32.004193Z

Ok, thanks! ๐Ÿ™‚

qqq 2017-02-23T11:35:53.004194Z

actually, I lied

qqq 2017-02-23T11:36:02.004195Z

if you look at section 3, exercise 2, it does the ident thing

qqq 2017-02-23T11:36:09.004196Z

basically, the trick appears to be "you can resolve ident manually"

qqq 2017-02-23T11:36:32.004197Z

and thus, when you get [:programmer "Rich Hickey"] you can decide whether you want it as a tuple or to look it up, @urbank

urbank 2017-02-23T11:37:23.004198Z

Ah, that makes a lot of sense!

qqq 2017-02-23T11:39:27.004199Z

want to help me solve exercise 3?

qqq 2017-02-23T11:39:37.004200Z

I'm not quite sure what's going on, but I think this om/db->tree is related to what we're talking about

urbank 2017-02-23T11:40:04.004201Z

Ok, i'll open the page

qqq 2017-02-23T11:40:43.004203Z

bottom of that links to the db exercise, 1 & 2 are trivial, 3 I still don't understand yet

urbank 2017-02-23T11:41:00.004204Z

right, I have it

qqq 2017-02-23T11:41:45.004205Z

I think https://github.com/omcljs/om/wiki/Documentation-(om.next)#db-tree is what we're supposed to understand

urbank 2017-02-23T11:43:22.004207Z

Aha, so that's basically the thing that resolves the queries.

qqq 2017-02-23T11:45:54.004208Z

okay, I got it working

qqq 2017-02-23T11:46:29.004209Z

the answer is:

(def c-ex3-uidb
{:main-panel {:toolbar ...} {:canvas ...}})
where the two ... are filled by (1) wirintg in 0, (2) looking at the error on why it doesn't match nd (3) copying/pasting the answer it's supposed to be

urbank 2017-02-23T11:48:13.004210Z

Aha, so you had to make a db that given that query would return that tree.

qqq 2017-02-23T11:49:28.004211Z

something like that, I'm not exactly sure, the docs confuse me

qqq 2017-02-23T11:49:50.004212Z

like wtf does

db->tree

(om.next/db->tree query some-data app-state-db)
Given a query expression, some data in the default database format, some application state data in the default database format, denormalize it. This will replace all ident link nodes with their actual data recursively. This is useful in parse in order to avoid manually joining in nested relationships.
mean, and why is ex3-uidb passed twice ?

urbank 2017-02-23T11:50:20.004213Z

btw, playing around with om/db->tree I found out that you can use [*] inside a query to get all the attributes of that object.

qqq 2017-02-23T11:50:20.004214Z

alright, I need to sleep

qqq 2017-02-23T11:50:32.004215Z

this was helpful; thanks for the discussion

urbank 2017-02-23T11:51:09.004216Z

I think that an om thing... db->tree needs it twice, probably they can be different. not sure. Ok goodnight! It was helpful to me to ๐Ÿ™‚

qqq 2017-02-23T19:21:52.004217Z

anyone want to work through http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.E_UI_Queries_and_State_Exercises together? I'm currently on Exercise 1

tony.kay 2017-02-23T21:13:14.004218Z

@qqq @urbank On om/computed: The issue is that Om can re-render a component by running the query for the component's data. When it does that, it calls render without going from root (through the parent)...but the query cannot figure out what the parent wants as callbacks (computed stuff of the parent).

tony.kay 2017-02-23T21:13:47.004219Z

By using computed, you're giving Om a chance to cache the last computed values from the last render that went through parent

tony.kay 2017-02-23T21:14:01.004220Z

without computed it would work on the first render, but localized refresh would break

tony.kay 2017-02-23T21:20:14.004221Z

and urbank is right: the db->tree API covers more advanced cases. The two args are in the same format, but need not be the same database. Most uses will just pass the complete app state both times.

qqq 2017-02-23T21:22:09.004222Z

@tony.kay: 1) thanks for creating untangled 2) thanks for occasionally dropping down from mount sinai to answer basic level questions ๐Ÿ™‚

qqq 2017-02-23T21:23:39.004223Z

one thing I don't get about queries:

qqq 2017-02-23T21:24:04.004224Z

is the root query supposed to get EVERYTHING or is it supposed to leave some unresolved for the sub-parts to load on demand?

qqq 2017-02-23T21:25:04.004225Z

concretely, in http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.E_UI_Queries_and_State_Exercises here, I am conflicted over the following: should the root element load the mate of the person too -- or should the root leave that unresolved as a [:db/id NUMBER], and ahve the sub component load it on demand?

tony.kay 2017-02-23T21:35:42.004226Z

So, the root query asks for everything. How much you want in RAM right now and what you want to demand load is totally up to you

tony.kay 2017-02-23T21:36:02.004227Z

and the UI only cares in the sense of triggering the load via some interaction you define

qqq 2017-02-23T21:39:18.004228Z

@tony.kay: suppose I have a root node that has 12 tabs; where only one of the 12 tabs is visible at any given time in the untangled model, do I load the data for all 12 tabs at the root, or only the visible one?

cjmurphy 2017-02-23T21:48:06.004229Z

@qqq: In that case you could use a union query and only one of the 12 would be loaded at any one time.

tony.kay 2017-02-23T21:49:06.004230Z

what @cjmurphy said...but remember that there are 2 concerns: What the UI query processes from RAM -> UI, and what you've loaded from a server. The cookbook shows an example of a tab triggering a network load.

tony.kay 2017-02-23T21:49:07.004231Z

all up to you

tony.kay 2017-02-23T21:50:03.004232Z

the cool think is you can hide the remote trigger for a load from the UI logic. The mutation to navigate just composes in a load

tony.kay 2017-02-23T21:50:32.004233Z

the UI just says "go to tab 5". the mutation looks in RAM and notices..."Oh, don't have that yet...load it"

tony.kay 2017-02-23T21:50:45.004234Z

it is just what you'd hope for: complete flexibility

tony.kay 2017-02-23T21:51:16.004235Z

with the capability of not tying model/logic/app behavior up in the UI itself

qqq 2017-02-23T21:51:48.004236Z

here's another extreme case:

qqq 2017-02-23T21:53:39.004237Z

I have a two panel setup. Left panel = 1 MB of data to render. Right panel = 12 tabs, each of which takes 100kb of data to render. Now, suppose I'm loading the right lazily. Then, when I switch a tab in the right, is the left reloaded (a 1MB data cost) -- or, if it's not -- how does it know the data is not stale?

tony.kay 2017-02-23T21:54:03.004238Z

cache invalidation is your problem (tm) ๐Ÿ˜‰

tony.kay 2017-02-23T21:54:21.004239Z

reloading is completely under your control.

tony.kay 2017-02-23T21:54:28.004240Z

it never ever happens unless you tell it to

qqq 2017-02-23T21:54:46.004241Z

sorry, let me rephrase my confusion

qqq 2017-02-23T21:55:04.004242Z

If "root node is in charge of loading ALL data", then when I switch a tab, wouldn't it automatically relaod the left panel 1MB also ?

tony.kay 2017-02-23T21:55:17.004243Z

no

tony.kay 2017-02-23T21:55:38.004244Z

so, there is a diff between loading (a server interaction) and providing the current client-side app state to the UI

tony.kay 2017-02-23T21:55:48.004245Z

just a min...

tony.kay 2017-02-23T22:03:05.004246Z

the UI query is about moving data from RAM onto the screen. Union queries, mentioned before, allow you to limit what goes from RAM towards the UI to one branch at a time.

tony.kay 2017-02-23T22:03:23.004247Z

The query on the UI is not directly sent to a server, ever

tony.kay 2017-02-23T22:03:35.004248Z

you decide what to ask the server for as part of mutations

tony.kay 2017-02-23T22:03:52.004249Z

The fact that you can use a portion of the UI query to solve that is part of the data-driven story

tony.kay 2017-02-23T22:04:06.004250Z

but don't mistake the total UI query for a server query

tony.kay 2017-02-23T22:04:46.004251Z

the UI concern (union queries) is purely a rendering efficiency concern.

tony.kay 2017-02-23T22:05:09.004252Z

The server interaction concern is addressed by the Untangled data-fetch namespace functions, like load, which you compose into mutations

tony.kay 2017-02-23T22:05:39.004253Z

Using a Person UI component in a load just joins together what that UI component wants with what the server can provide

urbank 2017-02-23T22:10:36.004254Z

Hm... so if I'm not missing something, I think something goes awry with queries if I use [org.clojure/clojurescript "1.9.473"] with untangled, whereas it works fine with [org.clojure/clojurescript "1.9.229"]

urbank 2017-02-23T22:11:30.004255Z

if I do (om/get-query Component) with 473 I get nil back, but I get the actual query with 229

urbank 2017-02-23T22:17:02.004256Z

So I suppose this looks like an om issue

๐Ÿ˜… 1
qqq 2017-02-23T22:20:52.004258Z

(ns app.core
  (:require
    app.mutations ; remember to load your add-on mutations
    [untangled.client.core :as uc]
    [app.ui :as ui]
    yahoo.intl-messageformat-with-locales ; if using i18n
    [om.next :as om]))

(defonce app (atom (uc/new-untangled-client :initial-state { :some-data 42 })))
(reset! app (core/mount @app ui/Root "app"))
http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.F_Untangled_Client where does core/mount come from?

adambros 2017-02-23T22:21:06.004259Z

that should be uc/mount

qqq 2017-02-23T22:26:17.004260Z

(defui ^:once Root
   static om/IQuery
   (query [this] [:ui/react-key ...])
   Object
   (render [this]
      (let [{:keys [ui/react-key ...]} (om/props this)]
        (dom/div #js { :key react-key } ...))))
what does the ... mean ? this is in http://untangled-web.github.io/untangled/guide.html#!/untangled_devguide.F_Untangled_DevEnv

tony.kay 2017-02-23T22:26:47.004261Z

In this case I'm just saying "whatever else"

tony.kay 2017-02-23T22:26:51.004262Z

it is pseudocode

tony.kay 2017-02-23T22:27:02.004263Z

it isn't meant to be literal code

tony.kay 2017-02-23T22:27:21.004264Z

sorry bout that. ... in a proper query would mean recursion

tony.kay 2017-02-23T22:27:42.004265Z

In that case I'm just trying to focus your attention on react-key and nothing else

qqq 2017-02-23T22:34:06.004266Z

@tony.kay: got it; thanks!

tony.kay 2017-02-23T23:41:46.004267Z

welcome

tony.kay 2017-02-23T23:43:32.004268Z

@urbank the version of cljs and Om can be closely tied (e.g. latest + latest is often the case). Om, being a project with close ties to the maintainers of cljs, tends to push the envelope

qqq 2017-02-23T23:47:20.004269Z

@tony.kay : is there any reason idents are exactly 2 levels of a (keyword, id) pair? it seems that if it was "just one level", it'd basically be a virtual pointer and at more than 2 levels, I'm not sure what it is but why was 2 the right number?

tony.kay 2017-02-23T23:49:22.004270Z

because the database format:

{ :table { id { entity }}}
(get-in db [:table id]) <--- thus an ident...the identity of a table entry

tony.kay 2017-02-23T23:49:35.004271Z

everything normalizes into tables. Their ident is their location

qqq 2017-02-23T23:49:52.004272Z

so the db really is meant to be A GROUP OF TABLES, where each TABLE is a bunch of (id, entity) pairs ?

qqq 2017-02-23T23:49:57.004273Z

thus the 2 levels?

tony.kay 2017-02-23T23:59:59.004274Z

yep...flat. The structure is made by idents linking things together