Fork me on GitHub

hi @tony.kay, I was browsing the dev guide from master [awkay/untangled] and noticed something odd in /guide.html#!/untangled_devguide.L_Internationalization:

Unknown app state mutation. Have you required the file with your mutations?:
when trying to click on the buttons 👇


um…try develop


I thought I fixed that


the mutation name changed namespaces


I went ahead and merged develop. technically I use master for releases, but I haven’t done one yet from this repo. develop is what I’m working on


it is fixed in both now


thanks for looking 🙂


ok, thanks! will test from develop then. I've been prototyping with Om.Next and Untagled the past few weeks - I guess I had to struggle myself a bit with recursive parsing first, but I will probably just stick with Untangled 🙂 I better appreaciate some of the design decisions now


thanks for all the work. specially upgrading the cljs dependencies now


Yeah, it is good to understand the base library. It is one of the struggles of adoption. I’m concerned that ppl will think Om Next too hard, then not even look at Untangled.


but the combo of Om Next’s concepts with some good concrete decisions is pretty nice


Any cheerleading you can do on #om is nice 😉 I try not to do too much of that.


I really wanted to use the idea of routing to remote on the parser, but still was not very happy with overall complexity - even trying to leverage specter, etc


Yeah, that was my problem with the parser concept as well. In theory it is great. In practice, not as much.


right now, I ended up using a webworker as a remote with datascript, and the normalized db state in the main thread ui.. but still not sure about the architecture, I have a deadline in the next couple months, will let you know about progress


The load stuff is pretty much what you end up writing in your own parser…do a mutation to set a marker so that your parser knows to ask for it…but lots of indirect paths to trace when it goes wrong.


why datascript? Needing to do complex queries on the client?


yes, because my backend is python, going to end up doing most of logic in the webworker, backend is mainly persistence


so you’re kinda kicking all the data to the client, and eliminating most remoting?


yes.. because there are some requirements for the web app to work offline, so most things will work with local storage, then sync to server


the actual http remote is very simple, just some persistence of facts/tuples (and hability to get deltas)


so your untangled networking really just talks to your local datascript db?


yes, I was really happy to see your example with rest network 🙂 it came really handy for me as an example


cool! I was just about to suggest that 🙂


it’s actually even easier than that. See the MockNetwork I use in some parts of the devguide




is a decent example , I think


then again, that’s probably all you’re doing


hm, ok - didn't see it before.


It’s just what I say in REST, but without any networking


I do that when I want to demo full-stack without writing a server


also nice for playing with a component or app that normally talks to a remote in a devcard, without needing the real server.


with a full-blown parser


I still need to update the docs, but the getting started guide shows a new untangled parser for the server that has 3 macros for writing server-side stuff. Makes client/server things like defmutation look identical


Not in the devguide yet


anyway…feel free to ask questions. I’m hacking like mad on various things trying to get to a nice 1.0 release


(just noticed that the stats are i’ve added 6k lines in the past week…mostly bootstrap and docs)


I’m still looking on how to get access to app state from the UntangledNetwork/send, still no success. To recap: looking at , I assume that (assoc this :complete-app app) in start means I can then use complete-app in send to get reconciler first, then state. However, that does not work, complete-app is nil in send. And while my Clojure- and defrecord-fu is rather weak, that makes sense for me, becase initialize calls start just for the side effect and throws the return value away.


Am I missing something here? Or is there a bug in initialize and it should collect stuff returned from start(s)? @tony.kay, please?


@bbktsk What do you get in send ?


@claudiu (prn complete-app) at the beginning of send prints just nil.


yep, but if there is a reconciler in the params you can get the state from it


