I've been trying to wrap my head around queries. Let's say I want a Root
component with multiple table-views on it.
The official tutorial suggests - one approach would be to have a table-view component with no query. And then you can pass whatever data it needs to use via props, and that works just fine.
But that's very simple case. In non-trivial app, probably you'd like to have TableView
with a query, because down the UI tree you may have some complex UI structure of components - table-header, footer, rows, cells, etc.
Now this tutorial suggests approach with a query:
And yet this is still somewhat simplified example. So let's say if I have:
(defmethod read :numbers/odd [_ _ _]
{:value (filter odd? (range 50))})
(defmethod read :numbers/even [_ _ _]
{:value (filter even? (range 50))})
in real app of course the data would come from the back-end and Om would stick it into the state atom (as usual)
now I need to have a TableView
component with a query that can render either of these (or any sequence in this case). So you see I have to somehow tell the TableView
component to use data that sits somewhere else in the state atom. And the query for the TableView
should be "dynamic", so I can possibly use multiple TableViews
rendering different data.
Let's say we'd have something like this for the Root:
(defui Root
(query [_] [{:table/odd ,,,} {:table/even ,,,}])
(render
[this]
(let [{:keys [table/odd table/even]}]
(html [:div
[:div.odds (ui-table-view odd)]
[:div.evens (ui-table-view even)]]))))
for brewity I omitted Om.Next interfaces
Now I have a few questions:
- How should the query for
Root
look like? - Should I have parametrized query in
TableView
(where I would maybe indicate a key for the data in the state atom)? Or how else I can tell oneTableView
to use:numbers/odd
and the other to use:numbers/even
? - If I use parametrized query in
TableView
then how do I pass params fromRoot
toTableView
? - Maybe I should pass data or link to TableView's data via computed props?
- How would I use then
om/get-query
(if sub-query is parametrized)? - How would read methods look like? Do I need to "move things around" in the atom at
read
? Doesn't sound like a good idea
Can someone please show me an example of some sort. Thanks a lot!.
So this is what I come up with:
For each table store a data key associated with it and then in the read phase grab that data and assoc to the map representing the table:
So if we have couple of tables (with odd and even numbers):
This what would read method look like:
This approach has one big drawback - it will try to parse ALL the data for all the tables, so I need to find a way to improve it - I want to be able to selectively specify tables to grab data for.
snippet for the entire solution is here:
upd: I made an improved version (added a file to the gist). In that example now you can specify the data keys, so it would load only specified pieces
upd2: Apparently this approach somehow breakes mutations. The idea is right though - need to make use of Om.Next's normalization mechanics. I'll try to update the gist sometime later.