you either:
1. Write a transact that does the two in succession: (om/transact! this '[(a) (b)])
2. Write a transact that calls one (om/transact! this '[(combo)]) and then in that one mutation you do the local updates along with load-action
I think I have to. No way round it - if not actually call, do the equivalent of calling.
Yeah I'll be doing the second, but semantically it is a call of one of the other.
Why not write a query that asks for both facts you need, as a union query. Then the server can tell you everything you need with one load
without loading more than you need
chaining is a bad practice in general
[{:dropdown-options (om/get-query DD)} ({:subdata (om/get-query Union)} {:current-selection :a})]
which you could queue up with two calls (on one event) to load
There are other ways. Good to think...
and use :params to send the current selection
either the server knows the complete answer, or you know a fact you can tell the server. There is no need for chaining in these cases đ
(and two calls to load in the same event handler will be sent together as one request)
(load this :dropdown-options DD) (load this :subdata Union {:params {:current :a}})
Yeah the first mutation is choosing the one to be selected as current in the drop down, but that is the wrong place for that choice, I think...
Itâs tough to un-learn the habits of js đ
Well especially when you never were a js programmer haha!
đ
Youâre doing a thing like âchoose your make of carâ, then âchoose a modelâ, where model gets loaded after they choose a make
right?
Yes - one dd to another dd. My first is types of account - Expense, Income etc
And second is then all the expenses say.
sure
you prob donât even need a union then
Are you saying I should have all the models for all the cars already loaded?
1. the initial setup (e.g. a load of the first dd content)
2. The user interacts with the dd. This triggers (transact! this '[(choose-first {:val v})])
3. The choose-first defmutation:
3a. Threads state through a function that updates the dropdown they interacted with
3b. continues the thread through a load-action that can send the proper query and param based on v
3c. Has a remote of (remote-load env)
When the load completes, the second dd is now populated
(assuming you targeted the load-action result to the dd state, or otherwise got it there with a post-mutation)
Hmm - problem is I need to load the second lot before any interaction.
but you donât know which to load
until they select the first dd content
Yes - the default one that the first mutation is choosing.
how is the default chosen?
you must have known it at step (1), so you can do it during that load
so yes, youâd preload the âmodelsâ for the known âdefaultâ make
By default "Expenses" say. Kind of arbitarily - perhaps the most popular choice in my mind, so user has to do less actions.
yeah, but youâre loading data they may not want to see at all, which is extra overhead for your user and your server
I've got no "No choice" in the drop down.
bad for multiuser performance
but whateverâŚyou can do it either way, as I just describedâŚjust move the default choice load to step (1)
But they are always going to go to the next step.
I donât understand âbutâ. Whatâs missing?
the next step is as I described above
event triggers dd update and next load
Was talking about perf, I didn't get the issue there.
steps 2+
oh
If I make the first choice explicit at the client level (not defmutation level) then I think my design becomes better.
say you show me expenses. You just loaded data from the server. That just consumed CPU and disk IO. Say you have 10000 users. They all go to that screen. You just did 10000 bits of CPU and IO. Now letâs say 20% of them didnât want that. You just blew 2000 users worth of interaction timeâŚslowing down the other 8000 as well.
ie "Expenses" - no reason that should be down at defmutation level - then my problem goes away.
They will all want it in my use case. They are creating a rule that they must create. So the 20% you mention is really 100%.
oh, then you already know everything you need at step 1
Yes. But I needed your help to get a better design. So thanks for taking the time. Working solo here...
NP. Glad it helped
My experience with Untangled so far has been: If itâs hard, youâre doing it wrong or missing a concept.
So, when I run into something that seems difficult, I try to remind myself of that.
so far, I have yet to find anything that didnât work out đ
knock-on-wood
The âchainingâ temptation is tricky: I loaded A, now A told me something that makes me want B. The thing is, unless youâre loading from more than one server, the server knew about what was in A when it sent it to you, meaning you could have also asked for B in a generic sort of way and had it handled at the same time.
Thereâs nothing technically impossible about using transact! within a mutation, other than it leads to a design where you could conceivably end up with recursive-looking transaction loops. So, poor design. If you had to do a two-server chained load, I think youâd probably be stuck with it, though. I just strongly encourage not doing it in most cases. Hm. actually, I take that back. Thereâs no way to get the timing right. Youâd probably have to install a merge handler and trigger the second one from there. Or use a post mutation to trigger a transact! against app. Post mutations are not allowed to have remote sides (theyâre ignored).
If possible, Iâd probably design server A to talk to server B for me, and avoid the whole client scenario đ
hello people, I would like to announce a new little open-source project I built with Untangled, it's a Chrome extension to represent an Youtube Queue based your emails, I made a post about it, I hope you can enjoy it đ https://medium.com/@wilkerlucio/using-gmail-messages-to-track-youtube-channels-ef35308a0ceb
I've watched that video a few times. Is one of the best for understanding things - very good video. I see that load-data does have config as last argument, which can include params. So I guess can achieve [({server-property (om/get-query SubqueryClass)} params)] by other means - in fact I can see that [state-atom server-property-or-ident SubqueryClass config] will do the job.
So -action means it is callable from within a client mutation?? That's the all important thing for me right now.
@cjmurphy yes. The -action is intended to mean that. Itâs really simple how it works: Calls to load basically run a mutation transaction on the untangled mutation load (donât remember the ns). The load mutation gets processed, but what it does is stores your desired load info into an app state load queue. The mutation specifies that it wants to be remote. When the layer just above networking sees the load mutation, it instead pulls the stuff from the load queue in app state and sends those queries instead.
The -action versions are the part that put the load on the queue. So, you still need to specify a remote-side, and data-fetch has a function (`remote-load`) for generating the right-looking thing for the remote side that will cause load queue processing to happen.
any number of load-actions can be run (each adding an entry to the load queue), and one remote-load (as the return value of the :remote side.
@cjmurphy You need a remote on it
thatâs what I was saying in prior comment
(remote [env] (df/remote-load env))
inside your defmutation
load-action affects state, but Om wonât even try to go remote without a remote indicator, which is generated by the remote-load function.
The doc string for load-action is pretty specific about that. Do you not have docstring help?
otherwise it looks good
(defmutation load-existing-rules [{:keys [sub-query-comp source-bank target-ledger]}]
(remote [env] (df/remote-load env))
(action [{:keys [state]}]
(df/load-action state :my-existing-rules sub-query-comp
{:target help/rules-list-items-whereabouts
:refresh [[:banking-form/by-id p/BANKING_FORM]]
:params {:source-bank source-bank :target-ledger target-ledger}})))
Mutations in Om can have multiple parts. The action is always local. It cannot trigger anything to do with networking. The other sections are names of remotes (the default name of a remote is remote). Each one indicates what should be done on that specific remote for this action. The special value true means âthe same abstract thing that happened on the client`...but for load actions, you donât want to run load-existing-rules on the server, you want to send the query. The load-action has stored the query in a queue. The remote-load returns an AST that will trigger the queue processing on that remote.
technically, for loads, triggering remote-load from any remote causes queue processing, and the queue entries themselves use a :remote option to indicate which remote they query
@tony.kay The docstring even has example, so you are correct it should be pretty obvious. At the moment I just read docstrings by looking at the source (cntl+B on the function), where there is no colour coding or anything. The example is in the old pre-defmutation style and is at the top of some lines of comments. And a colon sometimes looks like a semi-colon to me. So to my eyes :remote (df/remote-load env) was just part of the comments and got missed. If it had been new style, starting with a paren, or the remote had been after the action, so with lots of whitespace around it - in either of those case it would have been hard to miss. Syntax colouring is probably my answer - I'll see about using the proper IntelliJ way of looking at docstrings.
Yeah, updating the docstrings would be good đ
It is cnrl+Q on my Linux machine for looking at docstrings, but it doesn't have a different colour for code. Really I should have understood/researched your comment: "`data-fetch` has a function (`remote-load`) for generating the right-looking thing...". All my eyes needed was to see (remote [env] (df/remote-load env)), which was nowhere to be found. I did try (remote [_] true), but of course that didn't help.
Yeah, this was one of the important realizations in Untangled: how to turn mutations into loads so that we donât need a parser to be involved in remote queries. It turns out that you need a mutation to modify state so that your parser can trigger a load anyway in Om Next (otherwise youâd be loading at every parseâŚthe state has to change so your parser can be intelligent about loading). So, the trick was to realize that any mutation with a remote AST will cause Om Next to try to send that over the wire, so we hack into that to transform the mutation into a query. The only downside is that composing loads into mutations then looks a little wierd.
I guess there could be some macro similar to defmutation that always indicates youâre wanting to process the load queue and does it for you.
I'm going to be calling om/tranact! from within a defmutation... that's what about to try
no, that is not advised
mutations are the bit twiddling. Donât embed a higher-level abstraction in them
modify state, indicate what is remote. Thatâs all.
So I'll compose df/load-action into the threading macro on the state.
yep
that is the intention
So the other one that wasn't remote before will now become remote too.
?
Youâre writing one mutation, right?
One that calls another.
I donât see one that calls another
When a drop down is loaded with all its values - thats the first mutation. It works out the value which will be the chosen value of the drop down. Now data needs to be loaded from remote for this chosen value.
ah, so the completion of one load needs to trigger another?
No - the first is not a load
so, youâre trying to write a mutation that 1. sets the dropdown display, and 2. triggers a load
(as it happens in my case)
Yes
ok. (swap! state (fn [s] (-> s (do-dropdown-update) (load-action :kw ...))))
within action
and remote-load in remote
Yes good. So the first mutation now becomes a remote when it wasn't before.
what first mutation? You mean do-dropdown-update?
Yes - put the list of values in the actual drop down control.
that isnât a mutation, it is a function
that is part of the implementation of the action (local only) of a mutation
It is a mutation because it is changing state.
the remote-load sends an AST that just processes the network queue
it knows nothing of what you did to state
if you say âremote trueâ, then youâre asking the top-level transaction to go over the wireâŚstill doesnât know the guts of action
by using remote-load, youâre replacing the top-level transaction with a special AST that processes the network queue
I can just try it both ways, with and without making the first mutation remote. So it sounds right from what you are saying to make the first one be remote true.
(Iâm using the term mutation here to mean the top-level transaction)
I donât see a first one
I've got two defmutations.
so youâre just confusing me. I see defns
Both local.
not in the code you posted
but I assume you just elided that. So, remote true means you want to send the top-level tx, as DATA, across the wire to the server, as is from the UI
if that is what you want, then yes đ
Yeah the code I posted is the second defmutation, that I'm calling from another one.
If youâre doing a load-action, you do not want to send the top level UI txâŚyou want to process the queries of load-actions.
but you donât call one defmutation from another