Hi everyone, i’m trying to play with matrix with nested objects in make, and I have few questions:
1. in this example
(def example (make :test {:a (cI 1)
:b (cF (str "a value is:" (mget me :a)))
:c {:d 3
:e (cF (mget (mget (mget me :test) :c) :d))}}))
when i’m trying to do:
(mget example :test) it works,
but (mget (mget example :test) :c) won’t work, and i need to use get , make won’t create widgets for the nested object?
2. in this example
(make :todoApp
:name :todoApp
:a 1
:c {:d (cI 3)
:dom (cF (with-par me (div (mget (mget me :c) :d))))}
:dom (cF (with-par me (button
{:placeholder "placeholder"
:class "edit"
:onclick #(print me)}
"Log it"))))
when i click on the button i’m getting the error:
Uncaught RangeError: Maximum call stack size exceeded
Thanks!I looked first at the stack overflow. Let me play with your example a bit. btw, yesterday @lidorcg had a similar question, and I with his kind permission I will turn our exchange into a new bit of doc. Now let me try your example. brb.
Ah, OK, the correct make syntax would be sth like
(make :test
:a (cI 1)
:b ....etc...)
You might be thinking of the`web/mx` syntax for HTML tags:
(div {}
{:name :todoapp
:a 1}
(div {}
{:d (cI 3)}
(button
{:placeholder "placeholder"
:class "edit"
:onclick #(prx :button-parent-is me)})))
So you got the button to appear? Wow, surprised. What does your whole app look like?What the original code did was make a model instance with one property, :test, and the value: {:a (cI 1) :stuck_out_tongue:... etc
Disclaimer: me and @aviv846 are working together on the same project (so our questions might not represent statistical significance 😅 )
Doh! My first guess was that @aviv846 had worked off yesterday's thread! Thx for clarifying. 🙂
@hiskennyness thanks, the complete example for the first question is:
(defn matrix-build! []
(reset! matrix
(make :todoApp
:c {:d (cI "Aviv")}
:dom (cF
(with-par me
(div
(str "hey " (mget (mget (mget me :parent) :c) :d))))))))
i’m trying to create a nested reactive object and access it using mget, but the nested mget won’t work for :d, my guess would be that make refer to first level.
(:value @caja:d (mget (mget me :parent) :c))) (this worked for me)Well, we have quite a few things to sort out. You should not have to code with-par, or :dom or :c {:d (cI...)}.
That said, your code creates a model of type :todoApp with one of the two properties being :c, which gets the value {:d (cI "Aviv")}. Cells does not look inside a property value for cells such as (cI "Aviv"), and the map {:d (cI "Aviv")} as you surmised is not a model` to which you can apply mget.
Are you planning on changing :d to see the div change?
Ah, you mentioned "nested object". Are you exploring what it is like to code MX with a searchable model space?
I am starting to see why we have :c {:d (cI 3)}.
As we discussed yesterday, MX includes the family API that supports a nice, well-tested way of assembling individual models into a "matrix" of inter-reacting models.
If you do not want to use the family API, that is fine, but we should talk about various implementation issues.
In any case, your example would be better as sth like:
(make :todoApp
:name :todoApp
:a 1
:c (make :d (cI 3)
:dom (cF ...not sure...))
:dom (cF (with-par me (button
{:placeholder "placeholder"
:class "edit"
:onclick #(print me)}
"Log it"))))
If you want to explain your test case, I can code it up for you, avoiding the family API.btw, are you using:
[com.tiltontec/matrix "5.0.1-SNAPSHOT"]
[com.tiltontec/web-mx "2.0.2-SNAPSHOT"]
[com.tiltontec/mxxhr "2.0.0-SNAPSHOT"]
I ask because currently the test app looks for :mx-dom, not :dom.We changed that on our workspace 😄
You know what this does to your warranty, right? 🤣 But soldier on, have fun, I will support as best I can. 🚀
🤣 I got confident playing around with the shadow build
@hiskennyness
1. Yes i was going to change the :d you mentioned before
2. adding another make to make it work was solving it, but the issue with another make is that it creates another hierarchy, we are looking for some way to keep the me in the same level, so that accessing me from the :d will point to the todoApp
Specifically:
make won't create widgets for the nested object?
No, you would have to call make on
{:d (cI 3)
:dom (cF (with-par me (div (mget (mget me :c) :d))))}
Again, if you are looking at w/mx examples, they rely on w/mx to hide a lot. It makes for nice clean web programming, but to bypass that you have to work out everything that is hidden and recreate.so the whole “nested object” will be belong to the todoApp, no matter how nested :c
If you do :c (make :d (cI 3)) then that nested MX will be in its own world.
If you wrap :c in a formula, the nested object can see the :todoapp (untested):
(make :todoApp
:name :todoApp
:a 1
:c (cF (let [todo-app me]
(make
:d (cI 3)
:dom (cF (with-par me (div (mget (mget todo-app :c) :d))))
:dom (cF (with-par me (button
{:placeholder "placeholder"
:class "edit"
:onclick #(print me)}
"Log it"))))
...but you could also:
(make :todoApp
:name :todoApp
:a 1
:c (cF (make
:d (cI 3)
:dom (cF (with-par me (div (mget me :d))))}
:dom (cF (with-par me (button
{:placeholder "placeholder"
:class "edit"
:onclick #(print me)}
"Log it"))))So the way to create nested reactive objects is through cF + make?
You do not need the cF, but if you want the created matrix to have a reference to the outer matrix, cF provides that as me.
Without that, the outer matrix of course sees its own property :c, and the matrix it contains, so it can interact with that.
Is there any way to have a notion of dependency nested deep inside a matrix (like our example) or is the granularity of dependencies coupled with the notion of this (i.e me)
The first example @aviv846 shared is really good:
We're trying to have [:test :b] depend on [:test :a], and that me will still point to the root, in this case example.
Is there a way to have our cake and eat it?
I'll note the inconsistency with that example:
:b should not address directly to :a as in the example (mget me :a) but rather (mget-in me [:test :a])
P.S
Let's pretend mget-in exists
(def example (make :test {:a (cI 1)
:b (cF (str "a value is:" (mget me :a)))
:c {:d 3
:e (cF (mget (mget (mget me :test) :c) :d))}}))
This ^^ was the first example, IIUC.
There is one model, which gets bound to the var example.
Where is there a second model? Should we add a (make...) somewhere?No, no second model
Just deeply nested one model
Where one leaf depends on another
OK, no, a model has properties which we can make reactive. The values of those properties are out of reactive scope, even if a value is {:a (cI...)} or {:b (cF...)}. To get what you are after, create a model as a property of the original model, or even a separate model.
But you have me thinking. I have played with standalone cells, and you can see them in the MX test suite. Let me refresh my memory. brb
Alright, so models dictate the reactive scope + the binding of me
Is my understanding correct?
Actually my first impression was that your atomic building blocks are standalone cells style javelin
There are examples of standalone cell in here: https://github.com/kennytilton/matrix/blob/main/cljc/matrix/test/tiltontec/cell/core_test.cljc I never use them. 🙂
So model only wraps first level properties in cells am I correct?
And binds me
Javelin and MX are alike in spirit, esp. transparency, which is why I am a big fan of Javelin, but not much more.
My first guess: Matrix objects are cyclic, so we need a utility to print, maybe sth like:
(defn mx-print [mx]
(binding [*print-level* 3]
(print x)))
I have just been working on resurrecting an existing MX print mexhanism, let me see where that stands and if it is ready to push.
In the meantime, try the above.
Overall, we should also review how what you are doing might be done more easily in w/mx. 🤔We have http://tiltontec.ma/prx, which calls the same name internally defined as:
(defn prx [tag & bits]
(when tag
(binding [*print-level* 3]
(apply prn tag bits))))
The idea is that I can just stick in a nil as the first argument to silence a debug print.