I’ve been learning ReflexFRP by building a single page app, a graphical user interface (GUI) for calculating image aspect ratios. I wanted the ability to preview images with new image aspect ratios, and maybe someday also preview cropped images). The preview element changes shape depending on the numbers specified in the form inputs, as you can see in the preview below.
My approach for building this app has been from a designer perspective as you would be able to see from my commit log that I included the CSS and semantic DOM elements before figuring out how the dynamic behavior works
Here is a preview of the UI in action.
I mentioned having a designer perspective because the Reflex-FRP and Reflex-Dom has a different way of thinking. When I asked for help with coding my general format follows: (1) explain objective with GUI specs, (2) list docs referenced, (3) brief description of what I understand and attempted to do, and (4) hypothesis on where my knowledge gap lies and/or the confusion on how to put pieces together. Well, the answer in this particular case was that UX Design has a different way of modeling the GUI than an FRP system. I write this but don’t know how to explain the particulars in technical terms, hopefully the example below illustrates my point.
I wanted to know how to make the placeholder image change its shape depending on numbers inputted. I figured out it was a dynamic, some sort of elDynAttr
because the x
and y
values are not constants, but didn’t know how to pass in the number values. It’s important to understand the types because coding in Haskell when you’re doing it right is like connecting pipes. It turns out elDynAttr'
is a better choice as it returns a dynamic element type.
From the Reflex-Dom quickref:
Working with Reflex-Dom
FRP views the breakdown of interaction flows as a system of events and behaviors. In Reflex-Dom you have these and also the dynamic type. I mistakenly thought user events like the ones you might see in Javascript (keypress, mouseclick, etc), but it’s not just that, there’s also somewhat of a Rube Goldberg Machine setup to think about.
For example, with my ux design hat on I saw 4 text boxes for the user, each with a label on the side and then a placeholder image area. A user will most likely start from the left pair to find out what the image ratio is and then using that ratio figure out the correct measurements for the resulting image. As I’m learning Reflex-Dom, I realize it’s easier to code the left and right sides separately for now, it’s more complicated to connect the interactions of a grouping of GUI elements. As you add more GUI elements, you have more data to think about passing values around. Working with user-defined values requires a lot more code!
When writing Reflex-Dom apps, bear in mind the order of elements specified as it will affect the order in which the events and behaviors flow through the FRP mini-verse.
How the code works
In the most recent commit to my Getting Started With Haskell repo #f1336ec, the code specifies the dynamic behavior of the image preview with the elDynAttr’ function. The preview placeholder responds to the events created when the textboxes are updated.
In the 2nd line you’ll see rec
which is some sort of virtual container telling the compiler to let the values be used in any order in the subset. That’s how you get around the rule in blockquotes above about knowing the order in which elements are created.
In case you’re wondering about imgAttrs
and calcAspectRatio
, I defined those functions and you can see what they’re about below:
Here’s a use case showing how the calculated image aspect ratio based on the calcAspectRatio
function above. We don’t know if the user will input expected real number values, which is why I’ve the case statements for when there are legitimate values and when it’s null. The imgAttrs
function takes two numbers and returns the image place holder.