How best to separate view from logic in conditional splices?

21 views
Skip to first unread message

Pedro Vasconcelos

unread,
Jun 12, 2015, 7:18:50 AM6/12/15
to snap_fr...@googlegroups.com

Hi, I'm maintaing a little web app for students programming assignments and I have a questio about how to best keep the view and logic separate when writing splices that depend on conditions. 

Here is a concrete example; I have a data type for problem submission that includes wether it has been already submitted and accepted:

data ProblemSummary = ProblemSummary {
      summaryProb :: Problem,  -- the problem
      summaryAttempts :: Int,  -- total number of submissions
      summaryAccepted :: Int   -- number of accepted submitions
    }

Now I want a splice for an <accepted/> tag that be replaced by an empty node list if the number of accepted submissions is 0 and a suitable icon if it is positive. I can write it like this:

acceptSplice :: ProblemSummary -> AppSplices
acceptSplice ProblemSummary{..} = do
         "accepted" ## (if summaryAccepted>0 then 
                        return [X.Element "img" [("src", "/path/to/icon.png")] []] 
                        else return [])

The problem is that the specific path to the icon, any styles etc. are now part of the Haskell code rather than the template/CSS/whatever.  How can avoid this?

Thanks!

MightyByte

unread,
Jun 12, 2015, 10:53:11 AM6/12/15
to snap_fr...@googlegroups.com
Usually the way I do this kind of thing is write an "ifHasAccepted"
splice that calls runChildren if the condition is true and returns an
empty node list if the condition is false.
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "Snap Framework" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to snap_framewor...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Pedro Vasconcelos

unread,
Jun 12, 2015, 11:01:02 AM6/12/15
to snap_fr...@googlegroups.com


sexta-feira, 12 de Junho de 2015 às 15:53:11 UTC+1, mightybyte escreveu:
Usually the way I do this kind of thing is write an "ifHasAccepted"
splice that calls runChildren if the condition is true and returns an
empty node list if the condition is false.


OK, thanks for the reply. I tried this idea and it does solve the problem; the only disadvantage is that sometimes I also need inverse conditions, i.e. both "ifAccepted" and "ifNotAccepted" splices. It also puts some control flow into the templates, in the sense that we end up with templates that look like this

<ifAccepted>
   .... presentation for the accepted case
</ifAccepted>
<ifNotAccepted>
   ... presentation for the unaccepted case
</ifNotAccepted>

I was just wondering if there was some other alternative.

MightyByte

unread,
Jun 12, 2015, 11:13:06 AM6/12/15
to snap_fr...@googlegroups.com
I forgot to mention in the previous message that we have a helper
function for this kind of condition splice here:

http://hackage.haskell.org/package/heist-0.14.1/docs/Heist-Splices.html

It's not the prettiest, but I have not thought of anything better. I
think that in this case we're constrained by the structure of XML. If
you think about it, what you have there is structurally the same as if
you had the more concise

if accepted then
.... presentation for the accepted case
else
... presentation for the unaccepted case

The only difference is that you have to have a unique name to surround
the else case.

Hmmm, after giving it a little more thought, I suppose it might be
possible to write something like ifElseCSplice that searches through
the child nodes and splits them into two lists around an <else/> tag
and does the appropriate thing.

<acceptedConditional>
.... presentation for the accepted case
<else/>
... presentation for the unaccepted case
</acceptedConditional>

If you wrote a function like that, I'd probably be willing to include
it in the Heist.Splices module.

Pedro Vasconcelos

unread,
Jun 13, 2015, 11:27:48 AM6/13/15
to snap_fr...@googlegroups.com


sexta-feira, 12 de Junho de 2015 às 16:13:06 UTC+1, mightybyte escreveu:
I forgot to mention in the previous message that we have a helper
function for this kind of condition splice here:

http://hackage.haskell.org/package/heist-0.14.1/docs/Heist-Splices.html


Yes, I had seen this.
 
It's not the prettiest, but I have not thought of anything better.  I
think that in this case we're constrained by the structure of XML.  If
you think about it, what you have there is structurally the same as if
you had the more concise

if accepted then
   .... presentation for the accepted case
else
   ... presentation for the unaccepted case

The only difference is that you have to have a unique name to surround
the else case.

Hmmm, after giving it a little more thought, I suppose it might be
possible to write something like ifElseCSplice that searches through
the child nodes and splits them into two lists around an <else/> tag
and does the appropriate thing. 
If you wrote a function like that, I'd probably be willing to include
it in the Heist.Splices module.


Thanks -- this is a good idea; I put together a simple version for interpreted splices:

-- if/then/else conditional splice
-- split children around the <else/> element; removes the <else/> element
ifElseISplice :: Monad m => Bool -> I.Splice m
ifElseISplice cond = getParamNode >>= (rewrite . X.childNodes)
  where rewrite nodes = 
          let (ns, ns') = break (\n -> X.tagName n==Just "else") nodes
          in I.runNodeList $ if cond then ns else (drop 1 ns') 
  

Regards, Pedro
 

MightyByte

unread,
Jun 15, 2015, 11:56:50 PM6/15/15
to snap_fr...@googlegroups.com
Thanks, I just added it.
Reply all
Reply to author
Forward
0 new messages