send‘s signature is (send [this edn ok-fn error-fn] - this is UntangledNetwork, edn is the query, ok-fn and error-fn are callbacks, no reconciler there.


@bbktsk you do not have access to the app State in send. Technically at this level of om next, you don't even know the database format. What you have is a call back that is essentially merge. It takes two arguments. The tree of data, and query to help merge that data and normalize it.


@tony.kay My problem is this: I need to load some additional data to an entity that is already in the local database. I create a remote mutation, call df/load-action with ident and class of that entity, in send request the data from a legacy REST api, receive the result. So far, so good. But, to correctly parse the result and pass it to the callback to have it merged, I need other data from that entity, not just the ident. So I was planning to just look into local state and grab the entire entity using its ident. But now I am a little bit lost… any advice, please?


“to parse the result I need other data”


and have you read the section “Data Merge” in devguide section H_Server_Interactions


Sub-items in the response do not have correct keys, or, have “keys” that need to be fixed using data already in the database.


keys? Those should just be renamed with set/rename-keys. They are stable things, not data.


perhaps a short example?


Go ahead with the example, but I can say this: since you’re using Untangled, there is no need to be an Om purist here. If you’ve saved your app off in an atom, you can pull the app state from the app via that global.


Each Object has several SubObjects with Id, Name and ExtraData. I have defui-ed components for both Object and SubObject, use Id for the SubObject’s ident . Initial query that loads Objects also loads all SubObjects, however, it loads only Id and Name for these. The REST API for ExtraData is at Object level, i.e. I call GET "/api/Object/123/extra-data" and receive ExtraData for all SubObjects, but the response is a vector of [Name ExtraData] pairs. I.e. instead of using Id to identify ExtraData, the server use Name. Using Name as ident might probably work, but it feels quite ugly for a number of reasons (`Name` are not unique among all SubObjects so I’d have to unique-fy them, it would complicate other things and it just feels wrong 😎 )


@tony.kay I may end-up doing that, it’s just that by looking at the legacy api example, I thought that’s the idea behind current-app in UntangledNetwork/start. If not, what’s the point of that?


To be honest, I do not remember why the complete app is passed to networking. It could be we were thinking someone writing their own networking might need to access the app, but the default networking does not. I think that might be the case…might have been added to support websockets. Om defines the interaction with send


So, you say “name”…what about the object type? How are you going to write queries in the UI for these things if you don’t know what keys they have in advance?


or are you treating them as blobs of data?


Oh…duh. I just realized that you were pointing out a bug earlier: that current-app is there, but it doens’t work. Added issue:


I’m not sure I follow here. I know that Object has SubObjects, each SubObject had Id (number), Name (string) and ExtraData (string or nil when not loaded) . (actually, ExtraData is a couple of other things, but that’s not the point here)


you are writing your own networking 😊


ExtraData being other things is my point 😉


you cannot merge it successfully if the query doesn’t say what could be there


Trying to write 😎


I mean, in my case it is not single ExtraData but Value and Mode, both strings. The point is, I know what’s there, even the key is there, it is just set to nil until the follow-up load.


Can you paste an example REST response?


Example of follow-up request for one Object, these are some attributes belonging to it: {"ProtectionEnabled" ["true" "rw"], "Status" ["ok" "ro"]} So, it’s a map keyed by the name (that I have in local db already, but not as an ident), each value is a vector of new values. So apart from some massaging, I need to translate names (keys of this map) to ids …


So, a couple of possible approaches. If the data isn’t paricularly “deep”, then you could skip normalizing it and just treat it as a “bag of data” under a single prop in the database. E.g. the query could join an ident on a prop [ { ident [:object] } ] and merge the tree { ident {:object anything} } where anything just won’t be further normalized.


the other option I was thinking of had to do with a union query…which is what they are for: when a response can have any number of different types at a location.


then normalization can put the different kinds of things in different tables


I am not sure I understand here. Or maybe I’m just bad at explaining what the problem is 8-) I will think about it for some time and if I do not figure it out, I will create a complete working faked example of what the problem is. But thanks anyway for your time!


@tony.kay Ok, so here’s the example of my problem, as minimal as I could make it:


(hmm… Slack asked me to import it. That would probably make big wall of text here, right? Is it a good etiquette to do that?)


The core is in the FakeRestRemote record. Note that as it is, it works flawlessly because the faked responses from the rest api are “good”. The equivalent of the response I am receiving in the real world is commented out.


@tony.kay just something I noticed: when testing with :networking (, it seems that only the first remote send gets executed (i.e. just the first log msg appears). For custom remotes, I had to define (serialize-requests? [this] false) (in untangled/master) as work around