matrix

Aviv 2023-05-15T14:48:02.431049Z

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!

👀 1
kennytilton 2023-05-15T15:05:31.912449Z

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.

👍 2
🙏 1
kennytilton 2023-05-15T15:22:57.535799Z

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?

kennytilton 2023-05-15T15:25:12.678639Z

What the original code did was make a model instance with one property, :test, and the value: {:a (cI 1) :stuck_out_tongue:... etc

2023-05-15T15:34:09.450799Z

Disclaimer: me and @aviv846 are working together on the same project (so our questions might not represent statistical significance 😅 )

kennytilton 2023-05-15T15:40:44.272749Z

Doh! My first guess was that @aviv846 had worked off yesterday's thread! Thx for clarifying. 🙂

😬 1
Aviv 2023-05-15T15:46:43.193859Z

@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)

kennytilton 2023-05-15T15:57:41.003369Z

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?

kennytilton 2023-05-15T15:59:51.525079Z

Ah, you mentioned "nested object". Are you exploring what it is like to code MX with a searchable model space?

kennytilton 2023-05-15T16:11:00.495759Z

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.

kennytilton 2023-05-15T16:16:38.436839Z

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.

2023-05-15T16:19:46.353479Z

We changed that on our workspace 😄

👍 1
kennytilton 2023-05-15T16:22:45.279229Z

You know what this does to your warranty, right? 🤣 But soldier on, have fun, I will support as best I can. 🚀

2023-05-15T16:25:18.205959Z

🤣 I got confident playing around with the shadow build

Aviv 2023-05-15T16:25:59.396169Z

@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

kennytilton 2023-05-15T16:27:28.849539Z

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.

Aviv 2023-05-15T16:27:39.371869Z

so the whole “nested object” will be belong to the todoApp, no matter how nested :c

kennytilton 2023-05-15T16:31:38.183219Z

If you do :c (make :d (cI 3)) then that nested MX will be in its own world.

kennytilton 2023-05-15T16:40:07.169899Z

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"))))

2023-05-15T16:50:51.057169Z

So the way to create nested reactive objects is through cF + make?

kennytilton 2023-05-15T17:01:03.781939Z

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.

2023-05-15T17:10:11.397929Z

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?

👀 1
2023-05-15T17:14:46.996899Z

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

kennytilton 2023-05-15T17:16:24.573169Z

(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?

2023-05-15T17:16:53.725269Z

No, no second model

2023-05-15T17:17:05.137029Z

Just deeply nested one model

2023-05-15T17:17:27.426459Z

Where one leaf depends on another

kennytilton 2023-05-15T17:21:24.146169Z

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.

kennytilton 2023-05-15T17:23:30.624759Z

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

2023-05-15T17:23:56.139999Z

Alright, so models dictate the reactive scope + the binding of me Is my understanding correct?

2023-05-15T17:25:25.960939Z

Actually my first impression was that your atomic building blocks are standalone cells style javelin

kennytilton 2023-05-15T17:32:17.319839Z

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. 🙂

2023-05-15T17:39:45.228119Z

So model only wraps first level properties in cells am I correct?

✔️ 1
2023-05-15T17:40:03.722779Z

And binds me

✔️ 1
kennytilton 2023-05-15T18:02:16.135659Z

Javelin and MX are alike in spirit, esp. transparency, which is why I am a big fan of Javelin, but not much more.

kennytilton 2023-05-15T14:55:22.959939Z

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. 🤔

kennytilton 2023-05-15T15:00:23.796529Z

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.