Fork me on GitHub
#hoplon
<
2018-01-30
>
thedavidmeister01:01:19

@hiskennyness mmm how do we write that though...

flyboarder01:01:09

@thedavidmeister I use a dynamic state variable and rebind when I want to create a local state scope

thedavidmeister01:01:56

what does that look like?

flyboarder01:01:16

(ns degree9.state)

(def ^:dynamic *data* (javelin.core/cell nil))

flyboarder01:01:27

(ns other.ns
   (:require [degree9.state :as state]))

(defn mkstate [input]
   (binding [state/*state* (data.ns/get-data)]
     (let [...]
         ;;everything in here that has a cell which referenced state/*state* we get scoped data, this lets us create consistent state cells
      )))

thedavidmeister01:01:06

why not just make a fn that returns a new data cell?

thedavidmeister01:01:17

also i meant "how do we write that in a convincing way on the homepage" 😛

flyboarder01:01:23

thats what get-data does

thedavidmeister01:01:24

but this is interesting

thedavidmeister01:01:42

i don't really use binding so i'm wondering what the advantage is over just passing cells into fns as args

flyboarder01:01:05

runtime binding

flyboarder01:01:06

some state has to be bound at runtime, also you get state-isolation between elements in -tpl

flyboarder01:01:49

but hoplon also has it’s own runtime binding in the hoplon.binding ns provided by @micha

thedavidmeister01:01:00

i don't think i've run into issues with state not being isolated

flyboarder01:01:03

you also get to modify “nested” state without directly passing it around

thedavidmeister01:01:15

i think i need an example of the problem before i understand the solution

flyboarder01:01:10

in that example config is binding+`let`

flyboarder01:01:56

the best example on that page is probably how the router works, there is a router which can be dynamically bound so all the components use the router but dont actually care what it is implemented by, the implementation is bound at runtime

thedavidmeister01:01:47

right so you're setting *admin-menu* to a cell somewhere near the top of your app's tree structure

thedavidmeister01:01:55

then all the children can use it if they want

flyboarder01:01:10

right without passing the variable around

thedavidmeister01:01:17

hah, not sure if i love it or hate it 😛

flyboarder01:01:42

there is a common api which all the components agree on, ie the core “state”

thedavidmeister01:01:06

so it is very convenient from an app perspective

thedavidmeister01:01:12

but would make things less portable from a lib perspective

flyboarder01:01:31

sorta, the idea is you build App domains around it

thedavidmeister01:01:51

well if you went and stuck

thedavidmeister01:01:54

(defelem card-button [attr kids]
  (let [id (:id attr *admin-menu*)]
    (div :id "card-admin-button" :class [:mdl-button--admin_button-container]
      (btn/button :id id :fab true :class [:mdl-color--primary]
        (i :class [:material-icons :mdl-color-text--white] "more_vert"))
      (menu/menu :top-right true :data-mdl-for id
        (menu/menu-item "Admin Item")))))

flyboarder01:01:56

so libraries are wrapped within a ns, then you implement a namespace per provider

thedavidmeister01:01:05

i have to manage a *admin-menu*

thedavidmeister01:01:13

multiply that by a few dozen libs and it would be annoying

flyboarder01:01:34

the blog was a good example of how quickly the bindings can grow and be annoying but the cool thing is that you get the ability to swap state providers at a single site instead of throught an application simply by including the ns and replacing the binding

thedavidmeister01:01:55

yes, well my approach is just passing everything through

thedavidmeister01:01:26

because i got burned by my app having lots of "reaching out" to state inside hoplon elements

thedavidmeister01:01:33

so i did a big refactor

thedavidmeister01:01:45

but i can see a few places where it would be convenient to use your binding approach

flyboarder01:01:47

yeah thats what I usually do too, this was mostly an experiment, I dont know the runtime costs of doing all this rebinding

thedavidmeister01:01:57

well for me it was about testability

thedavidmeister01:01:07

but the binding approach can satisfy that i think

thedavidmeister01:01:00

for example, i have a project-id that lots of things use, and it comes from the route

thedavidmeister01:01:14

that could be a binding

thedavidmeister01:01:26

it makes sense to me when you have app-specific components that are deeply nested and rely on info derived directly from things that are already inherently global, like the route

flyboarder01:01:20

@thedavidmeister we could make running the tests as simple as binding the provider

flyboarder01:01:45

(binding [hoplon.test/*provider* hoplon.jquery]
   (require [hoplon.test/*provider*]))

flyboarder01:01:02

and calling all the tests with a function we can wrap

thedavidmeister01:01:42

yeah, or is there like a "before hook" that we can call once?

thedavidmeister01:01:47

for the whole suite

flyboarder01:01:30

yeah thats kinda what is possible with the elem! pr

thedavidmeister01:01:50

cool, will it work in cljs though?

thedavidmeister01:01:54

i don't think require is a fn in cljs

flyboarder01:01:56

since elem! implements invoke you can override it

flyboarder01:01:00

but I dont think we can do much at compile time without either a macro or compiler var

thedavidmeister01:01:37

i do wonder if we'll need providers forever...

thedavidmeister01:01:54

seems like a lot of what hoplon does should be supported by browsers in a reasonably standard way

thedavidmeister02:01:42

or maybe we just namespace the "extra features" from the provider at the attr level

thedavidmeister02:01:21

would :jq/click be the worst?

thedavidmeister02:01:38

i'm not 100% sold on the approach of pulling in a namespace and having that implicitly rewire all the core internals

thedavidmeister02:01:57

again, it makes writing and sharing libs harder

flyboarder02:01:20

I dont think we need the to do anything implicitly

thedavidmeister02:01:35

we already do though

thedavidmeister02:01:54

(:require hoplon.jquery) implements a whole bunch of stuff

flyboarder02:01:00

well only the “extra” features

thedavidmeister02:01:02

as soon as it is included it changes how core works

thedavidmeister02:01:21

yeah, what i mean is that if i write an app and use hoplon.jquery all the way through

flyboarder02:01:31

that could easily be fixed by prefixing the current provider attributes

thedavidmeister02:01:35

then i want to split out some cool functionality into a lib, then how do i do that easily?

thedavidmeister02:01:01

i wouldn't be confident that it works with any old provider, because i can't test that

thedavidmeister02:01:15

and i wouldn't want to include hoplon.jquery because then i'd blow away whatever provider you were using

flyboarder02:01:39

yeah vendor prefixes are probably a standard we should implement since the support has been around since v7.0

thedavidmeister02:01:00

i mean look at us scratching our head over just testing core's own functionality

thedavidmeister02:01:18

way harder to take that into the wild for random libs floating around

thedavidmeister02:01:23

and things like adding/removing attributes, adding event handlers, basic DOM manipulation, triggering events...

thedavidmeister02:01:29

all that shouldn't need a provider

thedavidmeister02:01:50

if you want a :toggle go ahead and use jquery as :jq/toggle

thedavidmeister02:01:07

if you want to add a class to an element, well that should just be a simple fn call in core

flyboarder02:01:35

@thedavidmeister yeah the basics are provided by hoplon core already, but most events arnt provided

thedavidmeister02:01:54

they are provided but then they get blown away when you pull a provider in

thedavidmeister02:01:17

which you inevitably have to do because events

thedavidmeister02:01:51

@flyboarder i'll put a tx up, we can come back to this at some point 🙂

thedavidmeister02:01:47

@hiskennyness mind if i paste what you said into the github thread?

flyboarder02:01:43

i mean go for it

thedavidmeister03:01:00

changing the way providers work is not a BC change, so i'm thinking a candidate for an 8.0 release...

kennytilton08:01:05

@thedavidmeister Search me. 🙂 How many folks have even coded up an FSM in anger? I think these spreadsheet and FSM analogies work only after a series of concrete examples have manifested the elegant effectiveness of dataflow. Then we go big with the parallels to spreadsheets and FSMs. I am trying to catch my tendency to explain dataflow to myself, who already has experienced its power and is trying to understand it. Those explanations are rationally sound but viscerally unbound.

kennytilton08:01:02

@thedavidmeister Yes, posting to the GitHub thread will be fine.

thedavidmeister09:01:38

@hiskennyness the localness of the scope and independence of components is good, also "programming with values" rather than "programming with time" is good

alandipert16:01:02

"programming with time" i like it, as the opposite of programming with values