Clojurians
#hoplon
<
2016-07-12
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

jumblerg06:07:15

@adamw: i’ve added your object tag, a way to handle bulleted lists via the markdown on the latest commit.

jumblerg06:07:32

the markdown support is very much incomplete, a minimal implementation i tossed in quick to support of a project i needed to get out the door, but you can extend it for your purposes.

adamw06:07:23

Thank you!

alandipert11:07:58

@flyboarder: it's possible but i think you need to set up the linkage in a constructor

alandipert11:07:49

or, make a function that takes an element, a cell, and an attribute, and syncs the cell's value to the attribute of the element

alandipert11:07:06

creates a cell= that is

alandipert11:07:35

very promising i think, because it gives attributes an idea of construction

alandipert11:07:34

altho i suppose even in that case, the attr code wolud only know about the elem it was attached to when do! is called the first time

adamw12:07:54

@jumblerg: hah, so hoplon/core has moved from object -> html-object

jumblerg12:07:02

ah, master has anyway, yeah

jumblerg12:07:12

the html- prefixes might be less critical now with the new ns+ macro

jumblerg12:07:08

but object is a type in cljs

adamw12:07:05

ah of course, ok that explains it

adamw12:07:21

@jumblerg: so we found a weird thing today

adamw12:07:33

to do with making 😛 (& :p) tags based on cells

adamw12:07:56

(elem :b (cell= (if <cell> 1 0)) "Element Contents"

adamw12:07:06

basically throws an error saying

adamw12:07:14

attrs.cljs:15 Uncaught Error: No protocol method IAttr.-dom-attribute defined for type javelin.core/Cell: [object Object]

jumblerg12:07:03

i have a hunch

jumblerg12:07:17

i'll look into it, thanks for the demo.

adamw12:07:36

cool thank you!

thedavidmeister13:07:55

is there a way to destructure cells?

alandipert13:07:22

there is cell-let which makes cells on the left side

alandipert13:07:58

e.g. (cell-let [[x y] some-cell] ... x and y are cells here...)

alandipert13:07:15

comes in handy inside -tpl bodies

thedavidmeister13:07:06

does that work for things that aren’t cells?

thedavidmeister13:07:46

actually, i don’t really understand

thedavidmeister13:07:33

(cell-let [foo (first my-cell)] …)

thedavidmeister13:07:37

would that be the same as

thedavidmeister13:07:59

(let [foo (cell= (first my-cell))] ..)

alandipert13:07:07

the idiotmatic way would be (cell-let [[foo] my-cell] ...)

levitanong13:07:27

@thedavidmeister: be careful when using cell-let though. If you changed your mind about a formula cell, and decided to make it an input cell, cell-let will still turn it into a formula cell, and you’ll get “cannot swap!/reset! a formula cell” errors.

thedavidmeister13:07:25

i didn’t know about that

micha13:07:41

(cell-let [[x & xs] (cell= [1 2 3])]
  (cell= (prn [x xs])))

micha13:07:45

is the same as

micha13:07:48

(let [things (cell= [1 2 3])
      x (cell= (first things))
      xs (cell= (rest things))]
  (cell= (prn [x xs])))

flyboarder17:07:00

@alandipert: thanks for the info, I saw that branch but i’m trying not to go exploring right now, instead I refactored the elements a bit and changed how I was storing the state

jumblerg17:07:03

@flyboarder: i was looking at your route-tpl while taking the train to my office. fwiw, i typically treat the route/hash just another view (and control for modifying) my application state.

jumblerg17:07:52

flow looks something like: user clicks button -> handler updates appstate cell -> route and dom update from appstate via formula cells

jumblerg17:07:57

or user changes route -> handler updates appstate in cell -> dom updates from appstate cell

jumblerg17:07:30

so rather than my route being tied directly to the view, it goes through a cell first

flyboarder17:07:56

@jumblerg: i think that’s pretty much how it works

flyboarder17:07:17

regex-tpl is generally for when the cell value could be any type of user input, so creating conditionals or cases may not be the most convenient method of catching everything; route-tpl would basically wrap this plus include a (route-cell) by making it dynamic you can redefine it be anything

flyboarder17:07:16

so if users wanted to rebind the route cell to a new route cell they could

flyboarder17:07:36

which i think keeps your app flow logic intact

jumblerg17:07:11

is the idea to persist the route in the cell as a string?

flyboarder17:07:18

well i’d like to provide the option for other things like vectors of keys, but generally everything would be converted to a URI path

flyboarder17:07:47

then destructure it back via another formula cell

jumblerg17:07:29

i’m not certain of the best approach, but i think maybe the string parsing could take place on the command side on the way into the cell/model rather than on the query side coming out.

flyboarder17:07:48

i see what you mean, that’s probably the best place for it, I was actually thinking of wrapping cemerick/url and storing a URI in the cell

jumblerg17:07:54

my route string is something derived from my application state, i find i need a layer of indirection there in practice

jumblerg17:07:46

routing is a tricky problem

jumblerg17:07:59

it seems innocuous

jumblerg17:07:18

but i’ve found that dealing with it is one of the biggest challenges of creating spas

flyboarder17:07:30

well i think it just depends on how much you want to include in the routing system and how much stays application logic

jumblerg17:07:56

here’s how i ended up managing it in ui, from the docs, fwiw:

routing. ui treats the hash within the address bar as another part of the view; it both presents a visualization of and provides a control for changing the application's underlying view state. this state must itself be persisted elsewhere, typically within a javelin cell containing the application's model. it's no more appropriate to use the address bar as a data store than it is to use the dom for this purpose.

ui represents routes as values of the form [[:foo :bar] {:baz "barf"}], where the vector in the first position is the path and the map in the second position corresponds the query string. ui reads and writes these values via the :route and :routechanged attributes passed to window when the application is constructed. like any other attribute, :route accepts either a route or, more practically, a formula cell bound to the application model to update the route as the application's state changes. :routechanged accepts a callback that will be invoked with an updated route whenever a users enters a route different for the one being displayed into the address bar. this callback should be used to update the application's view state in the same fashion that it would be updated through any other user-initiated event, such as clicking a button.

jumblerg17:07:20

i’m not 100% certain this approach is the best one either, however.

flyboarder17:07:44

awesome! i was totally looking for something like those!

jumblerg18:07:49

i think there’s a minor issue with the way it handles an empty {} atm, leaves the ? on the string.

jumblerg18:07:34

i’m also not certain there should be a query string there at all, it kinda flat, and i’ve found in practice i want to be able to represent more complex structures

jumblerg18:07:51

the hash is just a dumb string, so we can do whatever we want with it

jumblerg18:07:55

encode anything in there

flyboarder18:07:48

yeah I was actually thinking of making something that pulls in the query string and replaces the path with a md5hash or something so it’s always a path that im dealing with

flyboarder18:07:18

or some other uuid of somekind

flyboarder18:07:42

that way users can share links with cell data encoded

flyboarder18:07:05

my cells destructure the path and get their value from the route

flyboarder18:07:34

then you can have arbitrary state links

jumblerg18:07:36

that’s an interesting idea

jumblerg18:07:52

github does this now

flyboarder18:07:20

yeah it’s basically url minifying tied to (app) cell state

flyboarder18:07:12

like you could even just base64 encode it

flyboarder18:07:56

im not sure, i want it to be a user friendly string size but at the same time hold complex data

jumblerg18:07:58

a sha1 or something similar would guarantee the integrity of the app state

jumblerg18:07:33

but there are two separate ideas in play here: (1) serializing the entire app state to a url and (2) encoding in a hash to guarantee integrity and eliminate redundant but semantically identical url serializations

jumblerg18:07:45

gotta run to the gym, but i’ll be thinking on this while there

flyboarder18:07:14

oh goog.crypt has sha1, enjoy your workout!

jumblerg18:07:39

i might be guilty of thinking a bit too "in the box” in my ui implementation

jumblerg18:07:53

the benefit is that is is more user-friendly

jumblerg18:07:16

users can modify the url manually to navigate to different states

flyboarder18:07:20

usability is key

jumblerg18:07:31

but insofar as cutting and pasting url reference to various app states is concerned, which happens much more frequently in practice, a serialized app state representation seems much more powerful.

flyboarder18:07:55

the problem with allowing users to manually navigate app state is partial app state, what about a form that they can only see page 2 after all of page 1 is complete, so lets say someone partially fills out a form then sends their buddy a link to their current page, buddy over there is going to either lose the app state or have a broken state

jumblerg18:07:06

yeah, it is tough to validate

jumblerg18:07:43

good call re the serialized/hashed routes!

tbrooke20:07:24

@flyboarder: @jumblerg Why just do the routes outside of Hoplon with something like Bidi or Secretary?

jumblerg20:07:26

i’m not familiar with either of those libraries, so ignorance might well be the reason. i wonder how well they would fit in with the rest of the hoplon and javelin machinery.

flyboarder20:07:40

@tbrooke: as you can see from the wiki page doing that requires a whole bunch of boiler code

flyboarder20:07:16

@thedavidmeister: put a bunch of examples on the wiki https://github.com/hoplon/hoplon/wiki/Pages-and-routes

flyboarder20:07:58

https://github.com/hoplon/hoplon/pull/139 has a much simpler option using route-cell

jumblerg20:07:20

@tbrooke: i’m looking at them now, i can’t imagine a scenario where i’d need this sort of machinery on the client, in my spa.

jumblerg20:07:01

there’s a place, perhaps, for this sort of routing on the server if you’re exposing some sort of restful api

jumblerg20:07:23

but even there, castra provides a more general abstraction.

jumblerg20:07:53

most of my url matching is done in cloudfront

flyboarder20:07:10

@jumblerg: im using firebase, all of my urls are glob matched to my spa

jumblerg20:07:42

i’m sure there are cases for it, otherwise they wouldn’t have been written, i just haven’t found a need for this sort of thing in my own applications.

flyboarder20:07:33

i agree i think with javelin there could be a better solution

jumblerg20:07:12

@flyboarder: i guess i could see how it would make sense if you’re passing elements of the route through to a restful api underneath in some fashion.

flyboarder20:07:28

yeah i think it works better for cases where your not using hoplon/javelin or castra 😛

jumblerg20:07:13

my requests now come into cloudfront, if they’re static they go off to the S3 cache, if they’re for my service, they get passed through using representations created by castra. there’s also another heartbeat url. that’s pretty much it for me.

jumblerg20:07:24

url pattern-matching is a lower level thing that castra has reduced to an implementation detail of the http protocol i no longer have to worry about.

jumblerg20:07:19

it actually strikes me as a bit strange that, for almost every other protocol out there, everyone just uses libraries and remains largely ignorant of their implementations. yet for http, everyone seems to be experts in the minutiae .

alandipert20:07:53

maybe it's the shed, easy to have an opinion

alandipert20:07:12

i'm confident there isn't One Way to Route

alandipert20:07:24

i guess that's another way hoplon isn't a framework

flyboarder20:07:36

@alandipert: lol routing in a nut shell, many paths you can take

jumblerg20:07:05

yeah, if you’re a roy fielding fan, great - write a library that does it The One True Way and give me that to use.

jumblerg20:07:53

i’m not disparaging the implementation details, they need to be worked through, i just don’t want to get caught up in them.

alandipert20:07:54

they've oriented their whole thing around routes, kinda like rails

jumblerg20:07:21

(every time i write a new webapp)

alandipert20:07:48

i'm just grateful the path separator for URLs isn't different on windows

jumblerg20:07:23

yeah, good thing all the “\”s go the same way on the filesystem too.

jumblerg20:07:03

although i hear rumors they’ve finally decided to go posix

flyboarder20:07:20

that would be awesome

flyboarder20:07:39

I can deal with a leading drive character thats just a folder really

jumblerg20:07:45

not using windows is awesome

jumblerg20:07:59

but people around me do and they’re all ranting about this

flyboarder20:07:14

I would also like to point out that when using the query string for cell data, this should not be a global state cell with everything in it, just things that should recover from link sharing

alandipert20:07:42

i don't always use windows, but when i do, it's 3.1 to play minesweeper https://archive.org/details/win3_stock

tbrooke20:07:53

@flyboarder: Exactly what I was thinking for use with a restful API

flyboarder20:07:24

@tbrooke: so that method works if you have a backend, with firebase there is only my client app, no state to move around between the client and server

flyboarder20:07:17

@alandipert: let’s get hoplon in there 😉

tbrooke21:07:58

@flyboarder: I’ve looked at Firebase briefly but never thought about using it with Hoplon I’ll check it out

flyboarder21:07:32

I am slowly shifting everything away from backends for my apps, i really like the idea of a client only app and an api only app

flyboarder21:07:34

this fit’s in nicely with things like azure functions, where I write a single task as a function and commit to the repo, no app to build or anything

flyboarder21:07:31

then there is a list of actions in the db with their respective url’s the db fetches a list that the user has access to based on roles, my spa then executes an action from the list using a unique name, this way I can change the urls without affecting my code, I can also mix and match api’s by changing a db value

flyboarder21:07:13

I like to think of it like zappier but between my client app and backend api's

dm321:07:37

@flyboarder: where does the domain logic live? In azure functions?

tbrooke21:07:19

@flyboarder: Firebase has some static hosting can you host your Hoplon app there?

flyboarder21:07:15

@tbrooke: yes! Highly recommended! Works well with Firebase v3 API and new console. @dm3: depends on what you are looking to accomplish

flyboarder21:07:22

@dm3: for example all of the rules for interacting with the db are on the FB DB hosting side which uploads a rules json file, when I need to interact with other API’s then its azure functions

dm321:07:05

I mean the place where business-logic related decisions are made

dm321:07:59

not the infrastructure/integration

dm321:07:34

so it's mostly azure?

dm321:07:47

will read about firebase a bit 🙂

flyboarder21:07:19

well that depends on how your application works

flyboarder21:07:28

@dm3 for the db specifically?

dm321:07:48

I guess for general understanding on what it provides

dm321:07:47

the serverless architecture seems interesting, although it's also interesting how the implementation/ops complexity scales with the complexity of the domain

flyboarder21:07:50

i think it depends on your type of application, if you only need to store data in the db then it’s great, if you need to run server logic then youll need something like azure functions

flyboarder21:07:24

things like a todo app can house all it’s logic in javelin cells and the root cell is just the fb db

dm321:07:33

yep, thinking about the hosted db + aws lambda/azure functions

dm321:07:16

how the testing/deployment/logic flow goes when you have lots of those functions

flyboarder21:07:46

the idea is that each function is it’s own bit of logic, they are not directly related, imho

flyboarder21:07:36

i mean real life they will all be related to your app but i like to think of your web app as a global view of all the server bits of code I can launch, then its just buttons and webhooks

dm321:07:38

hehe, I usually start from the domain model and the UI comes out of actions that make sense given the business functions

dm321:07:58

but then I haven't wrote any CRUD in a long while

dm321:07:53

I guess I'd need to try writing something non-trivial and see how it goes

flyboarder21:07:33

ill have an app to show for the past few months of development soon

flyboarder22:07:36

@jumblerg: so route-tpl was fairly easy

flyboarder22:07:38

this is like the regex-tpl except it also supports a vector of korks